Merge "Make inprocesstests run with root." into tm-dev
diff --git a/Android.bp b/Android.bp
index 8afea34..5523986 100644
--- a/Android.bp
+++ b/Android.bp
@@ -132,7 +132,6 @@
":installd_aidl",
":libaudioclient_aidl",
":libbinder_aidl",
- ":libbluetooth-binder-aidl",
":libcamera_client_aidl",
":libcamera_client_framework_aidl",
":libupdate_engine_aidl",
@@ -273,7 +272,6 @@
defaults: ["framework-aidl-export-defaults"],
srcs: [
":framework-non-updatable-sources",
- ":framework-bluetooth-sources", // TODO(b/214988855) : Remove once framework-bluetooth jar is ready
"core/java/**/*.logtags",
":apex-info-list",
],
@@ -287,6 +285,7 @@
"frameworks/native/libs/permission/aidl",
// TODO: remove when moved to the below package
"frameworks/base/packages/ConnectivityT/framework-t/aidl-export",
+ "packages/modules/Bluetooth/system/binder",
"packages/modules/Connectivity/framework/aidl-export",
"packages/modules/Media/apex/aidl/stable",
"hardware/interfaces/graphics/common/aidl",
@@ -357,7 +356,6 @@
visibility: [
"//frameworks/base",
// TODO(b/147128803) remove the below lines
- "//frameworks/base/apex/appsearch/framework",
"//frameworks/base/apex/blobstore/framework",
"//frameworks/base/apex/jobscheduler/framework",
"//frameworks/base/packages/Tethering/tests/unit",
@@ -545,8 +543,9 @@
"frameworks/native/libs/permission/aidl",
// TODO: remove when moved to the below package
"frameworks/base/packages/ConnectivityT/framework-t/aidl-export",
- "packages/modules/Media/apex/aidl/stable",
+ "packages/modules/Bluetooth/system/binder",
"packages/modules/Connectivity/framework/aidl-export",
+ "packages/modules/Media/apex/aidl/stable",
"hardware/interfaces/graphics/common/aidl",
],
},
@@ -584,6 +583,7 @@
name: "module-classpath-stubs-defaults",
aidl: {
include_dirs: [
+ "packages/modules/Bluetooth/system/binder",
"packages/modules/Connectivity/framework/aidl-export",
"packages/modules/Media/apex/aidl/stable",
],
@@ -591,7 +591,7 @@
libs: [
"art.module.public.api",
"sdk_module-lib_current_framework-tethering",
- "sdk_module-lib_current_framework-connectivity-tiramisu",
+ "sdk_module-lib_current_framework-connectivity-t",
"sdk_public_current_framework-bluetooth",
// There are a few classes from modules used by the core that
// need to be resolved by metalava. We use a prebuilt stub of the
diff --git a/ApiDocs.bp b/ApiDocs.bp
index ba31161..5b7c125 100644
--- a/ApiDocs.bp
+++ b/ApiDocs.bp
@@ -79,6 +79,7 @@
":conscrypt.module.public.api{.public.stubs.source}",
":i18n.module.public.api{.public.stubs.source}",
+ ":framework-adservices-sources",
":framework-appsearch-sources",
":framework-auxiliary-sources",
":framework-connectivity-sources",
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 726ab2a..94f4374 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -258,7 +258,7 @@
srcs: [":module-lib-api-stubs-docs-non-updatable"],
libs: [
"sdk_module-lib_current_framework-tethering",
- "sdk_module-lib_current_framework-connectivity-tiramisu",
+ "sdk_module-lib_current_framework-connectivity-t",
"sdk_public_current_framework-bluetooth",
// NOTE: The below can be removed once the prebuilt stub contains bluetooth.
"sdk_system_current_android",
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 2b0a833..ee0f9e8 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.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 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 @@
+ "bgJobCountInMaxPeriod=" + bgJobCountInMaxPeriod + ", "
+ "sessionCountInWindow=" + sessionCountInWindow + ", "
+ "inQuotaTime=" + inQuotaTimeElapsed + ", "
- + "inQuotaTimeLow=" + inQuotaTimeLowElapsed + ", "
- + "inQuotaTimeMin=" + inQuotaTimeMinElapsed + ", "
+ "rateLimitJobCountExpirationTime=" + jobRateLimitExpirationTimeElapsed + ", "
+ "rateLimitJobCountWindow=" + jobCountInRateLimitingWindow + ", "
+ "rateLimitSessionCountExpirationTime="
@@ -385,24 +360,6 @@
*/
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 @@
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 @@
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 @@
@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 @@
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 @@
* 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
/**
* 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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
invalidateAllExecutionStatsLocked(mPkg.userId, mPkg.packageName);
}
scheduleCutoff();
- } else if (mRegularJobTimer && priorityLowered) {
- rescheduleCutoff();
}
}
}
@@ -2196,19 +2043,6 @@
&& !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 @@
}
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 @@
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 @@
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 @@
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 @@
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 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 @@
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 @@
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 @@
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 @@
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 @@
.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 @@
}
@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/tare/PowerSaveModeModifier.java b/apex/jobscheduler/service/java/com/android/server/tare/PowerSaveModeModifier.java
index 764a3a8..4aaa9f4 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/PowerSaveModeModifier.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/PowerSaveModeModifier.java
@@ -17,27 +17,48 @@
package com.android.server.tare;
import android.annotation.NonNull;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.os.PowerManager;
+import android.os.SystemClock;
import android.util.IndentingPrintWriter;
+import android.util.Log;
+import android.util.Slog;
/** Modifier that makes things more expensive in adaptive and full battery saver are active. */
class PowerSaveModeModifier extends Modifier {
+ private static final String TAG = "TARE-" + PowerSaveModeModifier.class.getSimpleName();
+ private static final boolean DEBUG = InternalResourceService.DEBUG
+ || Log.isLoggable(TAG, Log.DEBUG);
+
private final InternalResourceService mIrs;
- private final PowerManager mPowerManager;
+ private final PowerSaveModeTracker mPowerSaveModeTracker;
PowerSaveModeModifier(@NonNull InternalResourceService irs) {
super();
mIrs = irs;
- mPowerManager = irs.getContext().getSystemService(PowerManager.class);
+ mPowerSaveModeTracker = new PowerSaveModeTracker();
+ }
+
+ @Override
+ public void setup() {
+ mPowerSaveModeTracker.startTracking(mIrs.getContext());
+ }
+
+ @Override
+ public void tearDown() {
+ mPowerSaveModeTracker.stopTracking(mIrs.getContext());
}
@Override
long getModifiedCostToProduce(long ctp) {
- if (mPowerManager.isPowerSaveMode()) {
+ if (mPowerSaveModeTracker.mPowerSaveModeEnabled) {
return (long) (1.5 * ctp);
}
// TODO: get adaptive power save mode
- if (mPowerManager.isPowerSaveMode()) {
+ if (mPowerSaveModeTracker.mPowerSaveModeEnabled) {
return (long) (1.25 * ctp);
}
return ctp;
@@ -46,6 +67,45 @@
@Override
void dump(IndentingPrintWriter pw) {
pw.print("power save=");
- pw.println(mPowerManager.isPowerSaveMode());
+ pw.println(mPowerSaveModeTracker.mPowerSaveModeEnabled);
+ }
+
+ // TODO: migrate to relying on PowerSaveState and ServiceType.TARE
+ private final class PowerSaveModeTracker extends BroadcastReceiver {
+ private final PowerManager mPowerManager;
+ private volatile boolean mPowerSaveModeEnabled;
+
+ private PowerSaveModeTracker() {
+ mPowerManager = mIrs.getContext().getSystemService(PowerManager.class);
+ }
+
+ public void startTracking(@NonNull Context context) {
+ final IntentFilter filter = new IntentFilter();
+ filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
+ context.registerReceiver(this, filter);
+
+ // Initialise tracker state.
+ mPowerSaveModeEnabled = mPowerManager.isPowerSaveMode();
+ }
+
+ public void stopTracking(@NonNull Context context) {
+ context.unregisterReceiver(this);
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)) {
+ final boolean enabled = mPowerManager.isPowerSaveMode();
+ if (DEBUG) {
+ Slog.d(TAG, "Power save mode changed to " + enabled
+ + ", fired @ " + SystemClock.elapsedRealtime());
+ }
+ if (mPowerSaveModeEnabled != enabled) {
+ mPowerSaveModeEnabled = enabled;
+ mIrs.onDeviceStateChanged();
+ }
+ }
+ }
}
}
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 b843dca..54c3db4 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -25,6 +25,7 @@
import static android.app.usage.UsageStatsManager.REASON_MAIN_USAGE;
import static android.app.usage.UsageStatsManager.REASON_SUB_DEFAULT_APP_UPDATE;
import static android.app.usage.UsageStatsManager.REASON_SUB_FORCED_SYSTEM_FLAG_BUGGY;
+import static android.app.usage.UsageStatsManager.REASON_SUB_FORCED_USER_FLAG_INTERACTION;
import static android.app.usage.UsageStatsManager.REASON_SUB_MASK;
import static android.app.usage.UsageStatsManager.REASON_SUB_PREDICTED_RESTORED;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_ACTIVE_TIMEOUT;
@@ -103,6 +104,7 @@
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;
@@ -259,6 +261,13 @@
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
@@ -721,7 +730,14 @@
@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
@@ -1581,7 +1597,11 @@
// Only user force can bypass the delay restriction. If the user forced the
// app into the RESTRICTED bucket, then a toast confirming the action
// shouldn't be surprising.
- if (Build.IS_DEBUGGABLE) {
+ // Exclude REASON_SUB_FORCED_USER_FLAG_INTERACTION since the RESTRICTED bucket
+ // isn't directly visible in that flow.
+ if (Build.IS_DEBUGGABLE
+ && (reason & REASON_SUB_MASK)
+ != REASON_SUB_FORCED_USER_FLAG_INTERACTION) {
Toast.makeText(mContext,
// Since AppStandbyController sits low in the lock hierarchy,
// make sure not to call out with the lock held.
@@ -2369,10 +2389,32 @@
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/api/Android.bp b/api/Android.bp
index 66c7823..9e377a0 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -93,7 +93,6 @@
// Silence reflection warnings. See b/168689341
metalava_cmd += " -J--add-opens=java.base/java.util=ALL-UNNAMED "
metalava_cmd += " --quiet --no-banner --format=v2 "
-metalava_cmd += " --hide ChangedThrows "
genrule {
name: "current-api-xml",
@@ -110,10 +109,11 @@
"android.net.ipsec.ike",
"art.module.public.api",
"conscrypt.module.public.api",
+ "framework-adservices",
"framework-appsearch",
"framework-bluetooth",
"framework-connectivity",
- "framework-connectivity-tiramisu",
+ "framework-connectivity-t",
"framework-graphics",
"framework-media",
"framework-mediaprovider",
@@ -187,8 +187,10 @@
cmd: metalava_cmd +
"--check-compatibility:api:released $(location :android.api.module-lib.latest) " +
// Note: having "public" be the base of module-lib is not perfect -- it should
- // ideally be a merged public+system), but this will help when migrating from
- // MODULE_LIBS -> public.
+ // ideally be a merged public+system (which metalava is not currently able to generate).
+ // This "base" will help when migrating from MODULE_LIBS -> public, but not when
+ // migrating from MODULE_LIBS -> system (where it needs to instead be listed as
+ // an incompatibility).
"--check-compatibility:base $(location :frameworks-base-api-current.txt) " +
"--baseline:compatibility:released $(location :android-incompatibilities.api.module-lib.latest) " +
"--update-baseline:compatibility:released $(genDir)/updated-baseline.txt " +
diff --git a/api/api.go b/api/api.go
index 5e5f60e..94bccaa 100644
--- a/api/api.go
+++ b/api/api.go
@@ -203,8 +203,6 @@
func createMergedFrameworkImpl(ctx android.LoadHookContext, modules []string) {
// This module is for the "framework-all" module, which should not include the core libraries.
modules = removeAll(modules, core_libraries_modules)
- // TODO(b/214988855): remove the line below when framework-bluetooth has an impl jar.
- modules = remove(modules, "framework-bluetooth")
props := libraryProps{}
props.Name = proptools.StringPtr("all-framework-module-impl")
props.Static_libs = transformArray(modules, "", ".impl")
diff --git a/boot/Android.bp b/boot/Android.bp
index aa22532..90c3b9c 100644
--- a/boot/Android.bp
+++ b/boot/Android.bp
@@ -48,6 +48,10 @@
// bootclasspath.
fragments: [
{
+ apex: "com.android.adservices",
+ module: "com.android.adservices-bootclasspath-fragment",
+ },
+ {
apex: "com.android.appsearch",
module: "com.android.appsearch-bootclasspath-fragment",
},
@@ -60,6 +64,10 @@
module: "com.android.auxiliary-bootclasspath-fragment",
},
{
+ apex: "com.android.bluetooth",
+ module: "com.android.bluetooth-bootclasspath-fragment",
+ },
+ {
apex: "com.android.conscrypt",
module: "com.android.conscrypt-bootclasspath-fragment",
},
diff --git a/boot/hiddenapi/hiddenapi-max-target-o.txt b/boot/hiddenapi/hiddenapi-max-target-o.txt
index e346ebf..d3b5be9 100644
--- a/boot/hiddenapi/hiddenapi-max-target-o.txt
+++ b/boot/hiddenapi/hiddenapi-max-target-o.txt
@@ -9733,2812 +9733,6 @@
Landroid/appwidget/PendingHostUpdate;->views:Landroid/widget/RemoteViews;
Landroid/appwidget/PendingHostUpdate;->widgetInfo:Landroid/appwidget/AppWidgetProviderInfo;
Landroid/appwidget/PendingHostUpdate;->writeNullParcelable(Landroid/os/Parcelable;Landroid/os/Parcel;I)V
-Landroid/bluetooth/BluetoothA2dp;-><init>(Landroid/content/Context;Landroid/bluetooth/BluetoothProfile$ServiceListener;)V
-Landroid/bluetooth/BluetoothA2dp;->ACTION_AVRCP_CONNECTION_STATE_CHANGED:Ljava/lang/String;
-Landroid/bluetooth/BluetoothA2dp;->DBG:Z
-Landroid/bluetooth/BluetoothA2dp;->doBind()Z
-Landroid/bluetooth/BluetoothA2dp;->enableDisableOptionalCodecs(Landroid/bluetooth/BluetoothDevice;Z)V
-Landroid/bluetooth/BluetoothA2dp;->isAvrcpAbsoluteVolumeSupported()Z
-Landroid/bluetooth/BluetoothA2dp;->isEnabled()Z
-Landroid/bluetooth/BluetoothA2dp;->isValidDevice(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/BluetoothA2dp;->log(Ljava/lang/String;)V
-Landroid/bluetooth/BluetoothA2dp;->mAdapter:Landroid/bluetooth/BluetoothAdapter;
-Landroid/bluetooth/BluetoothA2dp;->mBluetoothStateChangeCallback:Landroid/bluetooth/IBluetoothStateChangeCallback;
-Landroid/bluetooth/BluetoothA2dp;->mConnection:Landroid/content/ServiceConnection;
-Landroid/bluetooth/BluetoothA2dp;->mContext:Landroid/content/Context;
-Landroid/bluetooth/BluetoothA2dp;->mService:Landroid/bluetooth/IBluetoothA2dp;
-Landroid/bluetooth/BluetoothA2dp;->mServiceListener:Landroid/bluetooth/BluetoothProfile$ServiceListener;
-Landroid/bluetooth/BluetoothA2dp;->mServiceLock:Ljava/util/concurrent/locks/ReentrantReadWriteLock;
-Landroid/bluetooth/BluetoothA2dp;->setAvrcpAbsoluteVolume(I)V
-Landroid/bluetooth/BluetoothA2dp;->setPriority(Landroid/bluetooth/BluetoothDevice;I)Z
-Landroid/bluetooth/BluetoothA2dp;->shouldSendVolumeKeys(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/BluetoothA2dp;->TAG:Ljava/lang/String;
-Landroid/bluetooth/BluetoothA2dp;->VDBG:Z
-Landroid/bluetooth/BluetoothA2dpSink;-><init>(Landroid/content/Context;Landroid/bluetooth/BluetoothProfile$ServiceListener;)V
-Landroid/bluetooth/BluetoothA2dpSink;->ACTION_AUDIO_CONFIG_CHANGED:Ljava/lang/String;
-Landroid/bluetooth/BluetoothA2dpSink;->ACTION_CONNECTION_STATE_CHANGED:Ljava/lang/String;
-Landroid/bluetooth/BluetoothA2dpSink;->ACTION_PLAYING_STATE_CHANGED:Ljava/lang/String;
-Landroid/bluetooth/BluetoothA2dpSink;->close()V
-Landroid/bluetooth/BluetoothA2dpSink;->connect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/BluetoothA2dpSink;->DBG:Z
-Landroid/bluetooth/BluetoothA2dpSink;->doBind()Z
-Landroid/bluetooth/BluetoothA2dpSink;->EXTRA_AUDIO_CONFIG:Ljava/lang/String;
-Landroid/bluetooth/BluetoothA2dpSink;->getAudioConfig(Landroid/bluetooth/BluetoothDevice;)Landroid/bluetooth/BluetoothAudioConfig;
-Landroid/bluetooth/BluetoothA2dpSink;->getPriority(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/BluetoothA2dpSink;->isA2dpPlaying(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/BluetoothA2dpSink;->isEnabled()Z
-Landroid/bluetooth/BluetoothA2dpSink;->isValidDevice(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/BluetoothA2dpSink;->log(Ljava/lang/String;)V
-Landroid/bluetooth/BluetoothA2dpSink;->mAdapter:Landroid/bluetooth/BluetoothAdapter;
-Landroid/bluetooth/BluetoothA2dpSink;->mBluetoothStateChangeCallback:Landroid/bluetooth/IBluetoothStateChangeCallback;
-Landroid/bluetooth/BluetoothA2dpSink;->mConnection:Landroid/content/ServiceConnection;
-Landroid/bluetooth/BluetoothA2dpSink;->mContext:Landroid/content/Context;
-Landroid/bluetooth/BluetoothA2dpSink;->mService:Landroid/bluetooth/IBluetoothA2dpSink;
-Landroid/bluetooth/BluetoothA2dpSink;->mServiceListener:Landroid/bluetooth/BluetoothProfile$ServiceListener;
-Landroid/bluetooth/BluetoothA2dpSink;->setPriority(Landroid/bluetooth/BluetoothDevice;I)Z
-Landroid/bluetooth/BluetoothA2dpSink;->stateToString(I)Ljava/lang/String;
-Landroid/bluetooth/BluetoothA2dpSink;->STATE_NOT_PLAYING:I
-Landroid/bluetooth/BluetoothA2dpSink;->STATE_PLAYING:I
-Landroid/bluetooth/BluetoothA2dpSink;->TAG:Ljava/lang/String;
-Landroid/bluetooth/BluetoothA2dpSink;->VDBG:Z
-Landroid/bluetooth/BluetoothActivityEnergyInfo;-><init>(JIJJJJ)V
-Landroid/bluetooth/BluetoothActivityEnergyInfo;-><init>(Landroid/os/Parcel;)V
-Landroid/bluetooth/BluetoothActivityEnergyInfo;->BT_STACK_STATE_INVALID:I
-Landroid/bluetooth/BluetoothActivityEnergyInfo;->BT_STACK_STATE_STATE_ACTIVE:I
-Landroid/bluetooth/BluetoothActivityEnergyInfo;->BT_STACK_STATE_STATE_IDLE:I
-Landroid/bluetooth/BluetoothActivityEnergyInfo;->BT_STACK_STATE_STATE_SCANNING:I
-Landroid/bluetooth/BluetoothActivityEnergyInfo;->CREATOR:Landroid/os/Parcelable$Creator;
-Landroid/bluetooth/BluetoothActivityEnergyInfo;->getBluetoothStackState()I
-Landroid/bluetooth/BluetoothActivityEnergyInfo;->getControllerEnergyUsed()J
-Landroid/bluetooth/BluetoothActivityEnergyInfo;->getControllerIdleTimeMillis()J
-Landroid/bluetooth/BluetoothActivityEnergyInfo;->getControllerRxTimeMillis()J
-Landroid/bluetooth/BluetoothActivityEnergyInfo;->getControllerTxTimeMillis()J
-Landroid/bluetooth/BluetoothActivityEnergyInfo;->getTimeStamp()J
-Landroid/bluetooth/BluetoothActivityEnergyInfo;->getUidTraffic()[Landroid/bluetooth/UidTraffic;
-Landroid/bluetooth/BluetoothActivityEnergyInfo;->isValid()Z
-Landroid/bluetooth/BluetoothActivityEnergyInfo;->mBluetoothStackState:I
-Landroid/bluetooth/BluetoothActivityEnergyInfo;->mControllerEnergyUsed:J
-Landroid/bluetooth/BluetoothActivityEnergyInfo;->mControllerIdleTimeMs:J
-Landroid/bluetooth/BluetoothActivityEnergyInfo;->mControllerRxTimeMs:J
-Landroid/bluetooth/BluetoothActivityEnergyInfo;->mControllerTxTimeMs:J
-Landroid/bluetooth/BluetoothActivityEnergyInfo;->mTimestamp:J
-Landroid/bluetooth/BluetoothActivityEnergyInfo;->mUidTraffic:[Landroid/bluetooth/UidTraffic;
-Landroid/bluetooth/BluetoothActivityEnergyInfo;->setUidTraffic([Landroid/bluetooth/UidTraffic;)V
-Landroid/bluetooth/BluetoothAdapter$BluetoothStateChangeCallback;->onBluetoothStateChange(Z)V
-Landroid/bluetooth/BluetoothAdapter$StateChangeCallbackWrapper;->mCallback:Landroid/bluetooth/BluetoothAdapter$BluetoothStateChangeCallback;
-Landroid/bluetooth/BluetoothAdapter$StateChangeCallbackWrapper;->onBluetoothStateChange(Z)V
-Landroid/bluetooth/BluetoothAdapter;-><init>(Landroid/bluetooth/IBluetoothManager;)V
-Landroid/bluetooth/BluetoothAdapter;->ACTION_BLE_ACL_CONNECTED:Ljava/lang/String;
-Landroid/bluetooth/BluetoothAdapter;->ACTION_BLE_ACL_DISCONNECTED:Ljava/lang/String;
-Landroid/bluetooth/BluetoothAdapter;->ACTION_BLUETOOTH_ADDRESS_CHANGED:Ljava/lang/String;
-Landroid/bluetooth/BluetoothAdapter;->ACTION_REQUEST_DISABLE:Ljava/lang/String;
-Landroid/bluetooth/BluetoothAdapter;->ADDRESS_LENGTH:I
-Landroid/bluetooth/BluetoothAdapter;->BLUETOOTH_MANAGER_SERVICE:Ljava/lang/String;
-Landroid/bluetooth/BluetoothAdapter;->changeApplicationBluetoothState(ZLandroid/bluetooth/BluetoothAdapter$BluetoothStateChangeCallback;)Z
-Landroid/bluetooth/BluetoothAdapter;->createNewRfcommSocketAndRecord(Ljava/lang/String;Ljava/util/UUID;ZZ)Landroid/bluetooth/BluetoothServerSocket;
-Landroid/bluetooth/BluetoothAdapter;->DBG:Z
-Landroid/bluetooth/BluetoothAdapter;->DEFAULT_MAC_ADDRESS:Ljava/lang/String;
-Landroid/bluetooth/BluetoothAdapter;->EXTRA_BLUETOOTH_ADDRESS:Ljava/lang/String;
-Landroid/bluetooth/BluetoothAdapter;->getBluetoothClass()Landroid/bluetooth/BluetoothClass;
-Landroid/bluetooth/BluetoothAdapter;->getControllerActivityEnergyInfo(I)Landroid/bluetooth/BluetoothActivityEnergyInfo;
-Landroid/bluetooth/BluetoothAdapter;->getDiscoveryEndMillis()J
-Landroid/bluetooth/BluetoothAdapter;->getLeAccess()Z
-Landroid/bluetooth/BluetoothAdapter;->getMaxConnectedAudioDevices()I
-Landroid/bluetooth/BluetoothAdapter;->getPeriodicAdvertisingManager()Landroid/bluetooth/le/PeriodicAdvertisingManager;
-Landroid/bluetooth/BluetoothAdapter;->getSupportedProfiles()Ljava/util/List;
-Landroid/bluetooth/BluetoothAdapter;->isHardwareTrackingFiltersAvailable()Z
-Landroid/bluetooth/BluetoothAdapter;->LE_PSM_CHARACTERISTIC_UUID:Ljava/util/UUID;
-Landroid/bluetooth/BluetoothAdapter;->listenUsingEncryptedRfcommOn(I)Landroid/bluetooth/BluetoothServerSocket;
-Landroid/bluetooth/BluetoothAdapter;->listenUsingInsecureL2capCoc(I)Landroid/bluetooth/BluetoothServerSocket;
-Landroid/bluetooth/BluetoothAdapter;->listenUsingInsecureL2capOn(I)Landroid/bluetooth/BluetoothServerSocket;
-Landroid/bluetooth/BluetoothAdapter;->listenUsingInsecureRfcommOn(I)Landroid/bluetooth/BluetoothServerSocket;
-Landroid/bluetooth/BluetoothAdapter;->listenUsingL2capCoc(I)Landroid/bluetooth/BluetoothServerSocket;
-Landroid/bluetooth/BluetoothAdapter;->listenUsingL2capOn(I)Landroid/bluetooth/BluetoothServerSocket;
-Landroid/bluetooth/BluetoothAdapter;->listenUsingL2capOn(IZZ)Landroid/bluetooth/BluetoothServerSocket;
-Landroid/bluetooth/BluetoothAdapter;->listenUsingRfcommOn(I)Landroid/bluetooth/BluetoothServerSocket;
-Landroid/bluetooth/BluetoothAdapter;->listenUsingScoOn()Landroid/bluetooth/BluetoothServerSocket;
-Landroid/bluetooth/BluetoothAdapter;->mLeScanClients:Ljava/util/Map;
-Landroid/bluetooth/BluetoothAdapter;->mLock:Ljava/lang/Object;
-Landroid/bluetooth/BluetoothAdapter;->mManagerCallback:Landroid/bluetooth/IBluetoothManagerCallback;
-Landroid/bluetooth/BluetoothAdapter;->mManagerService:Landroid/bluetooth/IBluetoothManager;
-Landroid/bluetooth/BluetoothAdapter;->mProxyServiceStateCallbacks:Ljava/util/ArrayList;
-Landroid/bluetooth/BluetoothAdapter;->mServiceLock:Ljava/util/concurrent/locks/ReentrantReadWriteLock;
-Landroid/bluetooth/BluetoothAdapter;->mToken:Landroid/os/IBinder;
-Landroid/bluetooth/BluetoothAdapter;->nameForState(I)Ljava/lang/String;
-Landroid/bluetooth/BluetoothAdapter;->readOutOfBandData()Landroid/util/Pair;
-Landroid/bluetooth/BluetoothAdapter;->removeServiceStateCallback(Landroid/bluetooth/IBluetoothManagerCallback;)V
-Landroid/bluetooth/BluetoothAdapter;->requestControllerActivityEnergyInfo(Landroid/os/ResultReceiver;)V
-Landroid/bluetooth/BluetoothAdapter;->sAdapter:Landroid/bluetooth/BluetoothAdapter;
-Landroid/bluetooth/BluetoothAdapter;->sBluetoothLeAdvertiser:Landroid/bluetooth/le/BluetoothLeAdvertiser;
-Landroid/bluetooth/BluetoothAdapter;->sBluetoothLeScanner:Landroid/bluetooth/le/BluetoothLeScanner;
-Landroid/bluetooth/BluetoothAdapter;->setBluetoothClass(Landroid/bluetooth/BluetoothClass;)Z
-Landroid/bluetooth/BluetoothAdapter;->SOCKET_CHANNEL_AUTO_STATIC_NO_SDP:I
-Landroid/bluetooth/BluetoothAdapter;->sPeriodicAdvertisingManager:Landroid/bluetooth/le/PeriodicAdvertisingManager;
-Landroid/bluetooth/BluetoothAdapter;->STATE_BLE_ON:I
-Landroid/bluetooth/BluetoothAdapter;->STATE_BLE_TURNING_OFF:I
-Landroid/bluetooth/BluetoothAdapter;->STATE_BLE_TURNING_ON:I
-Landroid/bluetooth/BluetoothAdapter;->TAG:Ljava/lang/String;
-Landroid/bluetooth/BluetoothAdapter;->toDeviceSet([Landroid/bluetooth/BluetoothDevice;)Ljava/util/Set;
-Landroid/bluetooth/BluetoothAdapter;->VDBG:Z
-Landroid/bluetooth/BluetoothAssignedNumbers;-><init>()V
-Landroid/bluetooth/BluetoothAudioConfig;-><init>(III)V
-Landroid/bluetooth/BluetoothAudioConfig;->CREATOR:Landroid/os/Parcelable$Creator;
-Landroid/bluetooth/BluetoothAudioConfig;->getAudioFormat()I
-Landroid/bluetooth/BluetoothAudioConfig;->getChannelConfig()I
-Landroid/bluetooth/BluetoothAudioConfig;->getSampleRate()I
-Landroid/bluetooth/BluetoothAudioConfig;->mAudioFormat:I
-Landroid/bluetooth/BluetoothAudioConfig;->mChannelConfig:I
-Landroid/bluetooth/BluetoothAudioConfig;->mSampleRate:I
-Landroid/bluetooth/BluetoothAvrcp;-><init>()V
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_0:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_1:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_2:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_3:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_4:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_5:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_6:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_7:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_8:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_9:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_ANGLE:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_BACKWARD:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_CHAN_DOWN:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_CHAN_UP:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_CLEAR:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_CONT_MENU:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_DISP_INFO:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_DOT:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_DOWN:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_EJECT:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_ENTER:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_EXIT:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_F1:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_F2:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_F3:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_F4:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_F5:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_FAST_FOR:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_FAV_MENU:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_FORWARD:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_HELP:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_INPUT_SEL:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_LEFT:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_LEFT_DOWN:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_LEFT_UP:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_MUTE:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_PAGE_DOWN:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_PAGE_UP:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_PAUSE:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_PLAY:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_POWER:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_PREV_CHAN:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_RECORD:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_REWIND:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_RIGHT:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_RIGHT_DOWN:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_RIGHT_UP:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_ROOT_MENU:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_SELECT:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_SETUP_MENU:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_SOUND_SEL:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_STOP:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_SUBPICT:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_UP:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_VENDOR:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_VOL_DOWN:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_ID_VOL_UP:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_KEYPRESSED_RELEASE:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_STATE_PRESS:I
-Landroid/bluetooth/BluetoothAvrcp;->PASSTHROUGH_STATE_RELEASE:I
-Landroid/bluetooth/BluetoothAvrcpController;-><init>(Landroid/content/Context;Landroid/bluetooth/BluetoothProfile$ServiceListener;)V
-Landroid/bluetooth/BluetoothAvrcpController;->ACTION_CONNECTION_STATE_CHANGED:Ljava/lang/String;
-Landroid/bluetooth/BluetoothAvrcpController;->ACTION_PLAYER_SETTING:Ljava/lang/String;
-Landroid/bluetooth/BluetoothAvrcpController;->close()V
-Landroid/bluetooth/BluetoothAvrcpController;->DBG:Z
-Landroid/bluetooth/BluetoothAvrcpController;->doBind()Z
-Landroid/bluetooth/BluetoothAvrcpController;->EXTRA_PLAYER_SETTING:Ljava/lang/String;
-Landroid/bluetooth/BluetoothAvrcpController;->getPlayerSettings(Landroid/bluetooth/BluetoothDevice;)Landroid/bluetooth/BluetoothAvrcpPlayerSettings;
-Landroid/bluetooth/BluetoothAvrcpController;->isEnabled()Z
-Landroid/bluetooth/BluetoothAvrcpController;->isValidDevice(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/BluetoothAvrcpController;->log(Ljava/lang/String;)V
-Landroid/bluetooth/BluetoothAvrcpController;->mAdapter:Landroid/bluetooth/BluetoothAdapter;
-Landroid/bluetooth/BluetoothAvrcpController;->mBluetoothStateChangeCallback:Landroid/bluetooth/IBluetoothStateChangeCallback;
-Landroid/bluetooth/BluetoothAvrcpController;->mConnection:Landroid/content/ServiceConnection;
-Landroid/bluetooth/BluetoothAvrcpController;->mContext:Landroid/content/Context;
-Landroid/bluetooth/BluetoothAvrcpController;->mService:Landroid/bluetooth/IBluetoothAvrcpController;
-Landroid/bluetooth/BluetoothAvrcpController;->mServiceListener:Landroid/bluetooth/BluetoothProfile$ServiceListener;
-Landroid/bluetooth/BluetoothAvrcpController;->sendGroupNavigationCmd(Landroid/bluetooth/BluetoothDevice;II)V
-Landroid/bluetooth/BluetoothAvrcpController;->setPlayerApplicationSetting(Landroid/bluetooth/BluetoothAvrcpPlayerSettings;)Z
-Landroid/bluetooth/BluetoothAvrcpController;->TAG:Ljava/lang/String;
-Landroid/bluetooth/BluetoothAvrcpController;->VDBG:Z
-Landroid/bluetooth/BluetoothAvrcpPlayerSettings;-><init>(I)V
-Landroid/bluetooth/BluetoothAvrcpPlayerSettings;-><init>(Landroid/os/Parcel;)V
-Landroid/bluetooth/BluetoothAvrcpPlayerSettings;->addSettingValue(II)V
-Landroid/bluetooth/BluetoothAvrcpPlayerSettings;->CREATOR:Landroid/os/Parcelable$Creator;
-Landroid/bluetooth/BluetoothAvrcpPlayerSettings;->getSettings()I
-Landroid/bluetooth/BluetoothAvrcpPlayerSettings;->getSettingValue(I)I
-Landroid/bluetooth/BluetoothAvrcpPlayerSettings;->mSettings:I
-Landroid/bluetooth/BluetoothAvrcpPlayerSettings;->mSettingsValue:Ljava/util/Map;
-Landroid/bluetooth/BluetoothAvrcpPlayerSettings;->SETTING_EQUALIZER:I
-Landroid/bluetooth/BluetoothAvrcpPlayerSettings;->SETTING_REPEAT:I
-Landroid/bluetooth/BluetoothAvrcpPlayerSettings;->SETTING_SCAN:I
-Landroid/bluetooth/BluetoothAvrcpPlayerSettings;->SETTING_SHUFFLE:I
-Landroid/bluetooth/BluetoothAvrcpPlayerSettings;->STATE_ALL_TRACK:I
-Landroid/bluetooth/BluetoothAvrcpPlayerSettings;->STATE_GROUP:I
-Landroid/bluetooth/BluetoothAvrcpPlayerSettings;->STATE_INVALID:I
-Landroid/bluetooth/BluetoothAvrcpPlayerSettings;->STATE_OFF:I
-Landroid/bluetooth/BluetoothAvrcpPlayerSettings;->STATE_ON:I
-Landroid/bluetooth/BluetoothAvrcpPlayerSettings;->STATE_SINGLE_TRACK:I
-Landroid/bluetooth/BluetoothAvrcpPlayerSettings;->TAG:Ljava/lang/String;
-Landroid/bluetooth/BluetoothClass$Device$Major;->BITMASK:I
-Landroid/bluetooth/BluetoothClass$Device;->BITMASK:I
-Landroid/bluetooth/BluetoothClass$Device;->PERIPHERAL_KEYBOARD:I
-Landroid/bluetooth/BluetoothClass$Device;->PERIPHERAL_KEYBOARD_POINTING:I
-Landroid/bluetooth/BluetoothClass$Device;->PERIPHERAL_NON_KEYBOARD_NON_POINTING:I
-Landroid/bluetooth/BluetoothClass$Device;->PERIPHERAL_POINTING:I
-Landroid/bluetooth/BluetoothClass$Service;->BITMASK:I
-Landroid/bluetooth/BluetoothClass;->ERROR:I
-Landroid/bluetooth/BluetoothClass;->getClassOfDevice()I
-Landroid/bluetooth/BluetoothClass;->getClassOfDeviceBytes()[B
-Landroid/bluetooth/BluetoothClass;->mClass:I
-Landroid/bluetooth/BluetoothClass;->PROFILE_A2DP_SINK:I
-Landroid/bluetooth/BluetoothClass;->PROFILE_HID:I
-Landroid/bluetooth/BluetoothClass;->PROFILE_NAP:I
-Landroid/bluetooth/BluetoothClass;->PROFILE_OPP:I
-Landroid/bluetooth/BluetoothClass;->PROFILE_PANU:I
-Landroid/bluetooth/BluetoothCodecConfig;->appendCapabilityToString(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
-Landroid/bluetooth/BluetoothCodecConfig;->CREATOR:Landroid/os/Parcelable$Creator;
-Landroid/bluetooth/BluetoothCodecConfig;->getCodecName()Ljava/lang/String;
-Landroid/bluetooth/BluetoothCodecConfig;->isMandatoryCodec()Z
-Landroid/bluetooth/BluetoothCodecConfig;->isValid()Z
-Landroid/bluetooth/BluetoothCodecConfig;->mBitsPerSample:I
-Landroid/bluetooth/BluetoothCodecConfig;->mChannelMode:I
-Landroid/bluetooth/BluetoothCodecConfig;->mCodecPriority:I
-Landroid/bluetooth/BluetoothCodecConfig;->mCodecSpecific1:J
-Landroid/bluetooth/BluetoothCodecConfig;->mCodecSpecific2:J
-Landroid/bluetooth/BluetoothCodecConfig;->mCodecSpecific3:J
-Landroid/bluetooth/BluetoothCodecConfig;->mCodecSpecific4:J
-Landroid/bluetooth/BluetoothCodecConfig;->mCodecType:I
-Landroid/bluetooth/BluetoothCodecConfig;->mSampleRate:I
-Landroid/bluetooth/BluetoothCodecConfig;->sameAudioFeedingParameters(Landroid/bluetooth/BluetoothCodecConfig;)Z
-Landroid/bluetooth/BluetoothCodecStatus;-><init>(Landroid/bluetooth/BluetoothCodecConfig;[Landroid/bluetooth/BluetoothCodecConfig;[Landroid/bluetooth/BluetoothCodecConfig;)V
-Landroid/bluetooth/BluetoothCodecStatus;->CREATOR:Landroid/os/Parcelable$Creator;
-Landroid/bluetooth/BluetoothCodecStatus;->mCodecConfig:Landroid/bluetooth/BluetoothCodecConfig;
-Landroid/bluetooth/BluetoothCodecStatus;->mCodecsLocalCapabilities:[Landroid/bluetooth/BluetoothCodecConfig;
-Landroid/bluetooth/BluetoothCodecStatus;->mCodecsSelectableCapabilities:[Landroid/bluetooth/BluetoothCodecConfig;
-Landroid/bluetooth/BluetoothCodecStatus;->sameCapabilities([Landroid/bluetooth/BluetoothCodecConfig;[Landroid/bluetooth/BluetoothCodecConfig;)Z
-Landroid/bluetooth/BluetoothDevice;->ACTION_BATTERY_LEVEL_CHANGED:Ljava/lang/String;
-Landroid/bluetooth/BluetoothDevice;->ACTION_CONNECTION_ACCESS_CANCEL:Ljava/lang/String;
-Landroid/bluetooth/BluetoothDevice;->ACTION_CONNECTION_ACCESS_REPLY:Ljava/lang/String;
-Landroid/bluetooth/BluetoothDevice;->ACTION_CONNECTION_ACCESS_REQUEST:Ljava/lang/String;
-Landroid/bluetooth/BluetoothDevice;->ACTION_MAS_INSTANCE:Ljava/lang/String;
-Landroid/bluetooth/BluetoothDevice;->ACTION_NAME_FAILED:Ljava/lang/String;
-Landroid/bluetooth/BluetoothDevice;->BATTERY_LEVEL_UNKNOWN:I
-Landroid/bluetooth/BluetoothDevice;->BOND_SUCCESS:I
-Landroid/bluetooth/BluetoothDevice;->CONNECTION_ACCESS_NO:I
-Landroid/bluetooth/BluetoothDevice;->CONNECTION_ACCESS_YES:I
-Landroid/bluetooth/BluetoothDevice;->CONNECTION_STATE_CONNECTED:I
-Landroid/bluetooth/BluetoothDevice;->CONNECTION_STATE_DISCONNECTED:I
-Landroid/bluetooth/BluetoothDevice;->CONNECTION_STATE_ENCRYPTED_BREDR:I
-Landroid/bluetooth/BluetoothDevice;->CONNECTION_STATE_ENCRYPTED_LE:I
-Landroid/bluetooth/BluetoothDevice;->createBondOutOfBand(ILandroid/bluetooth/OobData;)Z
-Landroid/bluetooth/BluetoothDevice;->createInsecureL2capCocSocket(II)Landroid/bluetooth/BluetoothSocket;
-Landroid/bluetooth/BluetoothDevice;->createInsecureL2capSocket(I)Landroid/bluetooth/BluetoothSocket;
-Landroid/bluetooth/BluetoothDevice;->createL2capCocSocket(II)Landroid/bluetooth/BluetoothSocket;
-Landroid/bluetooth/BluetoothDevice;->createL2capSocket(I)Landroid/bluetooth/BluetoothSocket;
-Landroid/bluetooth/BluetoothDevice;->DBG:Z
-Landroid/bluetooth/BluetoothDevice;->EXTRA_ACCESS_REQUEST_TYPE:Ljava/lang/String;
-Landroid/bluetooth/BluetoothDevice;->EXTRA_ALWAYS_ALLOWED:Ljava/lang/String;
-Landroid/bluetooth/BluetoothDevice;->EXTRA_BATTERY_LEVEL:Ljava/lang/String;
-Landroid/bluetooth/BluetoothDevice;->EXTRA_CLASS_NAME:Ljava/lang/String;
-Landroid/bluetooth/BluetoothDevice;->EXTRA_CONNECTION_ACCESS_RESULT:Ljava/lang/String;
-Landroid/bluetooth/BluetoothDevice;->EXTRA_MAS_INSTANCE:Ljava/lang/String;
-Landroid/bluetooth/BluetoothDevice;->EXTRA_PACKAGE_NAME:Ljava/lang/String;
-Landroid/bluetooth/BluetoothDevice;->EXTRA_SDP_RECORD:Ljava/lang/String;
-Landroid/bluetooth/BluetoothDevice;->getSimAccessPermission()I
-Landroid/bluetooth/BluetoothDevice;->isBluetoothEnabled()Z
-Landroid/bluetooth/BluetoothDevice;->mAddress:Ljava/lang/String;
-Landroid/bluetooth/BluetoothDevice;->PAIRING_VARIANT_CONSENT:I
-Landroid/bluetooth/BluetoothDevice;->PAIRING_VARIANT_DISPLAY_PASSKEY:I
-Landroid/bluetooth/BluetoothDevice;->PAIRING_VARIANT_DISPLAY_PIN:I
-Landroid/bluetooth/BluetoothDevice;->PAIRING_VARIANT_OOB_CONSENT:I
-Landroid/bluetooth/BluetoothDevice;->PAIRING_VARIANT_PASSKEY:I
-Landroid/bluetooth/BluetoothDevice;->PAIRING_VARIANT_PIN_16_DIGITS:I
-Landroid/bluetooth/BluetoothDevice;->REQUEST_TYPE_MESSAGE_ACCESS:I
-Landroid/bluetooth/BluetoothDevice;->REQUEST_TYPE_PHONEBOOK_ACCESS:I
-Landroid/bluetooth/BluetoothDevice;->REQUEST_TYPE_PROFILE_CONNECTION:I
-Landroid/bluetooth/BluetoothDevice;->REQUEST_TYPE_SIM_ACCESS:I
-Landroid/bluetooth/BluetoothDevice;->sdpSearch(Landroid/os/ParcelUuid;)Z
-Landroid/bluetooth/BluetoothDevice;->setDeviceOutOfBandData([B[B)Z
-Landroid/bluetooth/BluetoothDevice;->setRemoteOutOfBandData()Z
-Landroid/bluetooth/BluetoothDevice;->sService:Landroid/bluetooth/IBluetooth;
-Landroid/bluetooth/BluetoothDevice;->sStateChangeCallback:Landroid/bluetooth/IBluetoothManagerCallback;
-Landroid/bluetooth/BluetoothDevice;->TAG:Ljava/lang/String;
-Landroid/bluetooth/BluetoothDevice;->UNBOND_REASON_AUTH_CANCELED:I
-Landroid/bluetooth/BluetoothDevice;->UNBOND_REASON_REMOVED:I
-Landroid/bluetooth/BluetoothDevicePicker;->ACTION_DEVICE_SELECTED:Ljava/lang/String;
-Landroid/bluetooth/BluetoothDevicePicker;->ACTION_LAUNCH:Ljava/lang/String;
-Landroid/bluetooth/BluetoothDevicePicker;->EXTRA_FILTER_TYPE:Ljava/lang/String;
-Landroid/bluetooth/BluetoothDevicePicker;->EXTRA_LAUNCH_CLASS:Ljava/lang/String;
-Landroid/bluetooth/BluetoothDevicePicker;->EXTRA_LAUNCH_PACKAGE:Ljava/lang/String;
-Landroid/bluetooth/BluetoothDevicePicker;->EXTRA_NEED_AUTH:Ljava/lang/String;
-Landroid/bluetooth/BluetoothDevicePicker;->FILTER_TYPE_ALL:I
-Landroid/bluetooth/BluetoothDevicePicker;->FILTER_TYPE_AUDIO:I
-Landroid/bluetooth/BluetoothDevicePicker;->FILTER_TYPE_NAP:I
-Landroid/bluetooth/BluetoothDevicePicker;->FILTER_TYPE_PANU:I
-Landroid/bluetooth/BluetoothDevicePicker;->FILTER_TYPE_TRANSFER:I
-Landroid/bluetooth/BluetoothGatt;-><init>(Landroid/bluetooth/IBluetoothGatt;Landroid/bluetooth/BluetoothDevice;IZI)V
-Landroid/bluetooth/BluetoothGatt;->AUTHENTICATION_MITM:I
-Landroid/bluetooth/BluetoothGatt;->AUTHENTICATION_NONE:I
-Landroid/bluetooth/BluetoothGatt;->AUTHENTICATION_NO_MITM:I
-Landroid/bluetooth/BluetoothGatt;->AUTH_RETRY_STATE_IDLE:I
-Landroid/bluetooth/BluetoothGatt;->AUTH_RETRY_STATE_MITM:I
-Landroid/bluetooth/BluetoothGatt;->AUTH_RETRY_STATE_NO_MITM:I
-Landroid/bluetooth/BluetoothGatt;->CONN_STATE_CLOSED:I
-Landroid/bluetooth/BluetoothGatt;->CONN_STATE_CONNECTED:I
-Landroid/bluetooth/BluetoothGatt;->CONN_STATE_CONNECTING:I
-Landroid/bluetooth/BluetoothGatt;->CONN_STATE_DISCONNECTING:I
-Landroid/bluetooth/BluetoothGatt;->CONN_STATE_IDLE:I
-Landroid/bluetooth/BluetoothGatt;->DBG:Z
-Landroid/bluetooth/BluetoothGatt;->discoverServiceByUuid(Ljava/util/UUID;)Z
-Landroid/bluetooth/BluetoothGatt;->getCharacteristicById(Landroid/bluetooth/BluetoothDevice;I)Landroid/bluetooth/BluetoothGattCharacteristic;
-Landroid/bluetooth/BluetoothGatt;->getDescriptorById(Landroid/bluetooth/BluetoothDevice;I)Landroid/bluetooth/BluetoothGattDescriptor;
-Landroid/bluetooth/BluetoothGatt;->getService(Landroid/bluetooth/BluetoothDevice;Ljava/util/UUID;I)Landroid/bluetooth/BluetoothGattService;
-Landroid/bluetooth/BluetoothGatt;->mBluetoothGattCallback:Landroid/bluetooth/IBluetoothGattCallback;
-Landroid/bluetooth/BluetoothGatt;->mConnState:I
-Landroid/bluetooth/BluetoothGatt;->mDevice:Landroid/bluetooth/BluetoothDevice;
-Landroid/bluetooth/BluetoothGatt;->mHandler:Landroid/os/Handler;
-Landroid/bluetooth/BluetoothGatt;->mOpportunistic:Z
-Landroid/bluetooth/BluetoothGatt;->mPhy:I
-Landroid/bluetooth/BluetoothGatt;->mServices:Ljava/util/List;
-Landroid/bluetooth/BluetoothGatt;->mStateLock:Ljava/lang/Object;
-Landroid/bluetooth/BluetoothGatt;->readUsingCharacteristicUuid(Ljava/util/UUID;II)Z
-Landroid/bluetooth/BluetoothGatt;->registerApp(Landroid/bluetooth/BluetoothGattCallback;Landroid/os/Handler;)Z
-Landroid/bluetooth/BluetoothGatt;->requestLeConnectionUpdate(IIIIII)Z
-Landroid/bluetooth/BluetoothGatt;->runOrQueueCallback(Ljava/lang/Runnable;)V
-Landroid/bluetooth/BluetoothGatt;->TAG:Ljava/lang/String;
-Landroid/bluetooth/BluetoothGatt;->VDBG:Z
-Landroid/bluetooth/BluetoothGattCallback;->onConnectionUpdated(Landroid/bluetooth/BluetoothGatt;IIII)V
-Landroid/bluetooth/BluetoothGattCharacteristic;-><init>(Landroid/bluetooth/BluetoothGattService;Ljava/util/UUID;III)V
-Landroid/bluetooth/BluetoothGattCharacteristic;-><init>(Landroid/os/Parcel;)V
-Landroid/bluetooth/BluetoothGattCharacteristic;-><init>(Ljava/util/UUID;III)V
-Landroid/bluetooth/BluetoothGattCharacteristic;->bytesToFloat(BB)F
-Landroid/bluetooth/BluetoothGattCharacteristic;->bytesToFloat(BBBB)F
-Landroid/bluetooth/BluetoothGattCharacteristic;->getDescriptor(Ljava/util/UUID;I)Landroid/bluetooth/BluetoothGattDescriptor;
-Landroid/bluetooth/BluetoothGattCharacteristic;->getKeySize()I
-Landroid/bluetooth/BluetoothGattCharacteristic;->getTypeLen(I)I
-Landroid/bluetooth/BluetoothGattCharacteristic;->initCharacteristic(Landroid/bluetooth/BluetoothGattService;Ljava/util/UUID;III)V
-Landroid/bluetooth/BluetoothGattCharacteristic;->intToSignedBits(II)I
-Landroid/bluetooth/BluetoothGattCharacteristic;->mKeySize:I
-Landroid/bluetooth/BluetoothGattCharacteristic;->mPermissions:I
-Landroid/bluetooth/BluetoothGattCharacteristic;->mProperties:I
-Landroid/bluetooth/BluetoothGattCharacteristic;->mUuid:Ljava/util/UUID;
-Landroid/bluetooth/BluetoothGattCharacteristic;->mValue:[B
-Landroid/bluetooth/BluetoothGattCharacteristic;->mWriteType:I
-Landroid/bluetooth/BluetoothGattCharacteristic;->setInstanceId(I)V
-Landroid/bluetooth/BluetoothGattCharacteristic;->unsignedBytesToInt(BB)I
-Landroid/bluetooth/BluetoothGattCharacteristic;->unsignedBytesToInt(BBBB)I
-Landroid/bluetooth/BluetoothGattCharacteristic;->unsignedByteToInt(B)I
-Landroid/bluetooth/BluetoothGattCharacteristic;->unsignedToSigned(II)I
-Landroid/bluetooth/BluetoothGattDescriptor;-><init>(Landroid/bluetooth/BluetoothGattCharacteristic;Ljava/util/UUID;II)V
-Landroid/bluetooth/BluetoothGattDescriptor;-><init>(Landroid/os/Parcel;)V
-Landroid/bluetooth/BluetoothGattDescriptor;-><init>(Ljava/util/UUID;II)V
-Landroid/bluetooth/BluetoothGattDescriptor;->getInstanceId()I
-Landroid/bluetooth/BluetoothGattDescriptor;->initDescriptor(Landroid/bluetooth/BluetoothGattCharacteristic;Ljava/util/UUID;II)V
-Landroid/bluetooth/BluetoothGattDescriptor;->mPermissions:I
-Landroid/bluetooth/BluetoothGattDescriptor;->mUuid:Ljava/util/UUID;
-Landroid/bluetooth/BluetoothGattDescriptor;->mValue:[B
-Landroid/bluetooth/BluetoothGattDescriptor;->setInstanceId(I)V
-Landroid/bluetooth/BluetoothGattIncludedService;-><init>(Landroid/os/Parcel;)V
-Landroid/bluetooth/BluetoothGattIncludedService;-><init>(Ljava/util/UUID;II)V
-Landroid/bluetooth/BluetoothGattIncludedService;->CREATOR:Landroid/os/Parcelable$Creator;
-Landroid/bluetooth/BluetoothGattIncludedService;->getInstanceId()I
-Landroid/bluetooth/BluetoothGattIncludedService;->getType()I
-Landroid/bluetooth/BluetoothGattIncludedService;->getUuid()Ljava/util/UUID;
-Landroid/bluetooth/BluetoothGattIncludedService;->mInstanceId:I
-Landroid/bluetooth/BluetoothGattIncludedService;->mServiceType:I
-Landroid/bluetooth/BluetoothGattIncludedService;->mUuid:Ljava/util/UUID;
-Landroid/bluetooth/BluetoothGattServer;-><init>(Landroid/bluetooth/IBluetoothGatt;I)V
-Landroid/bluetooth/BluetoothGattServer;->CALLBACK_REG_TIMEOUT:I
-Landroid/bluetooth/BluetoothGattServer;->DBG:Z
-Landroid/bluetooth/BluetoothGattServer;->getCharacteristicByHandle(I)Landroid/bluetooth/BluetoothGattCharacteristic;
-Landroid/bluetooth/BluetoothGattServer;->getDescriptorByHandle(I)Landroid/bluetooth/BluetoothGattDescriptor;
-Landroid/bluetooth/BluetoothGattServer;->getService(Ljava/util/UUID;II)Landroid/bluetooth/BluetoothGattService;
-Landroid/bluetooth/BluetoothGattServer;->mAdapter:Landroid/bluetooth/BluetoothAdapter;
-Landroid/bluetooth/BluetoothGattServer;->mBluetoothGattServerCallback:Landroid/bluetooth/IBluetoothGattServerCallback;
-Landroid/bluetooth/BluetoothGattServer;->mCallback:Landroid/bluetooth/BluetoothGattServerCallback;
-Landroid/bluetooth/BluetoothGattServer;->mPendingService:Landroid/bluetooth/BluetoothGattService;
-Landroid/bluetooth/BluetoothGattServer;->mServerIf:I
-Landroid/bluetooth/BluetoothGattServer;->mServerIfLock:Ljava/lang/Object;
-Landroid/bluetooth/BluetoothGattServer;->mService:Landroid/bluetooth/IBluetoothGatt;
-Landroid/bluetooth/BluetoothGattServer;->mServices:Ljava/util/List;
-Landroid/bluetooth/BluetoothGattServer;->mTransport:I
-Landroid/bluetooth/BluetoothGattServer;->registerCallback(Landroid/bluetooth/BluetoothGattServerCallback;)Z
-Landroid/bluetooth/BluetoothGattServer;->TAG:Ljava/lang/String;
-Landroid/bluetooth/BluetoothGattServer;->unregisterCallback()V
-Landroid/bluetooth/BluetoothGattServer;->VDBG:Z
-Landroid/bluetooth/BluetoothGattServerCallback;->onConnectionUpdated(Landroid/bluetooth/BluetoothDevice;IIII)V
-Landroid/bluetooth/BluetoothGattService;-><init>(Landroid/bluetooth/BluetoothDevice;Ljava/util/UUID;II)V
-Landroid/bluetooth/BluetoothGattService;-><init>(Landroid/os/Parcel;)V
-Landroid/bluetooth/BluetoothGattService;-><init>(Ljava/util/UUID;II)V
-Landroid/bluetooth/BluetoothGattService;->addIncludedService(Landroid/bluetooth/BluetoothGattService;)V
-Landroid/bluetooth/BluetoothGattService;->getCharacteristic(Ljava/util/UUID;I)Landroid/bluetooth/BluetoothGattCharacteristic;
-Landroid/bluetooth/BluetoothGattService;->getDevice()Landroid/bluetooth/BluetoothDevice;
-Landroid/bluetooth/BluetoothGattService;->getHandles()I
-Landroid/bluetooth/BluetoothGattService;->isAdvertisePreferred()Z
-Landroid/bluetooth/BluetoothGattService;->mAdvertisePreferred:Z
-Landroid/bluetooth/BluetoothGattService;->mHandles:I
-Landroid/bluetooth/BluetoothGattService;->mInstanceId:I
-Landroid/bluetooth/BluetoothGattService;->mServiceType:I
-Landroid/bluetooth/BluetoothGattService;->mUuid:Ljava/util/UUID;
-Landroid/bluetooth/BluetoothGattService;->setDevice(Landroid/bluetooth/BluetoothDevice;)V
-Landroid/bluetooth/BluetoothGattService;->setHandles(I)V
-Landroid/bluetooth/BluetoothHeadset;-><init>(Landroid/content/Context;Landroid/bluetooth/BluetoothProfile$ServiceListener;)V
-Landroid/bluetooth/BluetoothHeadset;->ACTION_HF_INDICATORS_VALUE_CHANGED:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHeadset;->clccResponse(IIIIZLjava/lang/String;I)V
-Landroid/bluetooth/BluetoothHeadset;->DBG:Z
-Landroid/bluetooth/BluetoothHeadset;->doBind()Z
-Landroid/bluetooth/BluetoothHeadset;->doUnbind()V
-Landroid/bluetooth/BluetoothHeadset;->EXTRA_HF_INDICATORS_IND_ID:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHeadset;->EXTRA_HF_INDICATORS_IND_VALUE:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHeadset;->getAudioRouteAllowed()Z
-Landroid/bluetooth/BluetoothHeadset;->isAudioOn()Z
-Landroid/bluetooth/BluetoothHeadset;->isBluetoothVoiceDialingEnabled(Landroid/content/Context;)Z
-Landroid/bluetooth/BluetoothHeadset;->isDisabled()Z
-Landroid/bluetooth/BluetoothHeadset;->isInbandRingingEnabled()Z
-Landroid/bluetooth/BluetoothHeadset;->isInbandRingingSupported(Landroid/content/Context;)Z
-Landroid/bluetooth/BluetoothHeadset;->isValidDevice(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/BluetoothHeadset;->log(Ljava/lang/String;)V
-Landroid/bluetooth/BluetoothHeadset;->mAdapter:Landroid/bluetooth/BluetoothAdapter;
-Landroid/bluetooth/BluetoothHeadset;->mBluetoothStateChangeCallback:Landroid/bluetooth/IBluetoothStateChangeCallback;
-Landroid/bluetooth/BluetoothHeadset;->mConnection:Landroid/bluetooth/IBluetoothProfileServiceConnection;
-Landroid/bluetooth/BluetoothHeadset;->mContext:Landroid/content/Context;
-Landroid/bluetooth/BluetoothHeadset;->MESSAGE_HEADSET_SERVICE_CONNECTED:I
-Landroid/bluetooth/BluetoothHeadset;->MESSAGE_HEADSET_SERVICE_DISCONNECTED:I
-Landroid/bluetooth/BluetoothHeadset;->mHandler:Landroid/os/Handler;
-Landroid/bluetooth/BluetoothHeadset;->mService:Landroid/bluetooth/IBluetoothHeadset;
-Landroid/bluetooth/BluetoothHeadset;->mServiceListener:Landroid/bluetooth/BluetoothProfile$ServiceListener;
-Landroid/bluetooth/BluetoothHeadset;->setAudioRouteAllowed(Z)V
-Landroid/bluetooth/BluetoothHeadset;->setForceScoAudio(Z)V
-Landroid/bluetooth/BluetoothHeadset;->TAG:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHeadset;->VDBG:Z
-Landroid/bluetooth/BluetoothHeadset;->VENDOR_SPECIFIC_HEADSET_EVENT_IPHONEACCEV:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHeadset;->VENDOR_SPECIFIC_HEADSET_EVENT_IPHONEACCEV_BATTERY_LEVEL:I
-Landroid/bluetooth/BluetoothHeadset;->VENDOR_SPECIFIC_HEADSET_EVENT_XAPL:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHeadset;->VENDOR_SPECIFIC_HEADSET_EVENT_XEVENT:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHeadset;->VENDOR_SPECIFIC_HEADSET_EVENT_XEVENT_BATTERY_LEVEL:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHeadsetClient;-><init>(Landroid/content/Context;Landroid/bluetooth/BluetoothProfile$ServiceListener;)V
-Landroid/bluetooth/BluetoothHeadsetClient;->ACTION_AG_EVENT:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHeadsetClient;->ACTION_AUDIO_STATE_CHANGED:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHeadsetClient;->ACTION_CALL_CHANGED:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHeadsetClient;->ACTION_CONNECTION_STATE_CHANGED:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHeadsetClient;->ACTION_LAST_VTAG:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHeadsetClient;->ACTION_RESULT:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHeadsetClient;->ACTION_RESULT_ERROR:I
-Landroid/bluetooth/BluetoothHeadsetClient;->ACTION_RESULT_ERROR_BLACKLISTED:I
-Landroid/bluetooth/BluetoothHeadsetClient;->ACTION_RESULT_ERROR_BUSY:I
-Landroid/bluetooth/BluetoothHeadsetClient;->ACTION_RESULT_ERROR_CME:I
-Landroid/bluetooth/BluetoothHeadsetClient;->ACTION_RESULT_ERROR_DELAYED:I
-Landroid/bluetooth/BluetoothHeadsetClient;->ACTION_RESULT_ERROR_NO_ANSWER:I
-Landroid/bluetooth/BluetoothHeadsetClient;->ACTION_RESULT_ERROR_NO_CARRIER:I
-Landroid/bluetooth/BluetoothHeadsetClient;->ACTION_RESULT_OK:I
-Landroid/bluetooth/BluetoothHeadsetClient;->CALL_ACCEPT_HOLD:I
-Landroid/bluetooth/BluetoothHeadsetClient;->CALL_ACCEPT_NONE:I
-Landroid/bluetooth/BluetoothHeadsetClient;->CALL_ACCEPT_TERMINATE:I
-Landroid/bluetooth/BluetoothHeadsetClient;->close()V
-Landroid/bluetooth/BluetoothHeadsetClient;->CME_CORPORATE_PERSONALIZATION_PIN_REQUIRED:I
-Landroid/bluetooth/BluetoothHeadsetClient;->CME_CORPORATE_PERSONALIZATION_PUK_REQUIRED:I
-Landroid/bluetooth/BluetoothHeadsetClient;->CME_DIAL_STRING_TOO_LONG:I
-Landroid/bluetooth/BluetoothHeadsetClient;->CME_EAP_NOT_SUPPORTED:I
-Landroid/bluetooth/BluetoothHeadsetClient;->CME_EMERGENCY_SERVICE_ONLY:I
-Landroid/bluetooth/BluetoothHeadsetClient;->CME_HIDDEN_KEY_REQUIRED:I
-Landroid/bluetooth/BluetoothHeadsetClient;->CME_INCORRECT_PARAMETERS:I
-Landroid/bluetooth/BluetoothHeadsetClient;->CME_INCORRECT_PASSWORD:I
-Landroid/bluetooth/BluetoothHeadsetClient;->CME_INVALID_CHARACTER_IN_DIAL_STRING:I
-Landroid/bluetooth/BluetoothHeadsetClient;->CME_INVALID_CHARACTER_IN_TEXT_STRING:I
-Landroid/bluetooth/BluetoothHeadsetClient;->CME_INVALID_INDEX:I
-Landroid/bluetooth/BluetoothHeadsetClient;->CME_MEMORY_FAILURE:I
-Landroid/bluetooth/BluetoothHeadsetClient;->CME_MEMORY_FULL:I
-Landroid/bluetooth/BluetoothHeadsetClient;->CME_NETWORK_PERSONALIZATION_PIN_REQUIRED:I
-Landroid/bluetooth/BluetoothHeadsetClient;->CME_NETWORK_PERSONALIZATION_PUK_REQUIRED:I
-Landroid/bluetooth/BluetoothHeadsetClient;->CME_NETWORK_SUBSET_PERSONALIZATION_PIN_REQUIRED:I
-Landroid/bluetooth/BluetoothHeadsetClient;->CME_NETWORK_SUBSET_PERSONALIZATION_PUK_REQUIRED:I
-Landroid/bluetooth/BluetoothHeadsetClient;->CME_NETWORK_TIMEOUT:I
-Landroid/bluetooth/BluetoothHeadsetClient;->CME_NOT_FOUND:I
-Landroid/bluetooth/BluetoothHeadsetClient;->CME_NOT_SUPPORTED_FOR_VOIP:I
-Landroid/bluetooth/BluetoothHeadsetClient;->CME_NO_CONNECTION_TO_PHONE:I
-Landroid/bluetooth/BluetoothHeadsetClient;->CME_NO_NETWORK_SERVICE:I
-Landroid/bluetooth/BluetoothHeadsetClient;->CME_NO_SIMULTANOUS_VOIP_CS_CALLS:I
-Landroid/bluetooth/BluetoothHeadsetClient;->CME_OPERATION_NOT_ALLOWED:I
-Landroid/bluetooth/BluetoothHeadsetClient;->CME_OPERATION_NOT_SUPPORTED:I
-Landroid/bluetooth/BluetoothHeadsetClient;->CME_PHFSIM_PIN_REQUIRED:I
-Landroid/bluetooth/BluetoothHeadsetClient;->CME_PHFSIM_PUK_REQUIRED:I
-Landroid/bluetooth/BluetoothHeadsetClient;->CME_PHONE_FAILURE:I
-Landroid/bluetooth/BluetoothHeadsetClient;->CME_PHSIM_PIN_REQUIRED:I
-Landroid/bluetooth/BluetoothHeadsetClient;->CME_SERVICE_PROVIDER_PERSONALIZATION_PIN_REQUIRED:I
-Landroid/bluetooth/BluetoothHeadsetClient;->CME_SERVICE_PROVIDER_PERSONALIZATION_PUK_REQUIRED:I
-Landroid/bluetooth/BluetoothHeadsetClient;->CME_SIM_BUSY:I
-Landroid/bluetooth/BluetoothHeadsetClient;->CME_SIM_FAILURE:I
-Landroid/bluetooth/BluetoothHeadsetClient;->CME_SIM_NOT_INSERTED:I
-Landroid/bluetooth/BluetoothHeadsetClient;->CME_SIM_PIN2_REQUIRED:I
-Landroid/bluetooth/BluetoothHeadsetClient;->CME_SIM_PIN_REQUIRED:I
-Landroid/bluetooth/BluetoothHeadsetClient;->CME_SIM_PUK2_REQUIRED:I
-Landroid/bluetooth/BluetoothHeadsetClient;->CME_SIM_PUK_REQUIRED:I
-Landroid/bluetooth/BluetoothHeadsetClient;->CME_SIM_WRONG:I
-Landroid/bluetooth/BluetoothHeadsetClient;->CME_SIP_RESPONSE_CODE:I
-Landroid/bluetooth/BluetoothHeadsetClient;->CME_TEXT_STRING_TOO_LONG:I
-Landroid/bluetooth/BluetoothHeadsetClient;->connectAudio(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/BluetoothHeadsetClient;->DBG:Z
-Landroid/bluetooth/BluetoothHeadsetClient;->dial(Landroid/bluetooth/BluetoothDevice;Ljava/lang/String;)Landroid/bluetooth/BluetoothHeadsetClientCall;
-Landroid/bluetooth/BluetoothHeadsetClient;->disconnectAudio(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/BluetoothHeadsetClient;->doBind()Z
-Landroid/bluetooth/BluetoothHeadsetClient;->enterPrivateMode(Landroid/bluetooth/BluetoothDevice;I)Z
-Landroid/bluetooth/BluetoothHeadsetClient;->explicitCallTransfer(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/BluetoothHeadsetClient;->EXTRA_AG_FEATURE_3WAY_CALLING:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHeadsetClient;->EXTRA_AG_FEATURE_ACCEPT_HELD_OR_WAITING_CALL:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHeadsetClient;->EXTRA_AG_FEATURE_ATTACH_NUMBER_TO_VT:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHeadsetClient;->EXTRA_AG_FEATURE_ECC:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHeadsetClient;->EXTRA_AG_FEATURE_MERGE:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHeadsetClient;->EXTRA_AG_FEATURE_MERGE_AND_DETACH:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHeadsetClient;->EXTRA_AG_FEATURE_REJECT_CALL:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHeadsetClient;->EXTRA_AG_FEATURE_RELEASE_AND_ACCEPT:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHeadsetClient;->EXTRA_AG_FEATURE_RELEASE_HELD_OR_WAITING_CALL:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHeadsetClient;->EXTRA_AG_FEATURE_RESPONSE_AND_HOLD:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHeadsetClient;->EXTRA_AG_FEATURE_VOICE_RECOGNITION:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHeadsetClient;->EXTRA_AUDIO_WBS:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHeadsetClient;->EXTRA_BATTERY_LEVEL:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHeadsetClient;->EXTRA_CALL:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHeadsetClient;->EXTRA_CME_CODE:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHeadsetClient;->EXTRA_IN_BAND_RING:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHeadsetClient;->EXTRA_NETWORK_ROAMING:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHeadsetClient;->EXTRA_NETWORK_SIGNAL_STRENGTH:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHeadsetClient;->EXTRA_NETWORK_STATUS:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHeadsetClient;->EXTRA_NUMBER:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHeadsetClient;->EXTRA_OPERATOR_NAME:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHeadsetClient;->EXTRA_RESULT_CODE:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHeadsetClient;->EXTRA_SUBSCRIBER_INFO:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHeadsetClient;->EXTRA_VOICE_RECOGNITION:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHeadsetClient;->getAudioRouteAllowed(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/BluetoothHeadsetClient;->getCurrentAgEvents(Landroid/bluetooth/BluetoothDevice;)Landroid/os/Bundle;
-Landroid/bluetooth/BluetoothHeadsetClient;->getCurrentAgFeatures(Landroid/bluetooth/BluetoothDevice;)Landroid/os/Bundle;
-Landroid/bluetooth/BluetoothHeadsetClient;->getCurrentCalls(Landroid/bluetooth/BluetoothDevice;)Ljava/util/List;
-Landroid/bluetooth/BluetoothHeadsetClient;->getLastVoiceTagNumber(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/BluetoothHeadsetClient;->getPriority(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/BluetoothHeadsetClient;->holdCall(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/BluetoothHeadsetClient;->isEnabled()Z
-Landroid/bluetooth/BluetoothHeadsetClient;->isValidDevice(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/BluetoothHeadsetClient;->log(Ljava/lang/String;)V
-Landroid/bluetooth/BluetoothHeadsetClient;->mAdapter:Landroid/bluetooth/BluetoothAdapter;
-Landroid/bluetooth/BluetoothHeadsetClient;->mBluetoothStateChangeCallback:Landroid/bluetooth/IBluetoothStateChangeCallback;
-Landroid/bluetooth/BluetoothHeadsetClient;->mConnection:Landroid/content/ServiceConnection;
-Landroid/bluetooth/BluetoothHeadsetClient;->mContext:Landroid/content/Context;
-Landroid/bluetooth/BluetoothHeadsetClient;->mService:Landroid/bluetooth/IBluetoothHeadsetClient;
-Landroid/bluetooth/BluetoothHeadsetClient;->mServiceListener:Landroid/bluetooth/BluetoothProfile$ServiceListener;
-Landroid/bluetooth/BluetoothHeadsetClient;->sendDTMF(Landroid/bluetooth/BluetoothDevice;B)Z
-Landroid/bluetooth/BluetoothHeadsetClient;->setAudioRouteAllowed(Landroid/bluetooth/BluetoothDevice;Z)V
-Landroid/bluetooth/BluetoothHeadsetClient;->setPriority(Landroid/bluetooth/BluetoothDevice;I)Z
-Landroid/bluetooth/BluetoothHeadsetClient;->startVoiceRecognition(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/BluetoothHeadsetClient;->STATE_AUDIO_CONNECTED:I
-Landroid/bluetooth/BluetoothHeadsetClient;->STATE_AUDIO_CONNECTING:I
-Landroid/bluetooth/BluetoothHeadsetClient;->STATE_AUDIO_DISCONNECTED:I
-Landroid/bluetooth/BluetoothHeadsetClient;->stopVoiceRecognition(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/BluetoothHeadsetClient;->TAG:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHeadsetClient;->terminateCall(Landroid/bluetooth/BluetoothDevice;Landroid/bluetooth/BluetoothHeadsetClientCall;)Z
-Landroid/bluetooth/BluetoothHeadsetClient;->VDBG:Z
-Landroid/bluetooth/BluetoothHeadsetClientCall;-><init>(Landroid/bluetooth/BluetoothDevice;IILjava/lang/String;ZZZ)V
-Landroid/bluetooth/BluetoothHeadsetClientCall;-><init>(Landroid/bluetooth/BluetoothDevice;ILjava/util/UUID;ILjava/lang/String;ZZZ)V
-Landroid/bluetooth/BluetoothHeadsetClientCall;->CALL_STATE_ACTIVE:I
-Landroid/bluetooth/BluetoothHeadsetClientCall;->CALL_STATE_ALERTING:I
-Landroid/bluetooth/BluetoothHeadsetClientCall;->CALL_STATE_DIALING:I
-Landroid/bluetooth/BluetoothHeadsetClientCall;->CALL_STATE_HELD:I
-Landroid/bluetooth/BluetoothHeadsetClientCall;->CALL_STATE_HELD_BY_RESPONSE_AND_HOLD:I
-Landroid/bluetooth/BluetoothHeadsetClientCall;->CALL_STATE_INCOMING:I
-Landroid/bluetooth/BluetoothHeadsetClientCall;->CALL_STATE_TERMINATED:I
-Landroid/bluetooth/BluetoothHeadsetClientCall;->CALL_STATE_WAITING:I
-Landroid/bluetooth/BluetoothHeadsetClientCall;->CREATOR:Landroid/os/Parcelable$Creator;
-Landroid/bluetooth/BluetoothHeadsetClientCall;->getCreationElapsedMilli()J
-Landroid/bluetooth/BluetoothHeadsetClientCall;->getDevice()Landroid/bluetooth/BluetoothDevice;
-Landroid/bluetooth/BluetoothHeadsetClientCall;->getUUID()Ljava/util/UUID;
-Landroid/bluetooth/BluetoothHeadsetClientCall;->isInBandRing()Z
-Landroid/bluetooth/BluetoothHeadsetClientCall;->mCreationElapsedMilli:J
-Landroid/bluetooth/BluetoothHeadsetClientCall;->mDevice:Landroid/bluetooth/BluetoothDevice;
-Landroid/bluetooth/BluetoothHeadsetClientCall;->mId:I
-Landroid/bluetooth/BluetoothHeadsetClientCall;->mInBandRing:Z
-Landroid/bluetooth/BluetoothHeadsetClientCall;->mMultiParty:Z
-Landroid/bluetooth/BluetoothHeadsetClientCall;->mNumber:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHeadsetClientCall;->mOutgoing:Z
-Landroid/bluetooth/BluetoothHeadsetClientCall;->mState:I
-Landroid/bluetooth/BluetoothHeadsetClientCall;->mUUID:Ljava/util/UUID;
-Landroid/bluetooth/BluetoothHeadsetClientCall;->setMultiParty(Z)V
-Landroid/bluetooth/BluetoothHeadsetClientCall;->setNumber(Ljava/lang/String;)V
-Landroid/bluetooth/BluetoothHeadsetClientCall;->setState(I)V
-Landroid/bluetooth/BluetoothHeadsetClientCall;->toString(Z)Ljava/lang/String;
-Landroid/bluetooth/BluetoothHealth$BluetoothHealthCallbackWrapper;-><init>(Landroid/bluetooth/BluetoothHealthCallback;)V
-Landroid/bluetooth/BluetoothHealth$BluetoothHealthCallbackWrapper;->mCallback:Landroid/bluetooth/BluetoothHealthCallback;
-Landroid/bluetooth/BluetoothHealth$BluetoothHealthCallbackWrapper;->onHealthAppConfigurationStatusChange(Landroid/bluetooth/BluetoothHealthAppConfiguration;I)V
-Landroid/bluetooth/BluetoothHealth$BluetoothHealthCallbackWrapper;->onHealthChannelStateChange(Landroid/bluetooth/BluetoothHealthAppConfiguration;Landroid/bluetooth/BluetoothDevice;IILandroid/os/ParcelFileDescriptor;I)V
-Landroid/bluetooth/BluetoothHealth;-><init>(Landroid/content/Context;Landroid/bluetooth/BluetoothProfile$ServiceListener;)V
-Landroid/bluetooth/BluetoothHealth;->CHANNEL_TYPE_ANY:I
-Landroid/bluetooth/BluetoothHealth;->checkAppParam(Ljava/lang/String;IILandroid/bluetooth/BluetoothHealthCallback;)Z
-Landroid/bluetooth/BluetoothHealth;->close()V
-Landroid/bluetooth/BluetoothHealth;->connectChannelToSink(Landroid/bluetooth/BluetoothDevice;Landroid/bluetooth/BluetoothHealthAppConfiguration;I)Z
-Landroid/bluetooth/BluetoothHealth;->DBG:Z
-Landroid/bluetooth/BluetoothHealth;->doBind()Z
-Landroid/bluetooth/BluetoothHealth;->HEALTH_OPERATION_ERROR:I
-Landroid/bluetooth/BluetoothHealth;->HEALTH_OPERATION_GENERIC_FAILURE:I
-Landroid/bluetooth/BluetoothHealth;->HEALTH_OPERATION_INVALID_ARGS:I
-Landroid/bluetooth/BluetoothHealth;->HEALTH_OPERATION_NOT_ALLOWED:I
-Landroid/bluetooth/BluetoothHealth;->HEALTH_OPERATION_NOT_FOUND:I
-Landroid/bluetooth/BluetoothHealth;->HEALTH_OPERATION_SUCCESS:I
-Landroid/bluetooth/BluetoothHealth;->isEnabled()Z
-Landroid/bluetooth/BluetoothHealth;->isValidDevice(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/BluetoothHealth;->log(Ljava/lang/String;)V
-Landroid/bluetooth/BluetoothHealth;->mAdapter:Landroid/bluetooth/BluetoothAdapter;
-Landroid/bluetooth/BluetoothHealth;->mBluetoothStateChangeCallback:Landroid/bluetooth/IBluetoothStateChangeCallback;
-Landroid/bluetooth/BluetoothHealth;->mConnection:Landroid/content/ServiceConnection;
-Landroid/bluetooth/BluetoothHealth;->mContext:Landroid/content/Context;
-Landroid/bluetooth/BluetoothHealth;->mService:Landroid/bluetooth/IBluetoothHealth;
-Landroid/bluetooth/BluetoothHealth;->mServiceListener:Landroid/bluetooth/BluetoothProfile$ServiceListener;
-Landroid/bluetooth/BluetoothHealth;->registerAppConfiguration(Ljava/lang/String;IIILandroid/bluetooth/BluetoothHealthCallback;)Z
-Landroid/bluetooth/BluetoothHealth;->TAG:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHealth;->VDBG:Z
-Landroid/bluetooth/BluetoothHealthAppConfiguration;-><init>(Ljava/lang/String;I)V
-Landroid/bluetooth/BluetoothHealthAppConfiguration;-><init>(Ljava/lang/String;III)V
-Landroid/bluetooth/BluetoothHealthAppConfiguration;->getChannelType()I
-Landroid/bluetooth/BluetoothHealthAppConfiguration;->mChannelType:I
-Landroid/bluetooth/BluetoothHealthAppConfiguration;->mDataType:I
-Landroid/bluetooth/BluetoothHealthAppConfiguration;->mName:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHealthAppConfiguration;->mRole:I
-Landroid/bluetooth/BluetoothHealthCallback;->TAG:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHearingAid;-><init>(Landroid/content/Context;Landroid/bluetooth/BluetoothProfile$ServiceListener;)V
-Landroid/bluetooth/BluetoothHearingAid;->ACTION_CONNECTION_STATE_CHANGED:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHearingAid;->ACTION_PLAYING_STATE_CHANGED:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHearingAid;->adjustVolume(I)V
-Landroid/bluetooth/BluetoothHearingAid;->close()V
-Landroid/bluetooth/BluetoothHearingAid;->connect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/BluetoothHearingAid;->DBG:Z
-Landroid/bluetooth/BluetoothHearingAid;->disconnect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/BluetoothHearingAid;->doBind()V
-Landroid/bluetooth/BluetoothHearingAid;->getDeviceMode(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/BluetoothHearingAid;->getDeviceSide(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/BluetoothHearingAid;->getHiSyncId(Landroid/bluetooth/BluetoothDevice;)J
-Landroid/bluetooth/BluetoothHearingAid;->getPriority(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/BluetoothHearingAid;->getVolume()I
-Landroid/bluetooth/BluetoothHearingAid;->HI_SYNC_ID_INVALID:J
-Landroid/bluetooth/BluetoothHearingAid;->isEnabled()Z
-Landroid/bluetooth/BluetoothHearingAid;->isValidDevice(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/BluetoothHearingAid;->log(Ljava/lang/String;)V
-Landroid/bluetooth/BluetoothHearingAid;->mAdapter:Landroid/bluetooth/BluetoothAdapter;
-Landroid/bluetooth/BluetoothHearingAid;->mBluetoothStateChangeCallback:Landroid/bluetooth/IBluetoothStateChangeCallback;
-Landroid/bluetooth/BluetoothHearingAid;->mConnection:Landroid/content/ServiceConnection;
-Landroid/bluetooth/BluetoothHearingAid;->mContext:Landroid/content/Context;
-Landroid/bluetooth/BluetoothHearingAid;->MODE_BINAURAL:I
-Landroid/bluetooth/BluetoothHearingAid;->MODE_MONAURAL:I
-Landroid/bluetooth/BluetoothHearingAid;->mService:Landroid/bluetooth/IBluetoothHearingAid;
-Landroid/bluetooth/BluetoothHearingAid;->mServiceListener:Landroid/bluetooth/BluetoothProfile$ServiceListener;
-Landroid/bluetooth/BluetoothHearingAid;->mServiceLock:Ljava/util/concurrent/locks/ReentrantReadWriteLock;
-Landroid/bluetooth/BluetoothHearingAid;->setPriority(Landroid/bluetooth/BluetoothDevice;I)Z
-Landroid/bluetooth/BluetoothHearingAid;->setVolume(I)V
-Landroid/bluetooth/BluetoothHearingAid;->SIDE_LEFT:I
-Landroid/bluetooth/BluetoothHearingAid;->SIDE_RIGHT:I
-Landroid/bluetooth/BluetoothHearingAid;->stateToString(I)Ljava/lang/String;
-Landroid/bluetooth/BluetoothHearingAid;->STATE_NOT_PLAYING:I
-Landroid/bluetooth/BluetoothHearingAid;->STATE_PLAYING:I
-Landroid/bluetooth/BluetoothHearingAid;->TAG:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHearingAid;->VDBG:Z
-Landroid/bluetooth/BluetoothHidDevice$Callback;->TAG:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHidDevice$CallbackWrapper;-><init>(Ljava/util/concurrent/Executor;Landroid/bluetooth/BluetoothHidDevice$Callback;)V
-Landroid/bluetooth/BluetoothHidDevice$CallbackWrapper;->mCallback:Landroid/bluetooth/BluetoothHidDevice$Callback;
-Landroid/bluetooth/BluetoothHidDevice$CallbackWrapper;->mExecutor:Ljava/util/concurrent/Executor;
-Landroid/bluetooth/BluetoothHidDevice$CallbackWrapper;->onAppStatusChanged(Landroid/bluetooth/BluetoothDevice;Z)V
-Landroid/bluetooth/BluetoothHidDevice$CallbackWrapper;->onConnectionStateChanged(Landroid/bluetooth/BluetoothDevice;I)V
-Landroid/bluetooth/BluetoothHidDevice$CallbackWrapper;->onGetReport(Landroid/bluetooth/BluetoothDevice;BBI)V
-Landroid/bluetooth/BluetoothHidDevice$CallbackWrapper;->onInterruptData(Landroid/bluetooth/BluetoothDevice;B[B)V
-Landroid/bluetooth/BluetoothHidDevice$CallbackWrapper;->onSetProtocol(Landroid/bluetooth/BluetoothDevice;B)V
-Landroid/bluetooth/BluetoothHidDevice$CallbackWrapper;->onSetReport(Landroid/bluetooth/BluetoothDevice;BB[B)V
-Landroid/bluetooth/BluetoothHidDevice$CallbackWrapper;->onVirtualCableUnplug(Landroid/bluetooth/BluetoothDevice;)V
-Landroid/bluetooth/BluetoothHidDevice;-><init>(Landroid/content/Context;Landroid/bluetooth/BluetoothProfile$ServiceListener;)V
-Landroid/bluetooth/BluetoothHidDevice;->close()V
-Landroid/bluetooth/BluetoothHidDevice;->doBind()Z
-Landroid/bluetooth/BluetoothHidDevice;->doUnbind()V
-Landroid/bluetooth/BluetoothHidDevice;->getUserAppName()Ljava/lang/String;
-Landroid/bluetooth/BluetoothHidDevice;->mAdapter:Landroid/bluetooth/BluetoothAdapter;
-Landroid/bluetooth/BluetoothHidDevice;->mBluetoothStateChangeCallback:Landroid/bluetooth/IBluetoothStateChangeCallback;
-Landroid/bluetooth/BluetoothHidDevice;->mConnection:Landroid/content/ServiceConnection;
-Landroid/bluetooth/BluetoothHidDevice;->mContext:Landroid/content/Context;
-Landroid/bluetooth/BluetoothHidDevice;->mService:Landroid/bluetooth/IBluetoothHidDevice;
-Landroid/bluetooth/BluetoothHidDevice;->mServiceListener:Landroid/bluetooth/BluetoothProfile$ServiceListener;
-Landroid/bluetooth/BluetoothHidDevice;->TAG:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHidDeviceAppQosSettings;->mDelayVariation:I
-Landroid/bluetooth/BluetoothHidDeviceAppQosSettings;->mLatency:I
-Landroid/bluetooth/BluetoothHidDeviceAppQosSettings;->mPeakBandwidth:I
-Landroid/bluetooth/BluetoothHidDeviceAppQosSettings;->mServiceType:I
-Landroid/bluetooth/BluetoothHidDeviceAppQosSettings;->mTokenBucketSize:I
-Landroid/bluetooth/BluetoothHidDeviceAppQosSettings;->mTokenRate:I
-Landroid/bluetooth/BluetoothHidDeviceAppSdpSettings;->mDescription:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHidDeviceAppSdpSettings;->mDescriptors:[B
-Landroid/bluetooth/BluetoothHidDeviceAppSdpSettings;->mName:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHidDeviceAppSdpSettings;->mProvider:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHidDeviceAppSdpSettings;->mSubclass:B
-Landroid/bluetooth/BluetoothHidHost;-><init>(Landroid/content/Context;Landroid/bluetooth/BluetoothProfile$ServiceListener;)V
-Landroid/bluetooth/BluetoothHidHost;->ACTION_CONNECTION_STATE_CHANGED:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHidHost;->ACTION_HANDSHAKE:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHidHost;->ACTION_IDLE_TIME_CHANGED:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHidHost;->ACTION_PROTOCOL_MODE_CHANGED:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHidHost;->ACTION_REPORT:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHidHost;->ACTION_VIRTUAL_UNPLUG_STATUS:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHidHost;->close()V
-Landroid/bluetooth/BluetoothHidHost;->connect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/BluetoothHidHost;->DBG:Z
-Landroid/bluetooth/BluetoothHidHost;->disconnect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/BluetoothHidHost;->doBind()Z
-Landroid/bluetooth/BluetoothHidHost;->EXTRA_IDLE_TIME:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHidHost;->EXTRA_PROTOCOL_MODE:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHidHost;->EXTRA_REPORT:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHidHost;->EXTRA_REPORT_BUFFER_SIZE:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHidHost;->EXTRA_REPORT_ID:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHidHost;->EXTRA_REPORT_TYPE:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHidHost;->EXTRA_STATUS:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHidHost;->EXTRA_VIRTUAL_UNPLUG_STATUS:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHidHost;->getIdleTime(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/BluetoothHidHost;->getPriority(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/BluetoothHidHost;->getProtocolMode(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/BluetoothHidHost;->getReport(Landroid/bluetooth/BluetoothDevice;BBI)Z
-Landroid/bluetooth/BluetoothHidHost;->INPUT_CONNECT_FAILED_ALREADY_CONNECTED:I
-Landroid/bluetooth/BluetoothHidHost;->INPUT_CONNECT_FAILED_ATTEMPT_FAILED:I
-Landroid/bluetooth/BluetoothHidHost;->INPUT_DISCONNECT_FAILED_NOT_CONNECTED:I
-Landroid/bluetooth/BluetoothHidHost;->INPUT_OPERATION_GENERIC_FAILURE:I
-Landroid/bluetooth/BluetoothHidHost;->INPUT_OPERATION_SUCCESS:I
-Landroid/bluetooth/BluetoothHidHost;->isEnabled()Z
-Landroid/bluetooth/BluetoothHidHost;->isValidDevice(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/BluetoothHidHost;->log(Ljava/lang/String;)V
-Landroid/bluetooth/BluetoothHidHost;->mAdapter:Landroid/bluetooth/BluetoothAdapter;
-Landroid/bluetooth/BluetoothHidHost;->mBluetoothStateChangeCallback:Landroid/bluetooth/IBluetoothStateChangeCallback;
-Landroid/bluetooth/BluetoothHidHost;->mConnection:Landroid/content/ServiceConnection;
-Landroid/bluetooth/BluetoothHidHost;->mContext:Landroid/content/Context;
-Landroid/bluetooth/BluetoothHidHost;->mService:Landroid/bluetooth/IBluetoothHidHost;
-Landroid/bluetooth/BluetoothHidHost;->mServiceListener:Landroid/bluetooth/BluetoothProfile$ServiceListener;
-Landroid/bluetooth/BluetoothHidHost;->PROTOCOL_BOOT_MODE:I
-Landroid/bluetooth/BluetoothHidHost;->PROTOCOL_REPORT_MODE:I
-Landroid/bluetooth/BluetoothHidHost;->PROTOCOL_UNSUPPORTED_MODE:I
-Landroid/bluetooth/BluetoothHidHost;->REPORT_TYPE_FEATURE:B
-Landroid/bluetooth/BluetoothHidHost;->REPORT_TYPE_INPUT:B
-Landroid/bluetooth/BluetoothHidHost;->REPORT_TYPE_OUTPUT:B
-Landroid/bluetooth/BluetoothHidHost;->sendData(Landroid/bluetooth/BluetoothDevice;Ljava/lang/String;)Z
-Landroid/bluetooth/BluetoothHidHost;->setIdleTime(Landroid/bluetooth/BluetoothDevice;B)Z
-Landroid/bluetooth/BluetoothHidHost;->setPriority(Landroid/bluetooth/BluetoothDevice;I)Z
-Landroid/bluetooth/BluetoothHidHost;->setProtocolMode(Landroid/bluetooth/BluetoothDevice;I)Z
-Landroid/bluetooth/BluetoothHidHost;->setReport(Landroid/bluetooth/BluetoothDevice;BLjava/lang/String;)Z
-Landroid/bluetooth/BluetoothHidHost;->TAG:Ljava/lang/String;
-Landroid/bluetooth/BluetoothHidHost;->VDBG:Z
-Landroid/bluetooth/BluetoothHidHost;->virtualUnplug(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/BluetoothHidHost;->VIRTUAL_UNPLUG_STATUS_FAIL:I
-Landroid/bluetooth/BluetoothHidHost;->VIRTUAL_UNPLUG_STATUS_SUCCESS:I
-Landroid/bluetooth/BluetoothInputStream;-><init>(Landroid/bluetooth/BluetoothSocket;)V
-Landroid/bluetooth/BluetoothInputStream;->mSocket:Landroid/bluetooth/BluetoothSocket;
-Landroid/bluetooth/BluetoothManager;-><init>(Landroid/content/Context;)V
-Landroid/bluetooth/BluetoothManager;->DBG:Z
-Landroid/bluetooth/BluetoothManager;->mAdapter:Landroid/bluetooth/BluetoothAdapter;
-Landroid/bluetooth/BluetoothManager;->openGattServer(Landroid/content/Context;Landroid/bluetooth/BluetoothGattServerCallback;I)Landroid/bluetooth/BluetoothGattServer;
-Landroid/bluetooth/BluetoothManager;->TAG:Ljava/lang/String;
-Landroid/bluetooth/BluetoothManager;->VDBG:Z
-Landroid/bluetooth/BluetoothMap;-><init>(Landroid/content/Context;Landroid/bluetooth/BluetoothProfile$ServiceListener;)V
-Landroid/bluetooth/BluetoothMap;->ACTION_CONNECTION_STATE_CHANGED:Ljava/lang/String;
-Landroid/bluetooth/BluetoothMap;->close()V
-Landroid/bluetooth/BluetoothMap;->connect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/BluetoothMap;->DBG:Z
-Landroid/bluetooth/BluetoothMap;->doBind()Z
-Landroid/bluetooth/BluetoothMap;->doesClassMatchSink(Landroid/bluetooth/BluetoothClass;)Z
-Landroid/bluetooth/BluetoothMap;->getClient()Landroid/bluetooth/BluetoothDevice;
-Landroid/bluetooth/BluetoothMap;->getPriority(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/BluetoothMap;->getState()I
-Landroid/bluetooth/BluetoothMap;->isConnected(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/BluetoothMap;->isEnabled()Z
-Landroid/bluetooth/BluetoothMap;->isValidDevice(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/BluetoothMap;->log(Ljava/lang/String;)V
-Landroid/bluetooth/BluetoothMap;->mAdapter:Landroid/bluetooth/BluetoothAdapter;
-Landroid/bluetooth/BluetoothMap;->mBluetoothStateChangeCallback:Landroid/bluetooth/IBluetoothStateChangeCallback;
-Landroid/bluetooth/BluetoothMap;->mConnection:Landroid/content/ServiceConnection;
-Landroid/bluetooth/BluetoothMap;->mContext:Landroid/content/Context;
-Landroid/bluetooth/BluetoothMap;->mService:Landroid/bluetooth/IBluetoothMap;
-Landroid/bluetooth/BluetoothMap;->mServiceListener:Landroid/bluetooth/BluetoothProfile$ServiceListener;
-Landroid/bluetooth/BluetoothMap;->RESULT_CANCELED:I
-Landroid/bluetooth/BluetoothMap;->RESULT_FAILURE:I
-Landroid/bluetooth/BluetoothMap;->RESULT_SUCCESS:I
-Landroid/bluetooth/BluetoothMap;->setPriority(Landroid/bluetooth/BluetoothDevice;I)Z
-Landroid/bluetooth/BluetoothMap;->STATE_ERROR:I
-Landroid/bluetooth/BluetoothMap;->TAG:Ljava/lang/String;
-Landroid/bluetooth/BluetoothMap;->VDBG:Z
-Landroid/bluetooth/BluetoothMapClient;-><init>(Landroid/content/Context;Landroid/bluetooth/BluetoothProfile$ServiceListener;)V
-Landroid/bluetooth/BluetoothMapClient;->ACTION_CONNECTION_STATE_CHANGED:Ljava/lang/String;
-Landroid/bluetooth/BluetoothMapClient;->ACTION_MESSAGE_DELIVERED_SUCCESSFULLY:Ljava/lang/String;
-Landroid/bluetooth/BluetoothMapClient;->ACTION_MESSAGE_RECEIVED:Ljava/lang/String;
-Landroid/bluetooth/BluetoothMapClient;->ACTION_MESSAGE_SENT_SUCCESSFULLY:Ljava/lang/String;
-Landroid/bluetooth/BluetoothMapClient;->close()V
-Landroid/bluetooth/BluetoothMapClient;->connect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/BluetoothMapClient;->DBG:Z
-Landroid/bluetooth/BluetoothMapClient;->disconnect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/BluetoothMapClient;->doBind()Z
-Landroid/bluetooth/BluetoothMapClient;->EXTRA_MESSAGE_HANDLE:Ljava/lang/String;
-Landroid/bluetooth/BluetoothMapClient;->EXTRA_SENDER_CONTACT_NAME:Ljava/lang/String;
-Landroid/bluetooth/BluetoothMapClient;->EXTRA_SENDER_CONTACT_URI:Ljava/lang/String;
-Landroid/bluetooth/BluetoothMapClient;->getPriority(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/BluetoothMapClient;->getUnreadMessages(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/BluetoothMapClient;->isConnected(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/BluetoothMapClient;->isEnabled()Z
-Landroid/bluetooth/BluetoothMapClient;->isValidDevice(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/BluetoothMapClient;->mAdapter:Landroid/bluetooth/BluetoothAdapter;
-Landroid/bluetooth/BluetoothMapClient;->mBluetoothStateChangeCallback:Landroid/bluetooth/IBluetoothStateChangeCallback;
-Landroid/bluetooth/BluetoothMapClient;->mConnection:Landroid/content/ServiceConnection;
-Landroid/bluetooth/BluetoothMapClient;->mContext:Landroid/content/Context;
-Landroid/bluetooth/BluetoothMapClient;->mService:Landroid/bluetooth/IBluetoothMapClient;
-Landroid/bluetooth/BluetoothMapClient;->mServiceListener:Landroid/bluetooth/BluetoothProfile$ServiceListener;
-Landroid/bluetooth/BluetoothMapClient;->RESULT_CANCELED:I
-Landroid/bluetooth/BluetoothMapClient;->RESULT_FAILURE:I
-Landroid/bluetooth/BluetoothMapClient;->RESULT_SUCCESS:I
-Landroid/bluetooth/BluetoothMapClient;->setPriority(Landroid/bluetooth/BluetoothDevice;I)Z
-Landroid/bluetooth/BluetoothMapClient;->STATE_ERROR:I
-Landroid/bluetooth/BluetoothMapClient;->TAG:Ljava/lang/String;
-Landroid/bluetooth/BluetoothMapClient;->VDBG:Z
-Landroid/bluetooth/BluetoothMasInstance$MessageType;-><init>()V
-Landroid/bluetooth/BluetoothMasInstance$MessageType;->EMAIL:I
-Landroid/bluetooth/BluetoothMasInstance$MessageType;->MMS:I
-Landroid/bluetooth/BluetoothMasInstance$MessageType;->SMS_CDMA:I
-Landroid/bluetooth/BluetoothMasInstance$MessageType;->SMS_GSM:I
-Landroid/bluetooth/BluetoothMasInstance;-><init>(ILjava/lang/String;II)V
-Landroid/bluetooth/BluetoothMasInstance;->CREATOR:Landroid/os/Parcelable$Creator;
-Landroid/bluetooth/BluetoothMasInstance;->getChannel()I
-Landroid/bluetooth/BluetoothMasInstance;->getId()I
-Landroid/bluetooth/BluetoothMasInstance;->getMsgTypes()I
-Landroid/bluetooth/BluetoothMasInstance;->getName()Ljava/lang/String;
-Landroid/bluetooth/BluetoothMasInstance;->mChannel:I
-Landroid/bluetooth/BluetoothMasInstance;->mId:I
-Landroid/bluetooth/BluetoothMasInstance;->mMsgTypes:I
-Landroid/bluetooth/BluetoothMasInstance;->mName:Ljava/lang/String;
-Landroid/bluetooth/BluetoothMasInstance;->msgSupported(I)Z
-Landroid/bluetooth/BluetoothOutputStream;-><init>(Landroid/bluetooth/BluetoothSocket;)V
-Landroid/bluetooth/BluetoothOutputStream;->mSocket:Landroid/bluetooth/BluetoothSocket;
-Landroid/bluetooth/BluetoothPan;->ACTION_CONNECTION_STATE_CHANGED:Ljava/lang/String;
-Landroid/bluetooth/BluetoothPan;->DBG:Z
-Landroid/bluetooth/BluetoothPan;->EXTRA_LOCAL_ROLE:Ljava/lang/String;
-Landroid/bluetooth/BluetoothPan;->LOCAL_NAP_ROLE:I
-Landroid/bluetooth/BluetoothPan;->LOCAL_PANU_ROLE:I
-Landroid/bluetooth/BluetoothPan;->mAdapter:Landroid/bluetooth/BluetoothAdapter;
-Landroid/bluetooth/BluetoothPan;->mConnection:Landroid/content/ServiceConnection;
-Landroid/bluetooth/BluetoothPan;->mContext:Landroid/content/Context;
-Landroid/bluetooth/BluetoothPan;->mPanService:Landroid/bluetooth/IBluetoothPan;
-Landroid/bluetooth/BluetoothPan;->mServiceListener:Landroid/bluetooth/BluetoothProfile$ServiceListener;
-Landroid/bluetooth/BluetoothPan;->mStateChangeCallback:Landroid/bluetooth/IBluetoothStateChangeCallback;
-Landroid/bluetooth/BluetoothPan;->PAN_CONNECT_FAILED_ALREADY_CONNECTED:I
-Landroid/bluetooth/BluetoothPan;->PAN_CONNECT_FAILED_ATTEMPT_FAILED:I
-Landroid/bluetooth/BluetoothPan;->PAN_DISCONNECT_FAILED_NOT_CONNECTED:I
-Landroid/bluetooth/BluetoothPan;->PAN_OPERATION_GENERIC_FAILURE:I
-Landroid/bluetooth/BluetoothPan;->PAN_OPERATION_SUCCESS:I
-Landroid/bluetooth/BluetoothPan;->PAN_ROLE_NONE:I
-Landroid/bluetooth/BluetoothPan;->REMOTE_NAP_ROLE:I
-Landroid/bluetooth/BluetoothPan;->REMOTE_PANU_ROLE:I
-Landroid/bluetooth/BluetoothPan;->TAG:Ljava/lang/String;
-Landroid/bluetooth/BluetoothPan;->VDBG:Z
-Landroid/bluetooth/BluetoothPbap$ServiceListener;->onServiceConnected(Landroid/bluetooth/BluetoothPbap;)V
-Landroid/bluetooth/BluetoothPbap$ServiceListener;->onServiceDisconnected()V
-Landroid/bluetooth/BluetoothPbap;-><init>(Landroid/content/Context;Landroid/bluetooth/BluetoothPbap$ServiceListener;)V
-Landroid/bluetooth/BluetoothPbap;->ACTION_CONNECTION_STATE_CHANGED:Ljava/lang/String;
-Landroid/bluetooth/BluetoothPbap;->close()V
-Landroid/bluetooth/BluetoothPbap;->DBG:Z
-Landroid/bluetooth/BluetoothPbap;->doBind()Z
-Landroid/bluetooth/BluetoothPbap;->isConnected(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/BluetoothPbap;->log(Ljava/lang/String;)V
-Landroid/bluetooth/BluetoothPbap;->mAdapter:Landroid/bluetooth/BluetoothAdapter;
-Landroid/bluetooth/BluetoothPbap;->mBluetoothStateChangeCallback:Landroid/bluetooth/IBluetoothStateChangeCallback;
-Landroid/bluetooth/BluetoothPbap;->mConnection:Landroid/content/ServiceConnection;
-Landroid/bluetooth/BluetoothPbap;->mContext:Landroid/content/Context;
-Landroid/bluetooth/BluetoothPbap;->mService:Landroid/bluetooth/IBluetoothPbap;
-Landroid/bluetooth/BluetoothPbap;->mServiceListener:Landroid/bluetooth/BluetoothPbap$ServiceListener;
-Landroid/bluetooth/BluetoothPbap;->RESULT_CANCELED:I
-Landroid/bluetooth/BluetoothPbap;->RESULT_FAILURE:I
-Landroid/bluetooth/BluetoothPbap;->RESULT_SUCCESS:I
-Landroid/bluetooth/BluetoothPbap;->TAG:Ljava/lang/String;
-Landroid/bluetooth/BluetoothPbapClient;-><init>(Landroid/content/Context;Landroid/bluetooth/BluetoothProfile$ServiceListener;)V
-Landroid/bluetooth/BluetoothPbapClient;->ACTION_CONNECTION_STATE_CHANGED:Ljava/lang/String;
-Landroid/bluetooth/BluetoothPbapClient;->close()V
-Landroid/bluetooth/BluetoothPbapClient;->connect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/BluetoothPbapClient;->DBG:Z
-Landroid/bluetooth/BluetoothPbapClient;->disconnect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/BluetoothPbapClient;->doBind()Z
-Landroid/bluetooth/BluetoothPbapClient;->getPriority(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/BluetoothPbapClient;->isEnabled()Z
-Landroid/bluetooth/BluetoothPbapClient;->isValidDevice(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/BluetoothPbapClient;->log(Ljava/lang/String;)V
-Landroid/bluetooth/BluetoothPbapClient;->mAdapter:Landroid/bluetooth/BluetoothAdapter;
-Landroid/bluetooth/BluetoothPbapClient;->mBluetoothStateChangeCallback:Landroid/bluetooth/IBluetoothStateChangeCallback;
-Landroid/bluetooth/BluetoothPbapClient;->mConnection:Landroid/content/ServiceConnection;
-Landroid/bluetooth/BluetoothPbapClient;->mContext:Landroid/content/Context;
-Landroid/bluetooth/BluetoothPbapClient;->mService:Landroid/bluetooth/IBluetoothPbapClient;
-Landroid/bluetooth/BluetoothPbapClient;->mServiceListener:Landroid/bluetooth/BluetoothProfile$ServiceListener;
-Landroid/bluetooth/BluetoothPbapClient;->RESULT_CANCELED:I
-Landroid/bluetooth/BluetoothPbapClient;->RESULT_FAILURE:I
-Landroid/bluetooth/BluetoothPbapClient;->RESULT_SUCCESS:I
-Landroid/bluetooth/BluetoothPbapClient;->setPriority(Landroid/bluetooth/BluetoothDevice;I)Z
-Landroid/bluetooth/BluetoothPbapClient;->STATE_ERROR:I
-Landroid/bluetooth/BluetoothPbapClient;->TAG:Ljava/lang/String;
-Landroid/bluetooth/BluetoothPbapClient;->VDBG:Z
-Landroid/bluetooth/BluetoothProfile;->AVRCP:I
-Landroid/bluetooth/BluetoothProfile;->getConnectionStateName(I)Ljava/lang/String;
-Landroid/bluetooth/BluetoothProfile;->HEADSET_CLIENT:I
-Landroid/bluetooth/BluetoothProfile;->HEARING_AID:I
-Landroid/bluetooth/BluetoothProfile;->HID_HOST:I
-Landroid/bluetooth/BluetoothProfile;->MAP:I
-Landroid/bluetooth/BluetoothProfile;->MAP_CLIENT:I
-Landroid/bluetooth/BluetoothProfile;->MAX_PROFILE_ID:I
-Landroid/bluetooth/BluetoothProfile;->OPP:I
-Landroid/bluetooth/BluetoothProfile;->PBAP:I
-Landroid/bluetooth/BluetoothProfile;->PBAP_CLIENT:I
-Landroid/bluetooth/BluetoothProtoEnums;-><init>()V
-Landroid/bluetooth/BluetoothProtoEnums;->CONNECTION_STATE_CONNECTED:I
-Landroid/bluetooth/BluetoothProtoEnums;->CONNECTION_STATE_CONNECTING:I
-Landroid/bluetooth/BluetoothProtoEnums;->CONNECTION_STATE_DISCONNECTED:I
-Landroid/bluetooth/BluetoothProtoEnums;->CONNECTION_STATE_DISCONNECTING:I
-Landroid/bluetooth/BluetoothProtoEnums;->ENABLE_DISABLE_REASON_AIRPLANE_MODE:I
-Landroid/bluetooth/BluetoothProtoEnums;->ENABLE_DISABLE_REASON_APPLICATION_REQUEST:I
-Landroid/bluetooth/BluetoothProtoEnums;->ENABLE_DISABLE_REASON_CRASH:I
-Landroid/bluetooth/BluetoothProtoEnums;->ENABLE_DISABLE_REASON_DISALLOWED:I
-Landroid/bluetooth/BluetoothProtoEnums;->ENABLE_DISABLE_REASON_RESTARTED:I
-Landroid/bluetooth/BluetoothProtoEnums;->ENABLE_DISABLE_REASON_RESTORE_USER_SETTING:I
-Landroid/bluetooth/BluetoothProtoEnums;->ENABLE_DISABLE_REASON_START_ERROR:I
-Landroid/bluetooth/BluetoothProtoEnums;->ENABLE_DISABLE_REASON_SYSTEM_BOOT:I
-Landroid/bluetooth/BluetoothProtoEnums;->ENABLE_DISABLE_REASON_UNSPECIFIED:I
-Landroid/bluetooth/BluetoothProtoEnums;->ENABLE_DISABLE_REASON_USER_SWITCH:I
-Landroid/bluetooth/BluetoothSap;-><init>(Landroid/content/Context;Landroid/bluetooth/BluetoothProfile$ServiceListener;)V
-Landroid/bluetooth/BluetoothSap;->ACTION_CONNECTION_STATE_CHANGED:Ljava/lang/String;
-Landroid/bluetooth/BluetoothSap;->close()V
-Landroid/bluetooth/BluetoothSap;->connect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/BluetoothSap;->DBG:Z
-Landroid/bluetooth/BluetoothSap;->doBind()Z
-Landroid/bluetooth/BluetoothSap;->getClient()Landroid/bluetooth/BluetoothDevice;
-Landroid/bluetooth/BluetoothSap;->getPriority(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/BluetoothSap;->getState()I
-Landroid/bluetooth/BluetoothSap;->isConnected(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/BluetoothSap;->isEnabled()Z
-Landroid/bluetooth/BluetoothSap;->isValidDevice(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/BluetoothSap;->log(Ljava/lang/String;)V
-Landroid/bluetooth/BluetoothSap;->mAdapter:Landroid/bluetooth/BluetoothAdapter;
-Landroid/bluetooth/BluetoothSap;->mBluetoothStateChangeCallback:Landroid/bluetooth/IBluetoothStateChangeCallback;
-Landroid/bluetooth/BluetoothSap;->mConnection:Landroid/content/ServiceConnection;
-Landroid/bluetooth/BluetoothSap;->mContext:Landroid/content/Context;
-Landroid/bluetooth/BluetoothSap;->mService:Landroid/bluetooth/IBluetoothSap;
-Landroid/bluetooth/BluetoothSap;->mServiceListener:Landroid/bluetooth/BluetoothProfile$ServiceListener;
-Landroid/bluetooth/BluetoothSap;->RESULT_CANCELED:I
-Landroid/bluetooth/BluetoothSap;->RESULT_SUCCESS:I
-Landroid/bluetooth/BluetoothSap;->setPriority(Landroid/bluetooth/BluetoothDevice;I)Z
-Landroid/bluetooth/BluetoothSap;->STATE_ERROR:I
-Landroid/bluetooth/BluetoothSap;->TAG:Ljava/lang/String;
-Landroid/bluetooth/BluetoothSap;->VDBG:Z
-Landroid/bluetooth/BluetoothServerSocket;-><init>(IZZI)V
-Landroid/bluetooth/BluetoothServerSocket;-><init>(IZZIZZ)V
-Landroid/bluetooth/BluetoothServerSocket;-><init>(IZZLandroid/os/ParcelUuid;)V
-Landroid/bluetooth/BluetoothServerSocket;->DBG:Z
-Landroid/bluetooth/BluetoothServerSocket;->getChannel()I
-Landroid/bluetooth/BluetoothServerSocket;->getPsm()I
-Landroid/bluetooth/BluetoothServerSocket;->mChannel:I
-Landroid/bluetooth/BluetoothServerSocket;->mHandler:Landroid/os/Handler;
-Landroid/bluetooth/BluetoothServerSocket;->mMessage:I
-Landroid/bluetooth/BluetoothServerSocket;->setChannel(I)V
-Landroid/bluetooth/BluetoothServerSocket;->setCloseHandler(Landroid/os/Handler;I)V
-Landroid/bluetooth/BluetoothServerSocket;->setServiceName(Ljava/lang/String;)V
-Landroid/bluetooth/BluetoothServerSocket;->TAG:Ljava/lang/String;
-Landroid/bluetooth/BluetoothSocket$SocketState;->CLOSED:Landroid/bluetooth/BluetoothSocket$SocketState;
-Landroid/bluetooth/BluetoothSocket$SocketState;->CONNECTED:Landroid/bluetooth/BluetoothSocket$SocketState;
-Landroid/bluetooth/BluetoothSocket$SocketState;->INIT:Landroid/bluetooth/BluetoothSocket$SocketState;
-Landroid/bluetooth/BluetoothSocket$SocketState;->LISTENING:Landroid/bluetooth/BluetoothSocket$SocketState;
-Landroid/bluetooth/BluetoothSocket$SocketState;->valueOf(Ljava/lang/String;)Landroid/bluetooth/BluetoothSocket$SocketState;
-Landroid/bluetooth/BluetoothSocket$SocketState;->values()[Landroid/bluetooth/BluetoothSocket$SocketState;
-Landroid/bluetooth/BluetoothSocket;-><init>(IIZZLandroid/bluetooth/BluetoothDevice;ILandroid/os/ParcelUuid;)V
-Landroid/bluetooth/BluetoothSocket;-><init>(IIZZLandroid/bluetooth/BluetoothDevice;ILandroid/os/ParcelUuid;ZZ)V
-Landroid/bluetooth/BluetoothSocket;-><init>(IIZZLjava/lang/String;I)V
-Landroid/bluetooth/BluetoothSocket;-><init>(Landroid/bluetooth/BluetoothSocket;)V
-Landroid/bluetooth/BluetoothSocket;->accept(I)Landroid/bluetooth/BluetoothSocket;
-Landroid/bluetooth/BluetoothSocket;->acceptSocket(Ljava/lang/String;)Landroid/bluetooth/BluetoothSocket;
-Landroid/bluetooth/BluetoothSocket;->available()I
-Landroid/bluetooth/BluetoothSocket;->bindListen()I
-Landroid/bluetooth/BluetoothSocket;->BTSOCK_FLAG_NO_SDP:I
-Landroid/bluetooth/BluetoothSocket;->convertAddr([B)Ljava/lang/String;
-Landroid/bluetooth/BluetoothSocket;->createL2capRxBuffer()V
-Landroid/bluetooth/BluetoothSocket;->DBG:Z
-Landroid/bluetooth/BluetoothSocket;->EBADFD:I
-Landroid/bluetooth/BluetoothSocket;->fillL2capRxBuffer()I
-Landroid/bluetooth/BluetoothSocket;->getPort()I
-Landroid/bluetooth/BluetoothSocket;->getSecurityFlags()I
-Landroid/bluetooth/BluetoothSocket;->mAddress:Ljava/lang/String;
-Landroid/bluetooth/BluetoothSocket;->mAuth:Z
-Landroid/bluetooth/BluetoothSocket;->mAuthMitm:Z
-Landroid/bluetooth/BluetoothSocket;->MAX_L2CAP_PACKAGE_SIZE:I
-Landroid/bluetooth/BluetoothSocket;->MAX_RFCOMM_CHANNEL:I
-Landroid/bluetooth/BluetoothSocket;->mDevice:Landroid/bluetooth/BluetoothDevice;
-Landroid/bluetooth/BluetoothSocket;->mEncrypt:Z
-Landroid/bluetooth/BluetoothSocket;->mExcludeSdp:Z
-Landroid/bluetooth/BluetoothSocket;->mFd:I
-Landroid/bluetooth/BluetoothSocket;->mInputStream:Landroid/bluetooth/BluetoothInputStream;
-Landroid/bluetooth/BluetoothSocket;->mL2capBuffer:Ljava/nio/ByteBuffer;
-Landroid/bluetooth/BluetoothSocket;->mMaxRxPacketSize:I
-Landroid/bluetooth/BluetoothSocket;->mMaxTxPacketSize:I
-Landroid/bluetooth/BluetoothSocket;->mMin16DigitPin:Z
-Landroid/bluetooth/BluetoothSocket;->mOutputStream:Landroid/bluetooth/BluetoothOutputStream;
-Landroid/bluetooth/BluetoothSocket;->mServiceName:Ljava/lang/String;
-Landroid/bluetooth/BluetoothSocket;->mSocketIS:Ljava/io/InputStream;
-Landroid/bluetooth/BluetoothSocket;->mSocketOS:Ljava/io/OutputStream;
-Landroid/bluetooth/BluetoothSocket;->mSocketState:Landroid/bluetooth/BluetoothSocket$SocketState;
-Landroid/bluetooth/BluetoothSocket;->mType:I
-Landroid/bluetooth/BluetoothSocket;->mUuid:Landroid/os/ParcelUuid;
-Landroid/bluetooth/BluetoothSocket;->PROXY_CONNECTION_TIMEOUT:I
-Landroid/bluetooth/BluetoothSocket;->read([BII)I
-Landroid/bluetooth/BluetoothSocket;->readAll(Ljava/io/InputStream;[B)I
-Landroid/bluetooth/BluetoothSocket;->readInt(Ljava/io/InputStream;)I
-Landroid/bluetooth/BluetoothSocket;->removeChannel()V
-Landroid/bluetooth/BluetoothSocket;->requestMaximumTxDataLength()V
-Landroid/bluetooth/BluetoothSocket;->SEC_FLAG_AUTH:I
-Landroid/bluetooth/BluetoothSocket;->SEC_FLAG_AUTH_16_DIGIT:I
-Landroid/bluetooth/BluetoothSocket;->SEC_FLAG_AUTH_MITM:I
-Landroid/bluetooth/BluetoothSocket;->SEC_FLAG_ENCRYPT:I
-Landroid/bluetooth/BluetoothSocket;->setExcludeSdp(Z)V
-Landroid/bluetooth/BluetoothSocket;->setServiceName(Ljava/lang/String;)V
-Landroid/bluetooth/BluetoothSocket;->SOCK_SIGNAL_SIZE:I
-Landroid/bluetooth/BluetoothSocket;->TAG:Ljava/lang/String;
-Landroid/bluetooth/BluetoothSocket;->TYPE_L2CAP_BREDR:I
-Landroid/bluetooth/BluetoothSocket;->TYPE_L2CAP_LE:I
-Landroid/bluetooth/BluetoothSocket;->VDBG:Z
-Landroid/bluetooth/BluetoothSocket;->waitSocketSignal(Ljava/io/InputStream;)Ljava/lang/String;
-Landroid/bluetooth/BluetoothSocket;->write([BII)I
-Landroid/bluetooth/BluetoothUuid;-><init>()V
-Landroid/bluetooth/BluetoothUuid;->AudioSource:Landroid/os/ParcelUuid;
-Landroid/bluetooth/BluetoothUuid;->AvrcpController:Landroid/os/ParcelUuid;
-Landroid/bluetooth/BluetoothUuid;->AvrcpTarget:Landroid/os/ParcelUuid;
-Landroid/bluetooth/BluetoothUuid;->BASE_UUID:Landroid/os/ParcelUuid;
-Landroid/bluetooth/BluetoothUuid;->BNEP:Landroid/os/ParcelUuid;
-Landroid/bluetooth/BluetoothUuid;->containsAllUuids([Landroid/os/ParcelUuid;[Landroid/os/ParcelUuid;)Z
-Landroid/bluetooth/BluetoothUuid;->getServiceIdentifierFromParcelUuid(Landroid/os/ParcelUuid;)I
-Landroid/bluetooth/BluetoothUuid;->Handsfree_AG:Landroid/os/ParcelUuid;
-Landroid/bluetooth/BluetoothUuid;->HearingAid:Landroid/os/ParcelUuid;
-Landroid/bluetooth/BluetoothUuid;->Hid:Landroid/os/ParcelUuid;
-Landroid/bluetooth/BluetoothUuid;->HSP_AG:Landroid/os/ParcelUuid;
-Landroid/bluetooth/BluetoothUuid;->isAudioSink(Landroid/os/ParcelUuid;)Z
-Landroid/bluetooth/BluetoothUuid;->isAvrcpController(Landroid/os/ParcelUuid;)Z
-Landroid/bluetooth/BluetoothUuid;->isBnep(Landroid/os/ParcelUuid;)Z
-Landroid/bluetooth/BluetoothUuid;->isHandsfree(Landroid/os/ParcelUuid;)Z
-Landroid/bluetooth/BluetoothUuid;->isHeadset(Landroid/os/ParcelUuid;)Z
-Landroid/bluetooth/BluetoothUuid;->isInputDevice(Landroid/os/ParcelUuid;)Z
-Landroid/bluetooth/BluetoothUuid;->isMap(Landroid/os/ParcelUuid;)Z
-Landroid/bluetooth/BluetoothUuid;->isMas(Landroid/os/ParcelUuid;)Z
-Landroid/bluetooth/BluetoothUuid;->isMns(Landroid/os/ParcelUuid;)Z
-Landroid/bluetooth/BluetoothUuid;->isNap(Landroid/os/ParcelUuid;)Z
-Landroid/bluetooth/BluetoothUuid;->isPanu(Landroid/os/ParcelUuid;)Z
-Landroid/bluetooth/BluetoothUuid;->isSap(Landroid/os/ParcelUuid;)Z
-Landroid/bluetooth/BluetoothUuid;->MAP:Landroid/os/ParcelUuid;
-Landroid/bluetooth/BluetoothUuid;->MAS:Landroid/os/ParcelUuid;
-Landroid/bluetooth/BluetoothUuid;->MNS:Landroid/os/ParcelUuid;
-Landroid/bluetooth/BluetoothUuid;->PANU:Landroid/os/ParcelUuid;
-Landroid/bluetooth/BluetoothUuid;->parseUuidFrom([B)Landroid/os/ParcelUuid;
-Landroid/bluetooth/BluetoothUuid;->PBAP_PCE:Landroid/os/ParcelUuid;
-Landroid/bluetooth/BluetoothUuid;->SAP:Landroid/os/ParcelUuid;
-Landroid/bluetooth/BluetoothUuid;->uuidToBytes(Landroid/os/ParcelUuid;)[B
-Landroid/bluetooth/BluetoothUuid;->UUID_BYTES_128_BIT:I
-Landroid/bluetooth/BluetoothUuid;->UUID_BYTES_16_BIT:I
-Landroid/bluetooth/BluetoothUuid;->UUID_BYTES_32_BIT:I
-Landroid/bluetooth/IBluetooth$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->cancelBondProcess(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->cancelDiscovery()Z
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->createBond(Landroid/bluetooth/BluetoothDevice;I)Z
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->createBondOutOfBand(Landroid/bluetooth/BluetoothDevice;ILandroid/bluetooth/OobData;)Z
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->disable()Z
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->enable()Z
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->enableNoAutoConnect()Z
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->factoryReset()Z
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->fetchRemoteUuids(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->getAdapterConnectionState()I
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->getBatteryLevel(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->getBluetoothClass()Landroid/bluetooth/BluetoothClass;
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->getBondedDevices()[Landroid/bluetooth/BluetoothDevice;
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->getBondState(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->getDiscoverableTimeout()I
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->getDiscoveryEndMillis()J
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->getLeMaximumAdvertisingDataLength()I
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->getMaxConnectedAudioDevices()I
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->getMessageAccessPermission(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->getName()Ljava/lang/String;
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->getPhonebookAccessPermission(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->getProfileConnectionState(I)I
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->getRemoteAlias(Landroid/bluetooth/BluetoothDevice;)Ljava/lang/String;
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->getRemoteClass(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->getRemoteName(Landroid/bluetooth/BluetoothDevice;)Ljava/lang/String;
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->getRemoteType(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->getRemoteUuids(Landroid/bluetooth/BluetoothDevice;)[Landroid/os/ParcelUuid;
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->getScanMode()I
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->getSimAccessPermission(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->getSocketManager()Landroid/bluetooth/IBluetoothSocketManager;
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->getState()I
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->getSupportedProfiles()J
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->getUuids()[Landroid/os/ParcelUuid;
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->isActivityAndEnergyReportingSupported()Z
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->isBondingInitiatedLocally(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->isDiscovering()Z
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->isEnabled()Z
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->isLe2MPhySupported()Z
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->isLeCodedPhySupported()Z
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->isLeExtendedAdvertisingSupported()Z
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->isLePeriodicAdvertisingSupported()Z
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->isMultiAdvertisementSupported()Z
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->isOffloadedFilteringSupported()Z
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->isOffloadedScanBatchingSupported()Z
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->mRemote:Landroid/os/IBinder;
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->onBrEdrDown()V
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->onLeServiceUp()V
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->registerCallback(Landroid/bluetooth/IBluetoothCallback;)V
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->removeBond(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->reportActivityInfo()Landroid/bluetooth/BluetoothActivityEnergyInfo;
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->requestActivityInfo(Landroid/os/ResultReceiver;)V
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->sdpSearch(Landroid/bluetooth/BluetoothDevice;Landroid/os/ParcelUuid;)Z
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->sendConnectionStateChange(Landroid/bluetooth/BluetoothDevice;III)V
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->setBluetoothClass(Landroid/bluetooth/BluetoothClass;)Z
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->setDiscoverableTimeout(I)Z
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->setMessageAccessPermission(Landroid/bluetooth/BluetoothDevice;I)Z
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->setName(Ljava/lang/String;)Z
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->setPairingConfirmation(Landroid/bluetooth/BluetoothDevice;Z)Z
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->setPasskey(Landroid/bluetooth/BluetoothDevice;ZI[B)Z
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->setPhonebookAccessPermission(Landroid/bluetooth/BluetoothDevice;I)Z
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->setPin(Landroid/bluetooth/BluetoothDevice;ZI[B)Z
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->setRemoteAlias(Landroid/bluetooth/BluetoothDevice;Ljava/lang/String;)Z
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->setScanMode(II)Z
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->setSimAccessPermission(Landroid/bluetooth/BluetoothDevice;I)Z
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->startDiscovery()Z
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->unregisterCallback(Landroid/bluetooth/IBluetoothCallback;)V
-Landroid/bluetooth/IBluetooth$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_cancelBondProcess:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_cancelDiscovery:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_createBond:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_createBondOutOfBand:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_disable:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_enableNoAutoConnect:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_factoryReset:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_fetchRemoteUuids:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_getAdapterConnectionState:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_getAddress:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_getBatteryLevel:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_getBluetoothClass:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_getBondedDevices:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_getBondState:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_getConnectionState:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_getDiscoverableTimeout:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_getDiscoveryEndMillis:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_getLeMaximumAdvertisingDataLength:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_getMaxConnectedAudioDevices:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_getMessageAccessPermission:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_getName:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_getPhonebookAccessPermission:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_getProfileConnectionState:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_getRemoteAlias:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_getRemoteClass:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_getRemoteName:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_getRemoteType:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_getRemoteUuids:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_getScanMode:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_getSimAccessPermission:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_getSocketManager:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_getState:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_getSupportedProfiles:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_getUuids:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_isActivityAndEnergyReportingSupported:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_isBondingInitiatedLocally:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_isDiscovering:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_isEnabled:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_isLe2MPhySupported:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_isLeCodedPhySupported:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_isLeExtendedAdvertisingSupported:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_isLePeriodicAdvertisingSupported:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_isMultiAdvertisementSupported:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_isOffloadedFilteringSupported:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_isOffloadedScanBatchingSupported:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_onBrEdrDown:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_onLeServiceUp:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_registerCallback:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_removeBond:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_reportActivityInfo:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_requestActivityInfo:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_sdpSearch:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_sendConnectionStateChange:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_setBluetoothClass:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_setDiscoverableTimeout:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_setMessageAccessPermission:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_setName:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_setPairingConfirmation:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_setPasskey:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_setPhonebookAccessPermission:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_setPin:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_setRemoteAlias:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_setScanMode:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_setSimAccessPermission:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_startDiscovery:I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_unregisterCallback:I
-Landroid/bluetooth/IBluetooth;->cancelBondProcess(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetooth;->cancelDiscovery()Z
-Landroid/bluetooth/IBluetooth;->createBond(Landroid/bluetooth/BluetoothDevice;I)Z
-Landroid/bluetooth/IBluetooth;->createBondOutOfBand(Landroid/bluetooth/BluetoothDevice;ILandroid/bluetooth/OobData;)Z
-Landroid/bluetooth/IBluetooth;->disable()Z
-Landroid/bluetooth/IBluetooth;->enable()Z
-Landroid/bluetooth/IBluetooth;->enableNoAutoConnect()Z
-Landroid/bluetooth/IBluetooth;->factoryReset()Z
-Landroid/bluetooth/IBluetooth;->getAdapterConnectionState()I
-Landroid/bluetooth/IBluetooth;->getBatteryLevel(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetooth;->getBluetoothClass()Landroid/bluetooth/BluetoothClass;
-Landroid/bluetooth/IBluetooth;->getBondedDevices()[Landroid/bluetooth/BluetoothDevice;
-Landroid/bluetooth/IBluetooth;->getBondState(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetooth;->getConnectionState(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetooth;->getDiscoverableTimeout()I
-Landroid/bluetooth/IBluetooth;->getDiscoveryEndMillis()J
-Landroid/bluetooth/IBluetooth;->getLeMaximumAdvertisingDataLength()I
-Landroid/bluetooth/IBluetooth;->getMaxConnectedAudioDevices()I
-Landroid/bluetooth/IBluetooth;->getMessageAccessPermission(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetooth;->getName()Ljava/lang/String;
-Landroid/bluetooth/IBluetooth;->getPhonebookAccessPermission(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetooth;->getProfileConnectionState(I)I
-Landroid/bluetooth/IBluetooth;->getRemoteClass(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetooth;->getRemoteName(Landroid/bluetooth/BluetoothDevice;)Ljava/lang/String;
-Landroid/bluetooth/IBluetooth;->getRemoteType(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetooth;->getRemoteUuids(Landroid/bluetooth/BluetoothDevice;)[Landroid/os/ParcelUuid;
-Landroid/bluetooth/IBluetooth;->getScanMode()I
-Landroid/bluetooth/IBluetooth;->getSimAccessPermission(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetooth;->getSocketManager()Landroid/bluetooth/IBluetoothSocketManager;
-Landroid/bluetooth/IBluetooth;->getState()I
-Landroid/bluetooth/IBluetooth;->getSupportedProfiles()J
-Landroid/bluetooth/IBluetooth;->getUuids()[Landroid/os/ParcelUuid;
-Landroid/bluetooth/IBluetooth;->isActivityAndEnergyReportingSupported()Z
-Landroid/bluetooth/IBluetooth;->isBondingInitiatedLocally(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetooth;->isDiscovering()Z
-Landroid/bluetooth/IBluetooth;->isLe2MPhySupported()Z
-Landroid/bluetooth/IBluetooth;->isLeCodedPhySupported()Z
-Landroid/bluetooth/IBluetooth;->isLeExtendedAdvertisingSupported()Z
-Landroid/bluetooth/IBluetooth;->isLePeriodicAdvertisingSupported()Z
-Landroid/bluetooth/IBluetooth;->isMultiAdvertisementSupported()Z
-Landroid/bluetooth/IBluetooth;->isOffloadedFilteringSupported()Z
-Landroid/bluetooth/IBluetooth;->isOffloadedScanBatchingSupported()Z
-Landroid/bluetooth/IBluetooth;->onBrEdrDown()V
-Landroid/bluetooth/IBluetooth;->onLeServiceUp()V
-Landroid/bluetooth/IBluetooth;->registerCallback(Landroid/bluetooth/IBluetoothCallback;)V
-Landroid/bluetooth/IBluetooth;->removeBond(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetooth;->reportActivityInfo()Landroid/bluetooth/BluetoothActivityEnergyInfo;
-Landroid/bluetooth/IBluetooth;->requestActivityInfo(Landroid/os/ResultReceiver;)V
-Landroid/bluetooth/IBluetooth;->sdpSearch(Landroid/bluetooth/BluetoothDevice;Landroid/os/ParcelUuid;)Z
-Landroid/bluetooth/IBluetooth;->setBluetoothClass(Landroid/bluetooth/BluetoothClass;)Z
-Landroid/bluetooth/IBluetooth;->setDiscoverableTimeout(I)Z
-Landroid/bluetooth/IBluetooth;->setMessageAccessPermission(Landroid/bluetooth/BluetoothDevice;I)Z
-Landroid/bluetooth/IBluetooth;->setName(Ljava/lang/String;)Z
-Landroid/bluetooth/IBluetooth;->setPairingConfirmation(Landroid/bluetooth/BluetoothDevice;Z)Z
-Landroid/bluetooth/IBluetooth;->setPasskey(Landroid/bluetooth/BluetoothDevice;ZI[B)Z
-Landroid/bluetooth/IBluetooth;->setPhonebookAccessPermission(Landroid/bluetooth/BluetoothDevice;I)Z
-Landroid/bluetooth/IBluetooth;->setPin(Landroid/bluetooth/BluetoothDevice;ZI[B)Z
-Landroid/bluetooth/IBluetooth;->setRemoteAlias(Landroid/bluetooth/BluetoothDevice;Ljava/lang/String;)Z
-Landroid/bluetooth/IBluetooth;->setScanMode(II)Z
-Landroid/bluetooth/IBluetooth;->setSimAccessPermission(Landroid/bluetooth/BluetoothDevice;I)Z
-Landroid/bluetooth/IBluetooth;->startDiscovery()Z
-Landroid/bluetooth/IBluetooth;->unregisterCallback(Landroid/bluetooth/IBluetoothCallback;)V
-Landroid/bluetooth/IBluetoothA2dp$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/bluetooth/IBluetoothA2dp$Stub$Proxy;->connect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothA2dp$Stub$Proxy;->disableOptionalCodecs(Landroid/bluetooth/BluetoothDevice;)V
-Landroid/bluetooth/IBluetoothA2dp$Stub$Proxy;->disconnect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothA2dp$Stub$Proxy;->enableOptionalCodecs(Landroid/bluetooth/BluetoothDevice;)V
-Landroid/bluetooth/IBluetoothA2dp$Stub$Proxy;->getActiveDevice()Landroid/bluetooth/BluetoothDevice;
-Landroid/bluetooth/IBluetoothA2dp$Stub$Proxy;->getCodecStatus(Landroid/bluetooth/BluetoothDevice;)Landroid/bluetooth/BluetoothCodecStatus;
-Landroid/bluetooth/IBluetoothA2dp$Stub$Proxy;->getConnectedDevices()Ljava/util/List;
-Landroid/bluetooth/IBluetoothA2dp$Stub$Proxy;->getConnectionState(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothA2dp$Stub$Proxy;->getDevicesMatchingConnectionStates([I)Ljava/util/List;
-Landroid/bluetooth/IBluetoothA2dp$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
-Landroid/bluetooth/IBluetoothA2dp$Stub$Proxy;->getOptionalCodecsEnabled(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothA2dp$Stub$Proxy;->getPriority(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothA2dp$Stub$Proxy;->isA2dpPlaying(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothA2dp$Stub$Proxy;->isAvrcpAbsoluteVolumeSupported()Z
-Landroid/bluetooth/IBluetoothA2dp$Stub$Proxy;->mRemote:Landroid/os/IBinder;
-Landroid/bluetooth/IBluetoothA2dp$Stub$Proxy;->setActiveDevice(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothA2dp$Stub$Proxy;->setAvrcpAbsoluteVolume(I)V
-Landroid/bluetooth/IBluetoothA2dp$Stub$Proxy;->setCodecConfigPreference(Landroid/bluetooth/BluetoothDevice;Landroid/bluetooth/BluetoothCodecConfig;)V
-Landroid/bluetooth/IBluetoothA2dp$Stub$Proxy;->setOptionalCodecsEnabled(Landroid/bluetooth/BluetoothDevice;I)V
-Landroid/bluetooth/IBluetoothA2dp$Stub$Proxy;->setPriority(Landroid/bluetooth/BluetoothDevice;I)Z
-Landroid/bluetooth/IBluetoothA2dp$Stub$Proxy;->supportsOptionalCodecs(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothA2dp$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/bluetooth/IBluetoothA2dp$Stub;->TRANSACTION_connect:I
-Landroid/bluetooth/IBluetoothA2dp$Stub;->TRANSACTION_disableOptionalCodecs:I
-Landroid/bluetooth/IBluetoothA2dp$Stub;->TRANSACTION_disconnect:I
-Landroid/bluetooth/IBluetoothA2dp$Stub;->TRANSACTION_enableOptionalCodecs:I
-Landroid/bluetooth/IBluetoothA2dp$Stub;->TRANSACTION_getActiveDevice:I
-Landroid/bluetooth/IBluetoothA2dp$Stub;->TRANSACTION_getCodecStatus:I
-Landroid/bluetooth/IBluetoothA2dp$Stub;->TRANSACTION_getConnectedDevices:I
-Landroid/bluetooth/IBluetoothA2dp$Stub;->TRANSACTION_getConnectionState:I
-Landroid/bluetooth/IBluetoothA2dp$Stub;->TRANSACTION_getDevicesMatchingConnectionStates:I
-Landroid/bluetooth/IBluetoothA2dp$Stub;->TRANSACTION_getOptionalCodecsEnabled:I
-Landroid/bluetooth/IBluetoothA2dp$Stub;->TRANSACTION_getPriority:I
-Landroid/bluetooth/IBluetoothA2dp$Stub;->TRANSACTION_isA2dpPlaying:I
-Landroid/bluetooth/IBluetoothA2dp$Stub;->TRANSACTION_isAvrcpAbsoluteVolumeSupported:I
-Landroid/bluetooth/IBluetoothA2dp$Stub;->TRANSACTION_setActiveDevice:I
-Landroid/bluetooth/IBluetoothA2dp$Stub;->TRANSACTION_setAvrcpAbsoluteVolume:I
-Landroid/bluetooth/IBluetoothA2dp$Stub;->TRANSACTION_setCodecConfigPreference:I
-Landroid/bluetooth/IBluetoothA2dp$Stub;->TRANSACTION_setOptionalCodecsEnabled:I
-Landroid/bluetooth/IBluetoothA2dp$Stub;->TRANSACTION_setPriority:I
-Landroid/bluetooth/IBluetoothA2dp$Stub;->TRANSACTION_supportsOptionalCodecs:I
-Landroid/bluetooth/IBluetoothA2dp;->disableOptionalCodecs(Landroid/bluetooth/BluetoothDevice;)V
-Landroid/bluetooth/IBluetoothA2dp;->enableOptionalCodecs(Landroid/bluetooth/BluetoothDevice;)V
-Landroid/bluetooth/IBluetoothA2dp;->getActiveDevice()Landroid/bluetooth/BluetoothDevice;
-Landroid/bluetooth/IBluetoothA2dp;->getCodecStatus(Landroid/bluetooth/BluetoothDevice;)Landroid/bluetooth/BluetoothCodecStatus;
-Landroid/bluetooth/IBluetoothA2dp;->getOptionalCodecsEnabled(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothA2dp;->isA2dpPlaying(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothA2dp;->isAvrcpAbsoluteVolumeSupported()Z
-Landroid/bluetooth/IBluetoothA2dp;->setActiveDevice(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothA2dp;->setAvrcpAbsoluteVolume(I)V
-Landroid/bluetooth/IBluetoothA2dp;->setCodecConfigPreference(Landroid/bluetooth/BluetoothDevice;Landroid/bluetooth/BluetoothCodecConfig;)V
-Landroid/bluetooth/IBluetoothA2dp;->setOptionalCodecsEnabled(Landroid/bluetooth/BluetoothDevice;I)V
-Landroid/bluetooth/IBluetoothA2dp;->setPriority(Landroid/bluetooth/BluetoothDevice;I)Z
-Landroid/bluetooth/IBluetoothA2dp;->supportsOptionalCodecs(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothA2dpSink$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/bluetooth/IBluetoothA2dpSink$Stub$Proxy;->connect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothA2dpSink$Stub$Proxy;->disconnect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothA2dpSink$Stub$Proxy;->getAudioConfig(Landroid/bluetooth/BluetoothDevice;)Landroid/bluetooth/BluetoothAudioConfig;
-Landroid/bluetooth/IBluetoothA2dpSink$Stub$Proxy;->getConnectedDevices()Ljava/util/List;
-Landroid/bluetooth/IBluetoothA2dpSink$Stub$Proxy;->getConnectionState(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothA2dpSink$Stub$Proxy;->getDevicesMatchingConnectionStates([I)Ljava/util/List;
-Landroid/bluetooth/IBluetoothA2dpSink$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
-Landroid/bluetooth/IBluetoothA2dpSink$Stub$Proxy;->getPriority(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothA2dpSink$Stub$Proxy;->isA2dpPlaying(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothA2dpSink$Stub$Proxy;->mRemote:Landroid/os/IBinder;
-Landroid/bluetooth/IBluetoothA2dpSink$Stub$Proxy;->setPriority(Landroid/bluetooth/BluetoothDevice;I)Z
-Landroid/bluetooth/IBluetoothA2dpSink$Stub;-><init>()V
-Landroid/bluetooth/IBluetoothA2dpSink$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetoothA2dpSink;
-Landroid/bluetooth/IBluetoothA2dpSink$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/bluetooth/IBluetoothA2dpSink$Stub;->TRANSACTION_connect:I
-Landroid/bluetooth/IBluetoothA2dpSink$Stub;->TRANSACTION_disconnect:I
-Landroid/bluetooth/IBluetoothA2dpSink$Stub;->TRANSACTION_getAudioConfig:I
-Landroid/bluetooth/IBluetoothA2dpSink$Stub;->TRANSACTION_getConnectedDevices:I
-Landroid/bluetooth/IBluetoothA2dpSink$Stub;->TRANSACTION_getConnectionState:I
-Landroid/bluetooth/IBluetoothA2dpSink$Stub;->TRANSACTION_getDevicesMatchingConnectionStates:I
-Landroid/bluetooth/IBluetoothA2dpSink$Stub;->TRANSACTION_getPriority:I
-Landroid/bluetooth/IBluetoothA2dpSink$Stub;->TRANSACTION_isA2dpPlaying:I
-Landroid/bluetooth/IBluetoothA2dpSink$Stub;->TRANSACTION_setPriority:I
-Landroid/bluetooth/IBluetoothA2dpSink;->connect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothA2dpSink;->disconnect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothA2dpSink;->getAudioConfig(Landroid/bluetooth/BluetoothDevice;)Landroid/bluetooth/BluetoothAudioConfig;
-Landroid/bluetooth/IBluetoothA2dpSink;->getConnectedDevices()Ljava/util/List;
-Landroid/bluetooth/IBluetoothA2dpSink;->getConnectionState(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothA2dpSink;->getDevicesMatchingConnectionStates([I)Ljava/util/List;
-Landroid/bluetooth/IBluetoothA2dpSink;->getPriority(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothA2dpSink;->isA2dpPlaying(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothA2dpSink;->setPriority(Landroid/bluetooth/BluetoothDevice;I)Z
-Landroid/bluetooth/IBluetoothAvrcpController$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/bluetooth/IBluetoothAvrcpController$Stub$Proxy;->getConnectedDevices()Ljava/util/List;
-Landroid/bluetooth/IBluetoothAvrcpController$Stub$Proxy;->getConnectionState(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothAvrcpController$Stub$Proxy;->getDevicesMatchingConnectionStates([I)Ljava/util/List;
-Landroid/bluetooth/IBluetoothAvrcpController$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
-Landroid/bluetooth/IBluetoothAvrcpController$Stub$Proxy;->getPlayerSettings(Landroid/bluetooth/BluetoothDevice;)Landroid/bluetooth/BluetoothAvrcpPlayerSettings;
-Landroid/bluetooth/IBluetoothAvrcpController$Stub$Proxy;->mRemote:Landroid/os/IBinder;
-Landroid/bluetooth/IBluetoothAvrcpController$Stub$Proxy;->sendGroupNavigationCmd(Landroid/bluetooth/BluetoothDevice;II)V
-Landroid/bluetooth/IBluetoothAvrcpController$Stub$Proxy;->setPlayerApplicationSetting(Landroid/bluetooth/BluetoothAvrcpPlayerSettings;)Z
-Landroid/bluetooth/IBluetoothAvrcpController$Stub;-><init>()V
-Landroid/bluetooth/IBluetoothAvrcpController$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetoothAvrcpController;
-Landroid/bluetooth/IBluetoothAvrcpController$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/bluetooth/IBluetoothAvrcpController$Stub;->TRANSACTION_getConnectedDevices:I
-Landroid/bluetooth/IBluetoothAvrcpController$Stub;->TRANSACTION_getConnectionState:I
-Landroid/bluetooth/IBluetoothAvrcpController$Stub;->TRANSACTION_getDevicesMatchingConnectionStates:I
-Landroid/bluetooth/IBluetoothAvrcpController$Stub;->TRANSACTION_getPlayerSettings:I
-Landroid/bluetooth/IBluetoothAvrcpController$Stub;->TRANSACTION_sendGroupNavigationCmd:I
-Landroid/bluetooth/IBluetoothAvrcpController$Stub;->TRANSACTION_setPlayerApplicationSetting:I
-Landroid/bluetooth/IBluetoothAvrcpController;->getConnectedDevices()Ljava/util/List;
-Landroid/bluetooth/IBluetoothAvrcpController;->getConnectionState(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothAvrcpController;->getDevicesMatchingConnectionStates([I)Ljava/util/List;
-Landroid/bluetooth/IBluetoothAvrcpController;->getPlayerSettings(Landroid/bluetooth/BluetoothDevice;)Landroid/bluetooth/BluetoothAvrcpPlayerSettings;
-Landroid/bluetooth/IBluetoothAvrcpController;->sendGroupNavigationCmd(Landroid/bluetooth/BluetoothDevice;II)V
-Landroid/bluetooth/IBluetoothAvrcpController;->setPlayerApplicationSetting(Landroid/bluetooth/BluetoothAvrcpPlayerSettings;)Z
-Landroid/bluetooth/IBluetoothAvrcpTarget$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/bluetooth/IBluetoothAvrcpTarget$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
-Landroid/bluetooth/IBluetoothAvrcpTarget$Stub$Proxy;->mRemote:Landroid/os/IBinder;
-Landroid/bluetooth/IBluetoothAvrcpTarget$Stub$Proxy;->sendVolumeChanged(I)V
-Landroid/bluetooth/IBluetoothAvrcpTarget$Stub;-><init>()V
-Landroid/bluetooth/IBluetoothAvrcpTarget$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetoothAvrcpTarget;
-Landroid/bluetooth/IBluetoothAvrcpTarget$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/bluetooth/IBluetoothAvrcpTarget$Stub;->TRANSACTION_sendVolumeChanged:I
-Landroid/bluetooth/IBluetoothAvrcpTarget;->sendVolumeChanged(I)V
-Landroid/bluetooth/IBluetoothCallback$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/bluetooth/IBluetoothCallback$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
-Landroid/bluetooth/IBluetoothCallback$Stub$Proxy;->mRemote:Landroid/os/IBinder;
-Landroid/bluetooth/IBluetoothCallback$Stub$Proxy;->onBluetoothStateChange(II)V
-Landroid/bluetooth/IBluetoothCallback$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetoothCallback;
-Landroid/bluetooth/IBluetoothCallback$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/bluetooth/IBluetoothCallback$Stub;->TRANSACTION_onBluetoothStateChange:I
-Landroid/bluetooth/IBluetoothCallback;->onBluetoothStateChange(II)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->addService(ILandroid/bluetooth/BluetoothGattService;)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->beginReliableWrite(ILjava/lang/String;)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->clearServices(I)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->clientConnect(ILjava/lang/String;ZIZI)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->clientDisconnect(ILjava/lang/String;)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->clientReadPhy(ILjava/lang/String;)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->clientSetPreferredPhy(ILjava/lang/String;III)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->configureMTU(ILjava/lang/String;I)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->connectionParameterUpdate(ILjava/lang/String;I)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->disconnectAll()V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->discoverServiceByUuid(ILjava/lang/String;Landroid/os/ParcelUuid;)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->discoverServices(ILjava/lang/String;)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->enableAdvertisingSet(IZII)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->endReliableWrite(ILjava/lang/String;Z)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->flushPendingBatchResults(I)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->getDevicesMatchingConnectionStates([I)Ljava/util/List;
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->getOwnAddress(I)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->leConnectionUpdate(ILjava/lang/String;IIIIII)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->mRemote:Landroid/os/IBinder;
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->numHwTrackFiltersAvailable()I
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->readCharacteristic(ILjava/lang/String;II)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->readDescriptor(ILjava/lang/String;II)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->readRemoteRssi(ILjava/lang/String;)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->readUsingCharacteristicUuid(ILjava/lang/String;Landroid/os/ParcelUuid;III)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->refreshDevice(ILjava/lang/String;)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->registerClient(Landroid/os/ParcelUuid;Landroid/bluetooth/IBluetoothGattCallback;)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->registerForNotification(ILjava/lang/String;IZ)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->registerScanner(Landroid/bluetooth/le/IScannerCallback;Landroid/os/WorkSource;)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->registerServer(Landroid/os/ParcelUuid;Landroid/bluetooth/IBluetoothGattServerCallback;)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->registerSync(Landroid/bluetooth/le/ScanResult;IILandroid/bluetooth/le/IPeriodicAdvertisingCallback;)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->removeService(II)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->sendNotification(ILjava/lang/String;IZ[B)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->sendResponse(ILjava/lang/String;III[B)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->serverConnect(ILjava/lang/String;ZI)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->serverDisconnect(ILjava/lang/String;)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->serverReadPhy(ILjava/lang/String;)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->serverSetPreferredPhy(ILjava/lang/String;III)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->setAdvertisingData(ILandroid/bluetooth/le/AdvertiseData;)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->setAdvertisingParameters(ILandroid/bluetooth/le/AdvertisingSetParameters;)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->setPeriodicAdvertisingData(ILandroid/bluetooth/le/AdvertiseData;)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->setPeriodicAdvertisingEnable(IZ)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->setPeriodicAdvertisingParameters(ILandroid/bluetooth/le/PeriodicAdvertisingParameters;)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->setScanResponseData(ILandroid/bluetooth/le/AdvertiseData;)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->startAdvertisingSet(Landroid/bluetooth/le/AdvertisingSetParameters;Landroid/bluetooth/le/AdvertiseData;Landroid/bluetooth/le/AdvertiseData;Landroid/bluetooth/le/PeriodicAdvertisingParameters;Landroid/bluetooth/le/AdvertiseData;IILandroid/bluetooth/le/IAdvertisingSetCallback;)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->startScan(ILandroid/bluetooth/le/ScanSettings;Ljava/util/List;Ljava/util/List;Ljava/lang/String;)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->startScanForIntent(Landroid/app/PendingIntent;Landroid/bluetooth/le/ScanSettings;Ljava/util/List;Ljava/lang/String;)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->stopAdvertisingSet(Landroid/bluetooth/le/IAdvertisingSetCallback;)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->stopScan(I)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->stopScanForIntent(Landroid/app/PendingIntent;Ljava/lang/String;)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->unregAll()V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->unregisterClient(I)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->unregisterScanner(I)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->unregisterServer(I)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->unregisterSync(Landroid/bluetooth/le/IPeriodicAdvertisingCallback;)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->writeCharacteristic(ILjava/lang/String;III[B)V
-Landroid/bluetooth/IBluetoothGatt$Stub$Proxy;->writeDescriptor(ILjava/lang/String;II[B)V
-Landroid/bluetooth/IBluetoothGatt$Stub;-><init>()V
-Landroid/bluetooth/IBluetoothGatt$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetoothGatt;
-Landroid/bluetooth/IBluetoothGatt$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_addService:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_beginReliableWrite:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_clearServices:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_clientConnect:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_clientDisconnect:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_clientReadPhy:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_clientSetPreferredPhy:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_configureMTU:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_connectionParameterUpdate:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_disconnectAll:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_discoverServiceByUuid:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_discoverServices:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_enableAdvertisingSet:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_endReliableWrite:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_flushPendingBatchResults:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_getDevicesMatchingConnectionStates:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_getOwnAddress:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_leConnectionUpdate:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_numHwTrackFiltersAvailable:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_readCharacteristic:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_readDescriptor:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_readRemoteRssi:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_readUsingCharacteristicUuid:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_refreshDevice:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_registerClient:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_registerForNotification:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_registerScanner:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_registerServer:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_registerSync:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_removeService:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_sendNotification:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_sendResponse:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_serverConnect:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_serverDisconnect:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_serverReadPhy:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_serverSetPreferredPhy:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_setAdvertisingData:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_setAdvertisingParameters:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_setPeriodicAdvertisingData:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_setPeriodicAdvertisingEnable:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_setPeriodicAdvertisingParameters:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_setScanResponseData:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_startAdvertisingSet:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_startScan:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_startScanForIntent:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_stopAdvertisingSet:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_stopScan:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_stopScanForIntent:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_unregAll:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_unregisterClient:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_unregisterScanner:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_unregisterServer:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_unregisterSync:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_writeCharacteristic:I
-Landroid/bluetooth/IBluetoothGatt$Stub;->TRANSACTION_writeDescriptor:I
-Landroid/bluetooth/IBluetoothGatt;->addService(ILandroid/bluetooth/BluetoothGattService;)V
-Landroid/bluetooth/IBluetoothGatt;->beginReliableWrite(ILjava/lang/String;)V
-Landroid/bluetooth/IBluetoothGatt;->clearServices(I)V
-Landroid/bluetooth/IBluetoothGatt;->clientConnect(ILjava/lang/String;ZIZI)V
-Landroid/bluetooth/IBluetoothGatt;->clientDisconnect(ILjava/lang/String;)V
-Landroid/bluetooth/IBluetoothGatt;->clientReadPhy(ILjava/lang/String;)V
-Landroid/bluetooth/IBluetoothGatt;->clientSetPreferredPhy(ILjava/lang/String;III)V
-Landroid/bluetooth/IBluetoothGatt;->configureMTU(ILjava/lang/String;I)V
-Landroid/bluetooth/IBluetoothGatt;->connectionParameterUpdate(ILjava/lang/String;I)V
-Landroid/bluetooth/IBluetoothGatt;->disconnectAll()V
-Landroid/bluetooth/IBluetoothGatt;->discoverServiceByUuid(ILjava/lang/String;Landroid/os/ParcelUuid;)V
-Landroid/bluetooth/IBluetoothGatt;->discoverServices(ILjava/lang/String;)V
-Landroid/bluetooth/IBluetoothGatt;->enableAdvertisingSet(IZII)V
-Landroid/bluetooth/IBluetoothGatt;->endReliableWrite(ILjava/lang/String;Z)V
-Landroid/bluetooth/IBluetoothGatt;->flushPendingBatchResults(I)V
-Landroid/bluetooth/IBluetoothGatt;->getDevicesMatchingConnectionStates([I)Ljava/util/List;
-Landroid/bluetooth/IBluetoothGatt;->getOwnAddress(I)V
-Landroid/bluetooth/IBluetoothGatt;->leConnectionUpdate(ILjava/lang/String;IIIIII)V
-Landroid/bluetooth/IBluetoothGatt;->numHwTrackFiltersAvailable()I
-Landroid/bluetooth/IBluetoothGatt;->readCharacteristic(ILjava/lang/String;II)V
-Landroid/bluetooth/IBluetoothGatt;->readDescriptor(ILjava/lang/String;II)V
-Landroid/bluetooth/IBluetoothGatt;->readRemoteRssi(ILjava/lang/String;)V
-Landroid/bluetooth/IBluetoothGatt;->readUsingCharacteristicUuid(ILjava/lang/String;Landroid/os/ParcelUuid;III)V
-Landroid/bluetooth/IBluetoothGatt;->refreshDevice(ILjava/lang/String;)V
-Landroid/bluetooth/IBluetoothGatt;->registerForNotification(ILjava/lang/String;IZ)V
-Landroid/bluetooth/IBluetoothGatt;->registerScanner(Landroid/bluetooth/le/IScannerCallback;Landroid/os/WorkSource;)V
-Landroid/bluetooth/IBluetoothGatt;->registerServer(Landroid/os/ParcelUuid;Landroid/bluetooth/IBluetoothGattServerCallback;)V
-Landroid/bluetooth/IBluetoothGatt;->registerSync(Landroid/bluetooth/le/ScanResult;IILandroid/bluetooth/le/IPeriodicAdvertisingCallback;)V
-Landroid/bluetooth/IBluetoothGatt;->removeService(II)V
-Landroid/bluetooth/IBluetoothGatt;->sendNotification(ILjava/lang/String;IZ[B)V
-Landroid/bluetooth/IBluetoothGatt;->sendResponse(ILjava/lang/String;III[B)V
-Landroid/bluetooth/IBluetoothGatt;->serverConnect(ILjava/lang/String;ZI)V
-Landroid/bluetooth/IBluetoothGatt;->serverDisconnect(ILjava/lang/String;)V
-Landroid/bluetooth/IBluetoothGatt;->serverReadPhy(ILjava/lang/String;)V
-Landroid/bluetooth/IBluetoothGatt;->serverSetPreferredPhy(ILjava/lang/String;III)V
-Landroid/bluetooth/IBluetoothGatt;->setAdvertisingData(ILandroid/bluetooth/le/AdvertiseData;)V
-Landroid/bluetooth/IBluetoothGatt;->setAdvertisingParameters(ILandroid/bluetooth/le/AdvertisingSetParameters;)V
-Landroid/bluetooth/IBluetoothGatt;->setPeriodicAdvertisingData(ILandroid/bluetooth/le/AdvertiseData;)V
-Landroid/bluetooth/IBluetoothGatt;->setPeriodicAdvertisingEnable(IZ)V
-Landroid/bluetooth/IBluetoothGatt;->setPeriodicAdvertisingParameters(ILandroid/bluetooth/le/PeriodicAdvertisingParameters;)V
-Landroid/bluetooth/IBluetoothGatt;->setScanResponseData(ILandroid/bluetooth/le/AdvertiseData;)V
-Landroid/bluetooth/IBluetoothGatt;->startAdvertisingSet(Landroid/bluetooth/le/AdvertisingSetParameters;Landroid/bluetooth/le/AdvertiseData;Landroid/bluetooth/le/AdvertiseData;Landroid/bluetooth/le/PeriodicAdvertisingParameters;Landroid/bluetooth/le/AdvertiseData;IILandroid/bluetooth/le/IAdvertisingSetCallback;)V
-Landroid/bluetooth/IBluetoothGatt;->startScan(ILandroid/bluetooth/le/ScanSettings;Ljava/util/List;Ljava/util/List;Ljava/lang/String;)V
-Landroid/bluetooth/IBluetoothGatt;->startScanForIntent(Landroid/app/PendingIntent;Landroid/bluetooth/le/ScanSettings;Ljava/util/List;Ljava/lang/String;)V
-Landroid/bluetooth/IBluetoothGatt;->stopAdvertisingSet(Landroid/bluetooth/le/IAdvertisingSetCallback;)V
-Landroid/bluetooth/IBluetoothGatt;->stopScan(I)V
-Landroid/bluetooth/IBluetoothGatt;->stopScanForIntent(Landroid/app/PendingIntent;Ljava/lang/String;)V
-Landroid/bluetooth/IBluetoothGatt;->unregAll()V
-Landroid/bluetooth/IBluetoothGatt;->unregisterScanner(I)V
-Landroid/bluetooth/IBluetoothGatt;->unregisterServer(I)V
-Landroid/bluetooth/IBluetoothGatt;->unregisterSync(Landroid/bluetooth/le/IPeriodicAdvertisingCallback;)V
-Landroid/bluetooth/IBluetoothGatt;->writeCharacteristic(ILjava/lang/String;III[B)V
-Landroid/bluetooth/IBluetoothGatt;->writeDescriptor(ILjava/lang/String;II[B)V
-Landroid/bluetooth/IBluetoothGattCallback$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/bluetooth/IBluetoothGattCallback$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
-Landroid/bluetooth/IBluetoothGattCallback$Stub$Proxy;->mRemote:Landroid/os/IBinder;
-Landroid/bluetooth/IBluetoothGattCallback$Stub$Proxy;->onCharacteristicRead(Ljava/lang/String;II[B)V
-Landroid/bluetooth/IBluetoothGattCallback$Stub$Proxy;->onCharacteristicWrite(Ljava/lang/String;II)V
-Landroid/bluetooth/IBluetoothGattCallback$Stub$Proxy;->onClientConnectionState(IIZLjava/lang/String;)V
-Landroid/bluetooth/IBluetoothGattCallback$Stub$Proxy;->onClientRegistered(II)V
-Landroid/bluetooth/IBluetoothGattCallback$Stub$Proxy;->onConfigureMTU(Ljava/lang/String;II)V
-Landroid/bluetooth/IBluetoothGattCallback$Stub$Proxy;->onConnectionUpdated(Ljava/lang/String;IIII)V
-Landroid/bluetooth/IBluetoothGattCallback$Stub$Proxy;->onDescriptorRead(Ljava/lang/String;II[B)V
-Landroid/bluetooth/IBluetoothGattCallback$Stub$Proxy;->onDescriptorWrite(Ljava/lang/String;II)V
-Landroid/bluetooth/IBluetoothGattCallback$Stub$Proxy;->onExecuteWrite(Ljava/lang/String;I)V
-Landroid/bluetooth/IBluetoothGattCallback$Stub$Proxy;->onNotify(Ljava/lang/String;I[B)V
-Landroid/bluetooth/IBluetoothGattCallback$Stub$Proxy;->onPhyRead(Ljava/lang/String;III)V
-Landroid/bluetooth/IBluetoothGattCallback$Stub$Proxy;->onPhyUpdate(Ljava/lang/String;III)V
-Landroid/bluetooth/IBluetoothGattCallback$Stub$Proxy;->onReadRemoteRssi(Ljava/lang/String;II)V
-Landroid/bluetooth/IBluetoothGattCallback$Stub$Proxy;->onSearchComplete(Ljava/lang/String;Ljava/util/List;I)V
-Landroid/bluetooth/IBluetoothGattCallback$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/bluetooth/IBluetoothGattCallback$Stub;->TRANSACTION_onCharacteristicRead:I
-Landroid/bluetooth/IBluetoothGattCallback$Stub;->TRANSACTION_onCharacteristicWrite:I
-Landroid/bluetooth/IBluetoothGattCallback$Stub;->TRANSACTION_onClientConnectionState:I
-Landroid/bluetooth/IBluetoothGattCallback$Stub;->TRANSACTION_onClientRegistered:I
-Landroid/bluetooth/IBluetoothGattCallback$Stub;->TRANSACTION_onConfigureMTU:I
-Landroid/bluetooth/IBluetoothGattCallback$Stub;->TRANSACTION_onConnectionUpdated:I
-Landroid/bluetooth/IBluetoothGattCallback$Stub;->TRANSACTION_onDescriptorRead:I
-Landroid/bluetooth/IBluetoothGattCallback$Stub;->TRANSACTION_onDescriptorWrite:I
-Landroid/bluetooth/IBluetoothGattCallback$Stub;->TRANSACTION_onExecuteWrite:I
-Landroid/bluetooth/IBluetoothGattCallback$Stub;->TRANSACTION_onNotify:I
-Landroid/bluetooth/IBluetoothGattCallback$Stub;->TRANSACTION_onPhyRead:I
-Landroid/bluetooth/IBluetoothGattCallback$Stub;->TRANSACTION_onPhyUpdate:I
-Landroid/bluetooth/IBluetoothGattCallback$Stub;->TRANSACTION_onReadRemoteRssi:I
-Landroid/bluetooth/IBluetoothGattCallback$Stub;->TRANSACTION_onSearchComplete:I
-Landroid/bluetooth/IBluetoothGattCallback;->onCharacteristicRead(Ljava/lang/String;II[B)V
-Landroid/bluetooth/IBluetoothGattCallback;->onCharacteristicWrite(Ljava/lang/String;II)V
-Landroid/bluetooth/IBluetoothGattCallback;->onClientConnectionState(IIZLjava/lang/String;)V
-Landroid/bluetooth/IBluetoothGattCallback;->onClientRegistered(II)V
-Landroid/bluetooth/IBluetoothGattCallback;->onConfigureMTU(Ljava/lang/String;II)V
-Landroid/bluetooth/IBluetoothGattCallback;->onConnectionUpdated(Ljava/lang/String;IIII)V
-Landroid/bluetooth/IBluetoothGattCallback;->onDescriptorRead(Ljava/lang/String;II[B)V
-Landroid/bluetooth/IBluetoothGattCallback;->onDescriptorWrite(Ljava/lang/String;II)V
-Landroid/bluetooth/IBluetoothGattCallback;->onExecuteWrite(Ljava/lang/String;I)V
-Landroid/bluetooth/IBluetoothGattCallback;->onNotify(Ljava/lang/String;I[B)V
-Landroid/bluetooth/IBluetoothGattCallback;->onPhyRead(Ljava/lang/String;III)V
-Landroid/bluetooth/IBluetoothGattCallback;->onPhyUpdate(Ljava/lang/String;III)V
-Landroid/bluetooth/IBluetoothGattCallback;->onReadRemoteRssi(Ljava/lang/String;II)V
-Landroid/bluetooth/IBluetoothGattCallback;->onSearchComplete(Ljava/lang/String;Ljava/util/List;I)V
-Landroid/bluetooth/IBluetoothGattServerCallback$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/bluetooth/IBluetoothGattServerCallback$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
-Landroid/bluetooth/IBluetoothGattServerCallback$Stub$Proxy;->mRemote:Landroid/os/IBinder;
-Landroid/bluetooth/IBluetoothGattServerCallback$Stub$Proxy;->onCharacteristicReadRequest(Ljava/lang/String;IIZI)V
-Landroid/bluetooth/IBluetoothGattServerCallback$Stub$Proxy;->onCharacteristicWriteRequest(Ljava/lang/String;IIIZZI[B)V
-Landroid/bluetooth/IBluetoothGattServerCallback$Stub$Proxy;->onConnectionUpdated(Ljava/lang/String;IIII)V
-Landroid/bluetooth/IBluetoothGattServerCallback$Stub$Proxy;->onDescriptorReadRequest(Ljava/lang/String;IIZI)V
-Landroid/bluetooth/IBluetoothGattServerCallback$Stub$Proxy;->onDescriptorWriteRequest(Ljava/lang/String;IIIZZI[B)V
-Landroid/bluetooth/IBluetoothGattServerCallback$Stub$Proxy;->onExecuteWrite(Ljava/lang/String;IZ)V
-Landroid/bluetooth/IBluetoothGattServerCallback$Stub$Proxy;->onMtuChanged(Ljava/lang/String;I)V
-Landroid/bluetooth/IBluetoothGattServerCallback$Stub$Proxy;->onNotificationSent(Ljava/lang/String;I)V
-Landroid/bluetooth/IBluetoothGattServerCallback$Stub$Proxy;->onPhyRead(Ljava/lang/String;III)V
-Landroid/bluetooth/IBluetoothGattServerCallback$Stub$Proxy;->onPhyUpdate(Ljava/lang/String;III)V
-Landroid/bluetooth/IBluetoothGattServerCallback$Stub$Proxy;->onServerConnectionState(IIZLjava/lang/String;)V
-Landroid/bluetooth/IBluetoothGattServerCallback$Stub$Proxy;->onServerRegistered(II)V
-Landroid/bluetooth/IBluetoothGattServerCallback$Stub$Proxy;->onServiceAdded(ILandroid/bluetooth/BluetoothGattService;)V
-Landroid/bluetooth/IBluetoothGattServerCallback$Stub;-><init>()V
-Landroid/bluetooth/IBluetoothGattServerCallback$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetoothGattServerCallback;
-Landroid/bluetooth/IBluetoothGattServerCallback$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/bluetooth/IBluetoothGattServerCallback$Stub;->TRANSACTION_onCharacteristicReadRequest:I
-Landroid/bluetooth/IBluetoothGattServerCallback$Stub;->TRANSACTION_onCharacteristicWriteRequest:I
-Landroid/bluetooth/IBluetoothGattServerCallback$Stub;->TRANSACTION_onConnectionUpdated:I
-Landroid/bluetooth/IBluetoothGattServerCallback$Stub;->TRANSACTION_onDescriptorReadRequest:I
-Landroid/bluetooth/IBluetoothGattServerCallback$Stub;->TRANSACTION_onDescriptorWriteRequest:I
-Landroid/bluetooth/IBluetoothGattServerCallback$Stub;->TRANSACTION_onExecuteWrite:I
-Landroid/bluetooth/IBluetoothGattServerCallback$Stub;->TRANSACTION_onMtuChanged:I
-Landroid/bluetooth/IBluetoothGattServerCallback$Stub;->TRANSACTION_onNotificationSent:I
-Landroid/bluetooth/IBluetoothGattServerCallback$Stub;->TRANSACTION_onPhyRead:I
-Landroid/bluetooth/IBluetoothGattServerCallback$Stub;->TRANSACTION_onPhyUpdate:I
-Landroid/bluetooth/IBluetoothGattServerCallback$Stub;->TRANSACTION_onServerConnectionState:I
-Landroid/bluetooth/IBluetoothGattServerCallback$Stub;->TRANSACTION_onServerRegistered:I
-Landroid/bluetooth/IBluetoothGattServerCallback$Stub;->TRANSACTION_onServiceAdded:I
-Landroid/bluetooth/IBluetoothGattServerCallback;->onCharacteristicReadRequest(Ljava/lang/String;IIZI)V
-Landroid/bluetooth/IBluetoothGattServerCallback;->onCharacteristicWriteRequest(Ljava/lang/String;IIIZZI[B)V
-Landroid/bluetooth/IBluetoothGattServerCallback;->onConnectionUpdated(Ljava/lang/String;IIII)V
-Landroid/bluetooth/IBluetoothGattServerCallback;->onDescriptorReadRequest(Ljava/lang/String;IIZI)V
-Landroid/bluetooth/IBluetoothGattServerCallback;->onDescriptorWriteRequest(Ljava/lang/String;IIIZZI[B)V
-Landroid/bluetooth/IBluetoothGattServerCallback;->onExecuteWrite(Ljava/lang/String;IZ)V
-Landroid/bluetooth/IBluetoothGattServerCallback;->onMtuChanged(Ljava/lang/String;I)V
-Landroid/bluetooth/IBluetoothGattServerCallback;->onNotificationSent(Ljava/lang/String;I)V
-Landroid/bluetooth/IBluetoothGattServerCallback;->onPhyRead(Ljava/lang/String;III)V
-Landroid/bluetooth/IBluetoothGattServerCallback;->onPhyUpdate(Ljava/lang/String;III)V
-Landroid/bluetooth/IBluetoothGattServerCallback;->onServerConnectionState(IIZLjava/lang/String;)V
-Landroid/bluetooth/IBluetoothGattServerCallback;->onServerRegistered(II)V
-Landroid/bluetooth/IBluetoothGattServerCallback;->onServiceAdded(ILandroid/bluetooth/BluetoothGattService;)V
-Landroid/bluetooth/IBluetoothHeadset$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/bluetooth/IBluetoothHeadset$Stub$Proxy;->clccResponse(IIIIZLjava/lang/String;I)V
-Landroid/bluetooth/IBluetoothHeadset$Stub$Proxy;->connect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHeadset$Stub$Proxy;->connectAudio()Z
-Landroid/bluetooth/IBluetoothHeadset$Stub$Proxy;->disconnect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHeadset$Stub$Proxy;->disconnectAudio()Z
-Landroid/bluetooth/IBluetoothHeadset$Stub$Proxy;->getActiveDevice()Landroid/bluetooth/BluetoothDevice;
-Landroid/bluetooth/IBluetoothHeadset$Stub$Proxy;->getAudioRouteAllowed()Z
-Landroid/bluetooth/IBluetoothHeadset$Stub$Proxy;->getAudioState(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothHeadset$Stub$Proxy;->getConnectedDevices()Ljava/util/List;
-Landroid/bluetooth/IBluetoothHeadset$Stub$Proxy;->getConnectionState(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothHeadset$Stub$Proxy;->getDevicesMatchingConnectionStates([I)Ljava/util/List;
-Landroid/bluetooth/IBluetoothHeadset$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
-Landroid/bluetooth/IBluetoothHeadset$Stub$Proxy;->getPriority(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothHeadset$Stub$Proxy;->isAudioConnected(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHeadset$Stub$Proxy;->isAudioOn()Z
-Landroid/bluetooth/IBluetoothHeadset$Stub$Proxy;->isInbandRingingEnabled()Z
-Landroid/bluetooth/IBluetoothHeadset$Stub$Proxy;->mRemote:Landroid/os/IBinder;
-Landroid/bluetooth/IBluetoothHeadset$Stub$Proxy;->phoneStateChanged(IIILjava/lang/String;I)V
-Landroid/bluetooth/IBluetoothHeadset$Stub$Proxy;->sendVendorSpecificResultCode(Landroid/bluetooth/BluetoothDevice;Ljava/lang/String;Ljava/lang/String;)Z
-Landroid/bluetooth/IBluetoothHeadset$Stub$Proxy;->setActiveDevice(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHeadset$Stub$Proxy;->setAudioRouteAllowed(Z)V
-Landroid/bluetooth/IBluetoothHeadset$Stub$Proxy;->setForceScoAudio(Z)V
-Landroid/bluetooth/IBluetoothHeadset$Stub$Proxy;->setPriority(Landroid/bluetooth/BluetoothDevice;I)Z
-Landroid/bluetooth/IBluetoothHeadset$Stub$Proxy;->startScoUsingVirtualVoiceCall()Z
-Landroid/bluetooth/IBluetoothHeadset$Stub$Proxy;->startVoiceRecognition(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHeadset$Stub$Proxy;->stopScoUsingVirtualVoiceCall()Z
-Landroid/bluetooth/IBluetoothHeadset$Stub$Proxy;->stopVoiceRecognition(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHeadset$Stub;-><init>()V
-Landroid/bluetooth/IBluetoothHeadset$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/bluetooth/IBluetoothHeadset$Stub;->TRANSACTION_clccResponse:I
-Landroid/bluetooth/IBluetoothHeadset$Stub;->TRANSACTION_connect:I
-Landroid/bluetooth/IBluetoothHeadset$Stub;->TRANSACTION_connectAudio:I
-Landroid/bluetooth/IBluetoothHeadset$Stub;->TRANSACTION_disconnect:I
-Landroid/bluetooth/IBluetoothHeadset$Stub;->TRANSACTION_disconnectAudio:I
-Landroid/bluetooth/IBluetoothHeadset$Stub;->TRANSACTION_getActiveDevice:I
-Landroid/bluetooth/IBluetoothHeadset$Stub;->TRANSACTION_getAudioRouteAllowed:I
-Landroid/bluetooth/IBluetoothHeadset$Stub;->TRANSACTION_getAudioState:I
-Landroid/bluetooth/IBluetoothHeadset$Stub;->TRANSACTION_getConnectedDevices:I
-Landroid/bluetooth/IBluetoothHeadset$Stub;->TRANSACTION_getConnectionState:I
-Landroid/bluetooth/IBluetoothHeadset$Stub;->TRANSACTION_getDevicesMatchingConnectionStates:I
-Landroid/bluetooth/IBluetoothHeadset$Stub;->TRANSACTION_getPriority:I
-Landroid/bluetooth/IBluetoothHeadset$Stub;->TRANSACTION_isAudioConnected:I
-Landroid/bluetooth/IBluetoothHeadset$Stub;->TRANSACTION_isAudioOn:I
-Landroid/bluetooth/IBluetoothHeadset$Stub;->TRANSACTION_isInbandRingingEnabled:I
-Landroid/bluetooth/IBluetoothHeadset$Stub;->TRANSACTION_phoneStateChanged:I
-Landroid/bluetooth/IBluetoothHeadset$Stub;->TRANSACTION_sendVendorSpecificResultCode:I
-Landroid/bluetooth/IBluetoothHeadset$Stub;->TRANSACTION_setActiveDevice:I
-Landroid/bluetooth/IBluetoothHeadset$Stub;->TRANSACTION_setAudioRouteAllowed:I
-Landroid/bluetooth/IBluetoothHeadset$Stub;->TRANSACTION_setForceScoAudio:I
-Landroid/bluetooth/IBluetoothHeadset$Stub;->TRANSACTION_setPriority:I
-Landroid/bluetooth/IBluetoothHeadset$Stub;->TRANSACTION_startScoUsingVirtualVoiceCall:I
-Landroid/bluetooth/IBluetoothHeadset$Stub;->TRANSACTION_startVoiceRecognition:I
-Landroid/bluetooth/IBluetoothHeadset$Stub;->TRANSACTION_stopScoUsingVirtualVoiceCall:I
-Landroid/bluetooth/IBluetoothHeadset$Stub;->TRANSACTION_stopVoiceRecognition:I
-Landroid/bluetooth/IBluetoothHeadset;->clccResponse(IIIIZLjava/lang/String;I)V
-Landroid/bluetooth/IBluetoothHeadset;->connectAudio()Z
-Landroid/bluetooth/IBluetoothHeadset;->disconnectAudio()Z
-Landroid/bluetooth/IBluetoothHeadset;->getActiveDevice()Landroid/bluetooth/BluetoothDevice;
-Landroid/bluetooth/IBluetoothHeadset;->getAudioRouteAllowed()Z
-Landroid/bluetooth/IBluetoothHeadset;->getAudioState(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothHeadset;->getDevicesMatchingConnectionStates([I)Ljava/util/List;
-Landroid/bluetooth/IBluetoothHeadset;->isAudioConnected(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHeadset;->isAudioOn()Z
-Landroid/bluetooth/IBluetoothHeadset;->isInbandRingingEnabled()Z
-Landroid/bluetooth/IBluetoothHeadset;->phoneStateChanged(IIILjava/lang/String;I)V
-Landroid/bluetooth/IBluetoothHeadset;->sendVendorSpecificResultCode(Landroid/bluetooth/BluetoothDevice;Ljava/lang/String;Ljava/lang/String;)Z
-Landroid/bluetooth/IBluetoothHeadset;->setActiveDevice(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHeadset;->setAudioRouteAllowed(Z)V
-Landroid/bluetooth/IBluetoothHeadset;->setForceScoAudio(Z)V
-Landroid/bluetooth/IBluetoothHeadset;->startScoUsingVirtualVoiceCall()Z
-Landroid/bluetooth/IBluetoothHeadset;->startVoiceRecognition(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHeadset;->stopScoUsingVirtualVoiceCall()Z
-Landroid/bluetooth/IBluetoothHeadset;->stopVoiceRecognition(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub$Proxy;->acceptCall(Landroid/bluetooth/BluetoothDevice;I)Z
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub$Proxy;->connect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub$Proxy;->connectAudio(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub$Proxy;->dial(Landroid/bluetooth/BluetoothDevice;Ljava/lang/String;)Landroid/bluetooth/BluetoothHeadsetClientCall;
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub$Proxy;->disconnect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub$Proxy;->disconnectAudio(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub$Proxy;->enterPrivateMode(Landroid/bluetooth/BluetoothDevice;I)Z
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub$Proxy;->explicitCallTransfer(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub$Proxy;->getAudioRouteAllowed(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub$Proxy;->getAudioState(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub$Proxy;->getConnectedDevices()Ljava/util/List;
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub$Proxy;->getConnectionState(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub$Proxy;->getCurrentAgEvents(Landroid/bluetooth/BluetoothDevice;)Landroid/os/Bundle;
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub$Proxy;->getCurrentAgFeatures(Landroid/bluetooth/BluetoothDevice;)Landroid/os/Bundle;
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub$Proxy;->getCurrentCalls(Landroid/bluetooth/BluetoothDevice;)Ljava/util/List;
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub$Proxy;->getDevicesMatchingConnectionStates([I)Ljava/util/List;
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub$Proxy;->getLastVoiceTagNumber(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub$Proxy;->getPriority(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub$Proxy;->holdCall(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub$Proxy;->mRemote:Landroid/os/IBinder;
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub$Proxy;->rejectCall(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub$Proxy;->sendDTMF(Landroid/bluetooth/BluetoothDevice;B)Z
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub$Proxy;->setAudioRouteAllowed(Landroid/bluetooth/BluetoothDevice;Z)V
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub$Proxy;->setPriority(Landroid/bluetooth/BluetoothDevice;I)Z
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub$Proxy;->startVoiceRecognition(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub$Proxy;->stopVoiceRecognition(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub$Proxy;->terminateCall(Landroid/bluetooth/BluetoothDevice;Landroid/bluetooth/BluetoothHeadsetClientCall;)Z
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub;-><init>()V
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetoothHeadsetClient;
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub;->TRANSACTION_acceptCall:I
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub;->TRANSACTION_connect:I
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub;->TRANSACTION_connectAudio:I
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub;->TRANSACTION_dial:I
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub;->TRANSACTION_disconnect:I
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub;->TRANSACTION_disconnectAudio:I
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub;->TRANSACTION_enterPrivateMode:I
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub;->TRANSACTION_explicitCallTransfer:I
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub;->TRANSACTION_getAudioRouteAllowed:I
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub;->TRANSACTION_getAudioState:I
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub;->TRANSACTION_getConnectedDevices:I
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub;->TRANSACTION_getConnectionState:I
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub;->TRANSACTION_getCurrentAgEvents:I
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub;->TRANSACTION_getCurrentAgFeatures:I
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub;->TRANSACTION_getCurrentCalls:I
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub;->TRANSACTION_getDevicesMatchingConnectionStates:I
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub;->TRANSACTION_getLastVoiceTagNumber:I
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub;->TRANSACTION_getPriority:I
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub;->TRANSACTION_holdCall:I
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub;->TRANSACTION_rejectCall:I
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub;->TRANSACTION_sendDTMF:I
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub;->TRANSACTION_setAudioRouteAllowed:I
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub;->TRANSACTION_setPriority:I
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub;->TRANSACTION_startVoiceRecognition:I
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub;->TRANSACTION_stopVoiceRecognition:I
-Landroid/bluetooth/IBluetoothHeadsetClient$Stub;->TRANSACTION_terminateCall:I
-Landroid/bluetooth/IBluetoothHeadsetClient;->acceptCall(Landroid/bluetooth/BluetoothDevice;I)Z
-Landroid/bluetooth/IBluetoothHeadsetClient;->connect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHeadsetClient;->connectAudio(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHeadsetClient;->dial(Landroid/bluetooth/BluetoothDevice;Ljava/lang/String;)Landroid/bluetooth/BluetoothHeadsetClientCall;
-Landroid/bluetooth/IBluetoothHeadsetClient;->disconnect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHeadsetClient;->disconnectAudio(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHeadsetClient;->enterPrivateMode(Landroid/bluetooth/BluetoothDevice;I)Z
-Landroid/bluetooth/IBluetoothHeadsetClient;->explicitCallTransfer(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHeadsetClient;->getAudioRouteAllowed(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHeadsetClient;->getAudioState(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothHeadsetClient;->getConnectedDevices()Ljava/util/List;
-Landroid/bluetooth/IBluetoothHeadsetClient;->getConnectionState(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothHeadsetClient;->getCurrentAgEvents(Landroid/bluetooth/BluetoothDevice;)Landroid/os/Bundle;
-Landroid/bluetooth/IBluetoothHeadsetClient;->getCurrentAgFeatures(Landroid/bluetooth/BluetoothDevice;)Landroid/os/Bundle;
-Landroid/bluetooth/IBluetoothHeadsetClient;->getCurrentCalls(Landroid/bluetooth/BluetoothDevice;)Ljava/util/List;
-Landroid/bluetooth/IBluetoothHeadsetClient;->getDevicesMatchingConnectionStates([I)Ljava/util/List;
-Landroid/bluetooth/IBluetoothHeadsetClient;->getLastVoiceTagNumber(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHeadsetClient;->getPriority(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothHeadsetClient;->holdCall(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHeadsetClient;->rejectCall(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHeadsetClient;->sendDTMF(Landroid/bluetooth/BluetoothDevice;B)Z
-Landroid/bluetooth/IBluetoothHeadsetClient;->setAudioRouteAllowed(Landroid/bluetooth/BluetoothDevice;Z)V
-Landroid/bluetooth/IBluetoothHeadsetClient;->setPriority(Landroid/bluetooth/BluetoothDevice;I)Z
-Landroid/bluetooth/IBluetoothHeadsetClient;->startVoiceRecognition(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHeadsetClient;->stopVoiceRecognition(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHeadsetClient;->terminateCall(Landroid/bluetooth/BluetoothDevice;Landroid/bluetooth/BluetoothHeadsetClientCall;)Z
-Landroid/bluetooth/IBluetoothHeadsetPhone$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/bluetooth/IBluetoothHeadsetPhone$Stub$Proxy;->answerCall()Z
-Landroid/bluetooth/IBluetoothHeadsetPhone$Stub$Proxy;->cdmaSetSecondCallState(Z)V
-Landroid/bluetooth/IBluetoothHeadsetPhone$Stub$Proxy;->cdmaSwapSecondCallState()V
-Landroid/bluetooth/IBluetoothHeadsetPhone$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
-Landroid/bluetooth/IBluetoothHeadsetPhone$Stub$Proxy;->getNetworkOperator()Ljava/lang/String;
-Landroid/bluetooth/IBluetoothHeadsetPhone$Stub$Proxy;->getSubscriberNumber()Ljava/lang/String;
-Landroid/bluetooth/IBluetoothHeadsetPhone$Stub$Proxy;->hangupCall()Z
-Landroid/bluetooth/IBluetoothHeadsetPhone$Stub$Proxy;->listCurrentCalls()Z
-Landroid/bluetooth/IBluetoothHeadsetPhone$Stub$Proxy;->mRemote:Landroid/os/IBinder;
-Landroid/bluetooth/IBluetoothHeadsetPhone$Stub$Proxy;->processChld(I)Z
-Landroid/bluetooth/IBluetoothHeadsetPhone$Stub$Proxy;->queryPhoneState()Z
-Landroid/bluetooth/IBluetoothHeadsetPhone$Stub$Proxy;->sendDtmf(I)Z
-Landroid/bluetooth/IBluetoothHeadsetPhone$Stub$Proxy;->updateBtHandsfreeAfterRadioTechnologyChange()V
-Landroid/bluetooth/IBluetoothHeadsetPhone$Stub;-><init>()V
-Landroid/bluetooth/IBluetoothHeadsetPhone$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetoothHeadsetPhone;
-Landroid/bluetooth/IBluetoothHeadsetPhone$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/bluetooth/IBluetoothHeadsetPhone$Stub;->TRANSACTION_answerCall:I
-Landroid/bluetooth/IBluetoothHeadsetPhone$Stub;->TRANSACTION_cdmaSetSecondCallState:I
-Landroid/bluetooth/IBluetoothHeadsetPhone$Stub;->TRANSACTION_cdmaSwapSecondCallState:I
-Landroid/bluetooth/IBluetoothHeadsetPhone$Stub;->TRANSACTION_getNetworkOperator:I
-Landroid/bluetooth/IBluetoothHeadsetPhone$Stub;->TRANSACTION_getSubscriberNumber:I
-Landroid/bluetooth/IBluetoothHeadsetPhone$Stub;->TRANSACTION_hangupCall:I
-Landroid/bluetooth/IBluetoothHeadsetPhone$Stub;->TRANSACTION_listCurrentCalls:I
-Landroid/bluetooth/IBluetoothHeadsetPhone$Stub;->TRANSACTION_processChld:I
-Landroid/bluetooth/IBluetoothHeadsetPhone$Stub;->TRANSACTION_queryPhoneState:I
-Landroid/bluetooth/IBluetoothHeadsetPhone$Stub;->TRANSACTION_sendDtmf:I
-Landroid/bluetooth/IBluetoothHeadsetPhone$Stub;->TRANSACTION_updateBtHandsfreeAfterRadioTechnologyChange:I
-Landroid/bluetooth/IBluetoothHeadsetPhone;->answerCall()Z
-Landroid/bluetooth/IBluetoothHeadsetPhone;->cdmaSetSecondCallState(Z)V
-Landroid/bluetooth/IBluetoothHeadsetPhone;->cdmaSwapSecondCallState()V
-Landroid/bluetooth/IBluetoothHeadsetPhone;->getNetworkOperator()Ljava/lang/String;
-Landroid/bluetooth/IBluetoothHeadsetPhone;->getSubscriberNumber()Ljava/lang/String;
-Landroid/bluetooth/IBluetoothHeadsetPhone;->hangupCall()Z
-Landroid/bluetooth/IBluetoothHeadsetPhone;->listCurrentCalls()Z
-Landroid/bluetooth/IBluetoothHeadsetPhone;->processChld(I)Z
-Landroid/bluetooth/IBluetoothHeadsetPhone;->queryPhoneState()Z
-Landroid/bluetooth/IBluetoothHeadsetPhone;->sendDtmf(I)Z
-Landroid/bluetooth/IBluetoothHeadsetPhone;->updateBtHandsfreeAfterRadioTechnologyChange()V
-Landroid/bluetooth/IBluetoothHealth$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/bluetooth/IBluetoothHealth$Stub$Proxy;->connectChannelToSink(Landroid/bluetooth/BluetoothDevice;Landroid/bluetooth/BluetoothHealthAppConfiguration;I)Z
-Landroid/bluetooth/IBluetoothHealth$Stub$Proxy;->connectChannelToSource(Landroid/bluetooth/BluetoothDevice;Landroid/bluetooth/BluetoothHealthAppConfiguration;)Z
-Landroid/bluetooth/IBluetoothHealth$Stub$Proxy;->disconnectChannel(Landroid/bluetooth/BluetoothDevice;Landroid/bluetooth/BluetoothHealthAppConfiguration;I)Z
-Landroid/bluetooth/IBluetoothHealth$Stub$Proxy;->getConnectedHealthDevices()Ljava/util/List;
-Landroid/bluetooth/IBluetoothHealth$Stub$Proxy;->getHealthDeviceConnectionState(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothHealth$Stub$Proxy;->getHealthDevicesMatchingConnectionStates([I)Ljava/util/List;
-Landroid/bluetooth/IBluetoothHealth$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
-Landroid/bluetooth/IBluetoothHealth$Stub$Proxy;->getMainChannelFd(Landroid/bluetooth/BluetoothDevice;Landroid/bluetooth/BluetoothHealthAppConfiguration;)Landroid/os/ParcelFileDescriptor;
-Landroid/bluetooth/IBluetoothHealth$Stub$Proxy;->mRemote:Landroid/os/IBinder;
-Landroid/bluetooth/IBluetoothHealth$Stub$Proxy;->registerAppConfiguration(Landroid/bluetooth/BluetoothHealthAppConfiguration;Landroid/bluetooth/IBluetoothHealthCallback;)Z
-Landroid/bluetooth/IBluetoothHealth$Stub$Proxy;->unregisterAppConfiguration(Landroid/bluetooth/BluetoothHealthAppConfiguration;)Z
-Landroid/bluetooth/IBluetoothHealth$Stub;-><init>()V
-Landroid/bluetooth/IBluetoothHealth$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetoothHealth;
-Landroid/bluetooth/IBluetoothHealth$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/bluetooth/IBluetoothHealth$Stub;->TRANSACTION_connectChannelToSink:I
-Landroid/bluetooth/IBluetoothHealth$Stub;->TRANSACTION_connectChannelToSource:I
-Landroid/bluetooth/IBluetoothHealth$Stub;->TRANSACTION_disconnectChannel:I
-Landroid/bluetooth/IBluetoothHealth$Stub;->TRANSACTION_getConnectedHealthDevices:I
-Landroid/bluetooth/IBluetoothHealth$Stub;->TRANSACTION_getHealthDeviceConnectionState:I
-Landroid/bluetooth/IBluetoothHealth$Stub;->TRANSACTION_getHealthDevicesMatchingConnectionStates:I
-Landroid/bluetooth/IBluetoothHealth$Stub;->TRANSACTION_getMainChannelFd:I
-Landroid/bluetooth/IBluetoothHealth$Stub;->TRANSACTION_registerAppConfiguration:I
-Landroid/bluetooth/IBluetoothHealth$Stub;->TRANSACTION_unregisterAppConfiguration:I
-Landroid/bluetooth/IBluetoothHealth;->connectChannelToSink(Landroid/bluetooth/BluetoothDevice;Landroid/bluetooth/BluetoothHealthAppConfiguration;I)Z
-Landroid/bluetooth/IBluetoothHealth;->connectChannelToSource(Landroid/bluetooth/BluetoothDevice;Landroid/bluetooth/BluetoothHealthAppConfiguration;)Z
-Landroid/bluetooth/IBluetoothHealth;->disconnectChannel(Landroid/bluetooth/BluetoothDevice;Landroid/bluetooth/BluetoothHealthAppConfiguration;I)Z
-Landroid/bluetooth/IBluetoothHealth;->getConnectedHealthDevices()Ljava/util/List;
-Landroid/bluetooth/IBluetoothHealth;->getHealthDeviceConnectionState(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothHealth;->getHealthDevicesMatchingConnectionStates([I)Ljava/util/List;
-Landroid/bluetooth/IBluetoothHealth;->getMainChannelFd(Landroid/bluetooth/BluetoothDevice;Landroid/bluetooth/BluetoothHealthAppConfiguration;)Landroid/os/ParcelFileDescriptor;
-Landroid/bluetooth/IBluetoothHealth;->registerAppConfiguration(Landroid/bluetooth/BluetoothHealthAppConfiguration;Landroid/bluetooth/IBluetoothHealthCallback;)Z
-Landroid/bluetooth/IBluetoothHealth;->unregisterAppConfiguration(Landroid/bluetooth/BluetoothHealthAppConfiguration;)Z
-Landroid/bluetooth/IBluetoothHealthCallback$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/bluetooth/IBluetoothHealthCallback$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
-Landroid/bluetooth/IBluetoothHealthCallback$Stub$Proxy;->mRemote:Landroid/os/IBinder;
-Landroid/bluetooth/IBluetoothHealthCallback$Stub$Proxy;->onHealthAppConfigurationStatusChange(Landroid/bluetooth/BluetoothHealthAppConfiguration;I)V
-Landroid/bluetooth/IBluetoothHealthCallback$Stub$Proxy;->onHealthChannelStateChange(Landroid/bluetooth/BluetoothHealthAppConfiguration;Landroid/bluetooth/BluetoothDevice;IILandroid/os/ParcelFileDescriptor;I)V
-Landroid/bluetooth/IBluetoothHealthCallback$Stub;-><init>()V
-Landroid/bluetooth/IBluetoothHealthCallback$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetoothHealthCallback;
-Landroid/bluetooth/IBluetoothHealthCallback$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/bluetooth/IBluetoothHealthCallback$Stub;->TRANSACTION_onHealthAppConfigurationStatusChange:I
-Landroid/bluetooth/IBluetoothHealthCallback$Stub;->TRANSACTION_onHealthChannelStateChange:I
-Landroid/bluetooth/IBluetoothHealthCallback;->onHealthAppConfigurationStatusChange(Landroid/bluetooth/BluetoothHealthAppConfiguration;I)V
-Landroid/bluetooth/IBluetoothHealthCallback;->onHealthChannelStateChange(Landroid/bluetooth/BluetoothHealthAppConfiguration;Landroid/bluetooth/BluetoothDevice;IILandroid/os/ParcelFileDescriptor;I)V
-Landroid/bluetooth/IBluetoothHearingAid$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/bluetooth/IBluetoothHearingAid$Stub$Proxy;->adjustVolume(I)V
-Landroid/bluetooth/IBluetoothHearingAid$Stub$Proxy;->connect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHearingAid$Stub$Proxy;->disconnect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHearingAid$Stub$Proxy;->getActiveDevices()Ljava/util/List;
-Landroid/bluetooth/IBluetoothHearingAid$Stub$Proxy;->getConnectedDevices()Ljava/util/List;
-Landroid/bluetooth/IBluetoothHearingAid$Stub$Proxy;->getConnectionState(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothHearingAid$Stub$Proxy;->getDeviceMode(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothHearingAid$Stub$Proxy;->getDeviceSide(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothHearingAid$Stub$Proxy;->getDevicesMatchingConnectionStates([I)Ljava/util/List;
-Landroid/bluetooth/IBluetoothHearingAid$Stub$Proxy;->getHiSyncId(Landroid/bluetooth/BluetoothDevice;)J
-Landroid/bluetooth/IBluetoothHearingAid$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
-Landroid/bluetooth/IBluetoothHearingAid$Stub$Proxy;->getPriority(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothHearingAid$Stub$Proxy;->getVolume()I
-Landroid/bluetooth/IBluetoothHearingAid$Stub$Proxy;->mRemote:Landroid/os/IBinder;
-Landroid/bluetooth/IBluetoothHearingAid$Stub$Proxy;->setActiveDevice(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHearingAid$Stub$Proxy;->setPriority(Landroid/bluetooth/BluetoothDevice;I)Z
-Landroid/bluetooth/IBluetoothHearingAid$Stub$Proxy;->setVolume(I)V
-Landroid/bluetooth/IBluetoothHearingAid$Stub;-><init>()V
-Landroid/bluetooth/IBluetoothHearingAid$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetoothHearingAid;
-Landroid/bluetooth/IBluetoothHearingAid$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/bluetooth/IBluetoothHearingAid$Stub;->TRANSACTION_adjustVolume:I
-Landroid/bluetooth/IBluetoothHearingAid$Stub;->TRANSACTION_connect:I
-Landroid/bluetooth/IBluetoothHearingAid$Stub;->TRANSACTION_disconnect:I
-Landroid/bluetooth/IBluetoothHearingAid$Stub;->TRANSACTION_getActiveDevices:I
-Landroid/bluetooth/IBluetoothHearingAid$Stub;->TRANSACTION_getConnectedDevices:I
-Landroid/bluetooth/IBluetoothHearingAid$Stub;->TRANSACTION_getConnectionState:I
-Landroid/bluetooth/IBluetoothHearingAid$Stub;->TRANSACTION_getDeviceMode:I
-Landroid/bluetooth/IBluetoothHearingAid$Stub;->TRANSACTION_getDeviceSide:I
-Landroid/bluetooth/IBluetoothHearingAid$Stub;->TRANSACTION_getDevicesMatchingConnectionStates:I
-Landroid/bluetooth/IBluetoothHearingAid$Stub;->TRANSACTION_getHiSyncId:I
-Landroid/bluetooth/IBluetoothHearingAid$Stub;->TRANSACTION_getPriority:I
-Landroid/bluetooth/IBluetoothHearingAid$Stub;->TRANSACTION_getVolume:I
-Landroid/bluetooth/IBluetoothHearingAid$Stub;->TRANSACTION_setActiveDevice:I
-Landroid/bluetooth/IBluetoothHearingAid$Stub;->TRANSACTION_setPriority:I
-Landroid/bluetooth/IBluetoothHearingAid$Stub;->TRANSACTION_setVolume:I
-Landroid/bluetooth/IBluetoothHearingAid;->adjustVolume(I)V
-Landroid/bluetooth/IBluetoothHearingAid;->connect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHearingAid;->disconnect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHearingAid;->getActiveDevices()Ljava/util/List;
-Landroid/bluetooth/IBluetoothHearingAid;->getConnectedDevices()Ljava/util/List;
-Landroid/bluetooth/IBluetoothHearingAid;->getConnectionState(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothHearingAid;->getDeviceMode(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothHearingAid;->getDeviceSide(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothHearingAid;->getDevicesMatchingConnectionStates([I)Ljava/util/List;
-Landroid/bluetooth/IBluetoothHearingAid;->getHiSyncId(Landroid/bluetooth/BluetoothDevice;)J
-Landroid/bluetooth/IBluetoothHearingAid;->getPriority(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothHearingAid;->getVolume()I
-Landroid/bluetooth/IBluetoothHearingAid;->HI_SYNC_ID_INVALID:I
-Landroid/bluetooth/IBluetoothHearingAid;->MODE_BINAURAL:I
-Landroid/bluetooth/IBluetoothHearingAid;->MODE_MONAURAL:I
-Landroid/bluetooth/IBluetoothHearingAid;->setActiveDevice(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHearingAid;->setPriority(Landroid/bluetooth/BluetoothDevice;I)Z
-Landroid/bluetooth/IBluetoothHearingAid;->setVolume(I)V
-Landroid/bluetooth/IBluetoothHearingAid;->SIDE_LEFT:I
-Landroid/bluetooth/IBluetoothHearingAid;->SIDE_RIGHT:I
-Landroid/bluetooth/IBluetoothHidDevice$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/bluetooth/IBluetoothHidDevice$Stub$Proxy;->connect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHidDevice$Stub$Proxy;->disconnect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHidDevice$Stub$Proxy;->getConnectedDevices()Ljava/util/List;
-Landroid/bluetooth/IBluetoothHidDevice$Stub$Proxy;->getConnectionState(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothHidDevice$Stub$Proxy;->getDevicesMatchingConnectionStates([I)Ljava/util/List;
-Landroid/bluetooth/IBluetoothHidDevice$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
-Landroid/bluetooth/IBluetoothHidDevice$Stub$Proxy;->getUserAppName()Ljava/lang/String;
-Landroid/bluetooth/IBluetoothHidDevice$Stub$Proxy;->mRemote:Landroid/os/IBinder;
-Landroid/bluetooth/IBluetoothHidDevice$Stub$Proxy;->registerApp(Landroid/bluetooth/BluetoothHidDeviceAppSdpSettings;Landroid/bluetooth/BluetoothHidDeviceAppQosSettings;Landroid/bluetooth/BluetoothHidDeviceAppQosSettings;Landroid/bluetooth/IBluetoothHidDeviceCallback;)Z
-Landroid/bluetooth/IBluetoothHidDevice$Stub$Proxy;->replyReport(Landroid/bluetooth/BluetoothDevice;BB[B)Z
-Landroid/bluetooth/IBluetoothHidDevice$Stub$Proxy;->reportError(Landroid/bluetooth/BluetoothDevice;B)Z
-Landroid/bluetooth/IBluetoothHidDevice$Stub$Proxy;->sendReport(Landroid/bluetooth/BluetoothDevice;I[B)Z
-Landroid/bluetooth/IBluetoothHidDevice$Stub$Proxy;->unplug(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHidDevice$Stub$Proxy;->unregisterApp()Z
-Landroid/bluetooth/IBluetoothHidDevice$Stub;-><init>()V
-Landroid/bluetooth/IBluetoothHidDevice$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetoothHidDevice;
-Landroid/bluetooth/IBluetoothHidDevice$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/bluetooth/IBluetoothHidDevice$Stub;->TRANSACTION_connect:I
-Landroid/bluetooth/IBluetoothHidDevice$Stub;->TRANSACTION_disconnect:I
-Landroid/bluetooth/IBluetoothHidDevice$Stub;->TRANSACTION_getConnectedDevices:I
-Landroid/bluetooth/IBluetoothHidDevice$Stub;->TRANSACTION_getConnectionState:I
-Landroid/bluetooth/IBluetoothHidDevice$Stub;->TRANSACTION_getDevicesMatchingConnectionStates:I
-Landroid/bluetooth/IBluetoothHidDevice$Stub;->TRANSACTION_getUserAppName:I
-Landroid/bluetooth/IBluetoothHidDevice$Stub;->TRANSACTION_registerApp:I
-Landroid/bluetooth/IBluetoothHidDevice$Stub;->TRANSACTION_replyReport:I
-Landroid/bluetooth/IBluetoothHidDevice$Stub;->TRANSACTION_reportError:I
-Landroid/bluetooth/IBluetoothHidDevice$Stub;->TRANSACTION_sendReport:I
-Landroid/bluetooth/IBluetoothHidDevice$Stub;->TRANSACTION_unplug:I
-Landroid/bluetooth/IBluetoothHidDevice$Stub;->TRANSACTION_unregisterApp:I
-Landroid/bluetooth/IBluetoothHidDevice;->connect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHidDevice;->disconnect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHidDevice;->getConnectedDevices()Ljava/util/List;
-Landroid/bluetooth/IBluetoothHidDevice;->getConnectionState(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothHidDevice;->getDevicesMatchingConnectionStates([I)Ljava/util/List;
-Landroid/bluetooth/IBluetoothHidDevice;->getUserAppName()Ljava/lang/String;
-Landroid/bluetooth/IBluetoothHidDevice;->registerApp(Landroid/bluetooth/BluetoothHidDeviceAppSdpSettings;Landroid/bluetooth/BluetoothHidDeviceAppQosSettings;Landroid/bluetooth/BluetoothHidDeviceAppQosSettings;Landroid/bluetooth/IBluetoothHidDeviceCallback;)Z
-Landroid/bluetooth/IBluetoothHidDevice;->replyReport(Landroid/bluetooth/BluetoothDevice;BB[B)Z
-Landroid/bluetooth/IBluetoothHidDevice;->reportError(Landroid/bluetooth/BluetoothDevice;B)Z
-Landroid/bluetooth/IBluetoothHidDevice;->sendReport(Landroid/bluetooth/BluetoothDevice;I[B)Z
-Landroid/bluetooth/IBluetoothHidDevice;->unplug(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHidDevice;->unregisterApp()Z
-Landroid/bluetooth/IBluetoothHidDeviceCallback$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/bluetooth/IBluetoothHidDeviceCallback$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
-Landroid/bluetooth/IBluetoothHidDeviceCallback$Stub$Proxy;->mRemote:Landroid/os/IBinder;
-Landroid/bluetooth/IBluetoothHidDeviceCallback$Stub$Proxy;->onAppStatusChanged(Landroid/bluetooth/BluetoothDevice;Z)V
-Landroid/bluetooth/IBluetoothHidDeviceCallback$Stub$Proxy;->onConnectionStateChanged(Landroid/bluetooth/BluetoothDevice;I)V
-Landroid/bluetooth/IBluetoothHidDeviceCallback$Stub$Proxy;->onGetReport(Landroid/bluetooth/BluetoothDevice;BBI)V
-Landroid/bluetooth/IBluetoothHidDeviceCallback$Stub$Proxy;->onInterruptData(Landroid/bluetooth/BluetoothDevice;B[B)V
-Landroid/bluetooth/IBluetoothHidDeviceCallback$Stub$Proxy;->onSetProtocol(Landroid/bluetooth/BluetoothDevice;B)V
-Landroid/bluetooth/IBluetoothHidDeviceCallback$Stub$Proxy;->onSetReport(Landroid/bluetooth/BluetoothDevice;BB[B)V
-Landroid/bluetooth/IBluetoothHidDeviceCallback$Stub$Proxy;->onVirtualCableUnplug(Landroid/bluetooth/BluetoothDevice;)V
-Landroid/bluetooth/IBluetoothHidDeviceCallback$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetoothHidDeviceCallback;
-Landroid/bluetooth/IBluetoothHidDeviceCallback$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/bluetooth/IBluetoothHidDeviceCallback$Stub;->TRANSACTION_onAppStatusChanged:I
-Landroid/bluetooth/IBluetoothHidDeviceCallback$Stub;->TRANSACTION_onConnectionStateChanged:I
-Landroid/bluetooth/IBluetoothHidDeviceCallback$Stub;->TRANSACTION_onGetReport:I
-Landroid/bluetooth/IBluetoothHidDeviceCallback$Stub;->TRANSACTION_onInterruptData:I
-Landroid/bluetooth/IBluetoothHidDeviceCallback$Stub;->TRANSACTION_onSetProtocol:I
-Landroid/bluetooth/IBluetoothHidDeviceCallback$Stub;->TRANSACTION_onSetReport:I
-Landroid/bluetooth/IBluetoothHidDeviceCallback$Stub;->TRANSACTION_onVirtualCableUnplug:I
-Landroid/bluetooth/IBluetoothHidDeviceCallback;->onAppStatusChanged(Landroid/bluetooth/BluetoothDevice;Z)V
-Landroid/bluetooth/IBluetoothHidDeviceCallback;->onConnectionStateChanged(Landroid/bluetooth/BluetoothDevice;I)V
-Landroid/bluetooth/IBluetoothHidDeviceCallback;->onGetReport(Landroid/bluetooth/BluetoothDevice;BBI)V
-Landroid/bluetooth/IBluetoothHidDeviceCallback;->onInterruptData(Landroid/bluetooth/BluetoothDevice;B[B)V
-Landroid/bluetooth/IBluetoothHidDeviceCallback;->onSetProtocol(Landroid/bluetooth/BluetoothDevice;B)V
-Landroid/bluetooth/IBluetoothHidDeviceCallback;->onSetReport(Landroid/bluetooth/BluetoothDevice;BB[B)V
-Landroid/bluetooth/IBluetoothHidDeviceCallback;->onVirtualCableUnplug(Landroid/bluetooth/BluetoothDevice;)V
-Landroid/bluetooth/IBluetoothHidHost$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/bluetooth/IBluetoothHidHost$Stub$Proxy;->connect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHidHost$Stub$Proxy;->disconnect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHidHost$Stub$Proxy;->getConnectedDevices()Ljava/util/List;
-Landroid/bluetooth/IBluetoothHidHost$Stub$Proxy;->getConnectionState(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothHidHost$Stub$Proxy;->getDevicesMatchingConnectionStates([I)Ljava/util/List;
-Landroid/bluetooth/IBluetoothHidHost$Stub$Proxy;->getIdleTime(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHidHost$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
-Landroid/bluetooth/IBluetoothHidHost$Stub$Proxy;->getPriority(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothHidHost$Stub$Proxy;->getProtocolMode(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHidHost$Stub$Proxy;->getReport(Landroid/bluetooth/BluetoothDevice;BBI)Z
-Landroid/bluetooth/IBluetoothHidHost$Stub$Proxy;->mRemote:Landroid/os/IBinder;
-Landroid/bluetooth/IBluetoothHidHost$Stub$Proxy;->sendData(Landroid/bluetooth/BluetoothDevice;Ljava/lang/String;)Z
-Landroid/bluetooth/IBluetoothHidHost$Stub$Proxy;->setIdleTime(Landroid/bluetooth/BluetoothDevice;B)Z
-Landroid/bluetooth/IBluetoothHidHost$Stub$Proxy;->setPriority(Landroid/bluetooth/BluetoothDevice;I)Z
-Landroid/bluetooth/IBluetoothHidHost$Stub$Proxy;->setProtocolMode(Landroid/bluetooth/BluetoothDevice;I)Z
-Landroid/bluetooth/IBluetoothHidHost$Stub$Proxy;->setReport(Landroid/bluetooth/BluetoothDevice;BLjava/lang/String;)Z
-Landroid/bluetooth/IBluetoothHidHost$Stub$Proxy;->virtualUnplug(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHidHost$Stub;-><init>()V
-Landroid/bluetooth/IBluetoothHidHost$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetoothHidHost;
-Landroid/bluetooth/IBluetoothHidHost$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/bluetooth/IBluetoothHidHost$Stub;->TRANSACTION_connect:I
-Landroid/bluetooth/IBluetoothHidHost$Stub;->TRANSACTION_disconnect:I
-Landroid/bluetooth/IBluetoothHidHost$Stub;->TRANSACTION_getConnectedDevices:I
-Landroid/bluetooth/IBluetoothHidHost$Stub;->TRANSACTION_getConnectionState:I
-Landroid/bluetooth/IBluetoothHidHost$Stub;->TRANSACTION_getDevicesMatchingConnectionStates:I
-Landroid/bluetooth/IBluetoothHidHost$Stub;->TRANSACTION_getIdleTime:I
-Landroid/bluetooth/IBluetoothHidHost$Stub;->TRANSACTION_getPriority:I
-Landroid/bluetooth/IBluetoothHidHost$Stub;->TRANSACTION_getProtocolMode:I
-Landroid/bluetooth/IBluetoothHidHost$Stub;->TRANSACTION_getReport:I
-Landroid/bluetooth/IBluetoothHidHost$Stub;->TRANSACTION_sendData:I
-Landroid/bluetooth/IBluetoothHidHost$Stub;->TRANSACTION_setIdleTime:I
-Landroid/bluetooth/IBluetoothHidHost$Stub;->TRANSACTION_setPriority:I
-Landroid/bluetooth/IBluetoothHidHost$Stub;->TRANSACTION_setProtocolMode:I
-Landroid/bluetooth/IBluetoothHidHost$Stub;->TRANSACTION_setReport:I
-Landroid/bluetooth/IBluetoothHidHost$Stub;->TRANSACTION_virtualUnplug:I
-Landroid/bluetooth/IBluetoothHidHost;->connect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHidHost;->disconnect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHidHost;->getConnectedDevices()Ljava/util/List;
-Landroid/bluetooth/IBluetoothHidHost;->getConnectionState(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothHidHost;->getDevicesMatchingConnectionStates([I)Ljava/util/List;
-Landroid/bluetooth/IBluetoothHidHost;->getIdleTime(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHidHost;->getPriority(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothHidHost;->getProtocolMode(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothHidHost;->getReport(Landroid/bluetooth/BluetoothDevice;BBI)Z
-Landroid/bluetooth/IBluetoothHidHost;->sendData(Landroid/bluetooth/BluetoothDevice;Ljava/lang/String;)Z
-Landroid/bluetooth/IBluetoothHidHost;->setIdleTime(Landroid/bluetooth/BluetoothDevice;B)Z
-Landroid/bluetooth/IBluetoothHidHost;->setPriority(Landroid/bluetooth/BluetoothDevice;I)Z
-Landroid/bluetooth/IBluetoothHidHost;->setProtocolMode(Landroid/bluetooth/BluetoothDevice;I)Z
-Landroid/bluetooth/IBluetoothHidHost;->setReport(Landroid/bluetooth/BluetoothDevice;BLjava/lang/String;)Z
-Landroid/bluetooth/IBluetoothHidHost;->virtualUnplug(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothManager$Stub$Proxy;->bindBluetoothProfileService(ILandroid/bluetooth/IBluetoothProfileServiceConnection;)Z
-Landroid/bluetooth/IBluetoothManager$Stub$Proxy;->disable(Ljava/lang/String;Z)Z
-Landroid/bluetooth/IBluetoothManager$Stub$Proxy;->enable(Ljava/lang/String;)Z
-Landroid/bluetooth/IBluetoothManager$Stub$Proxy;->enableNoAutoConnect(Ljava/lang/String;)Z
-Landroid/bluetooth/IBluetoothManager$Stub$Proxy;->getAddress()Ljava/lang/String;
-Landroid/bluetooth/IBluetoothManager$Stub$Proxy;->getBluetoothGatt()Landroid/bluetooth/IBluetoothGatt;
-Landroid/bluetooth/IBluetoothManager$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
-Landroid/bluetooth/IBluetoothManager$Stub$Proxy;->getName()Ljava/lang/String;
-Landroid/bluetooth/IBluetoothManager$Stub$Proxy;->getState()I
-Landroid/bluetooth/IBluetoothManager$Stub$Proxy;->isBleAppPresent()Z
-Landroid/bluetooth/IBluetoothManager$Stub$Proxy;->isBleScanAlwaysAvailable()Z
-Landroid/bluetooth/IBluetoothManager$Stub$Proxy;->isEnabled()Z
-Landroid/bluetooth/IBluetoothManager$Stub$Proxy;->mRemote:Landroid/os/IBinder;
-Landroid/bluetooth/IBluetoothManager$Stub$Proxy;->registerAdapter(Landroid/bluetooth/IBluetoothManagerCallback;)Landroid/bluetooth/IBluetooth;
-Landroid/bluetooth/IBluetoothManager$Stub$Proxy;->registerStateChangeCallback(Landroid/bluetooth/IBluetoothStateChangeCallback;)V
-Landroid/bluetooth/IBluetoothManager$Stub$Proxy;->unbindBluetoothProfileService(ILandroid/bluetooth/IBluetoothProfileServiceConnection;)V
-Landroid/bluetooth/IBluetoothManager$Stub$Proxy;->unregisterAdapter(Landroid/bluetooth/IBluetoothManagerCallback;)V
-Landroid/bluetooth/IBluetoothManager$Stub$Proxy;->unregisterStateChangeCallback(Landroid/bluetooth/IBluetoothStateChangeCallback;)V
-Landroid/bluetooth/IBluetoothManager$Stub$Proxy;->updateBleAppCount(Landroid/os/IBinder;ZLjava/lang/String;)I
-Landroid/bluetooth/IBluetoothManager$Stub;-><init>()V
-Landroid/bluetooth/IBluetoothManager$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/bluetooth/IBluetoothManager$Stub;->TRANSACTION_bindBluetoothProfileService:I
-Landroid/bluetooth/IBluetoothManager$Stub;->TRANSACTION_disable:I
-Landroid/bluetooth/IBluetoothManager$Stub;->TRANSACTION_enableNoAutoConnect:I
-Landroid/bluetooth/IBluetoothManager$Stub;->TRANSACTION_getAddress:I
-Landroid/bluetooth/IBluetoothManager$Stub;->TRANSACTION_getBluetoothGatt:I
-Landroid/bluetooth/IBluetoothManager$Stub;->TRANSACTION_getName:I
-Landroid/bluetooth/IBluetoothManager$Stub;->TRANSACTION_getState:I
-Landroid/bluetooth/IBluetoothManager$Stub;->TRANSACTION_isBleAppPresent:I
-Landroid/bluetooth/IBluetoothManager$Stub;->TRANSACTION_isBleScanAlwaysAvailable:I
-Landroid/bluetooth/IBluetoothManager$Stub;->TRANSACTION_isEnabled:I
-Landroid/bluetooth/IBluetoothManager$Stub;->TRANSACTION_registerAdapter:I
-Landroid/bluetooth/IBluetoothManager$Stub;->TRANSACTION_registerStateChangeCallback:I
-Landroid/bluetooth/IBluetoothManager$Stub;->TRANSACTION_unbindBluetoothProfileService:I
-Landroid/bluetooth/IBluetoothManager$Stub;->TRANSACTION_unregisterAdapter:I
-Landroid/bluetooth/IBluetoothManager$Stub;->TRANSACTION_unregisterStateChangeCallback:I
-Landroid/bluetooth/IBluetoothManager$Stub;->TRANSACTION_updateBleAppCount:I
-Landroid/bluetooth/IBluetoothManager;->bindBluetoothProfileService(ILandroid/bluetooth/IBluetoothProfileServiceConnection;)Z
-Landroid/bluetooth/IBluetoothManager;->disable(Ljava/lang/String;Z)Z
-Landroid/bluetooth/IBluetoothManager;->enable(Ljava/lang/String;)Z
-Landroid/bluetooth/IBluetoothManager;->enableNoAutoConnect(Ljava/lang/String;)Z
-Landroid/bluetooth/IBluetoothManager;->getAddress()Ljava/lang/String;
-Landroid/bluetooth/IBluetoothManager;->getName()Ljava/lang/String;
-Landroid/bluetooth/IBluetoothManager;->getState()I
-Landroid/bluetooth/IBluetoothManager;->isBleAppPresent()Z
-Landroid/bluetooth/IBluetoothManager;->isBleScanAlwaysAvailable()Z
-Landroid/bluetooth/IBluetoothManager;->isEnabled()Z
-Landroid/bluetooth/IBluetoothManager;->registerAdapter(Landroid/bluetooth/IBluetoothManagerCallback;)Landroid/bluetooth/IBluetooth;
-Landroid/bluetooth/IBluetoothManager;->unbindBluetoothProfileService(ILandroid/bluetooth/IBluetoothProfileServiceConnection;)V
-Landroid/bluetooth/IBluetoothManager;->unregisterAdapter(Landroid/bluetooth/IBluetoothManagerCallback;)V
-Landroid/bluetooth/IBluetoothManager;->updateBleAppCount(Landroid/os/IBinder;ZLjava/lang/String;)I
-Landroid/bluetooth/IBluetoothManagerCallback$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/bluetooth/IBluetoothManagerCallback$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
-Landroid/bluetooth/IBluetoothManagerCallback$Stub$Proxy;->mRemote:Landroid/os/IBinder;
-Landroid/bluetooth/IBluetoothManagerCallback$Stub$Proxy;->onBluetoothServiceDown()V
-Landroid/bluetooth/IBluetoothManagerCallback$Stub$Proxy;->onBluetoothServiceUp(Landroid/bluetooth/IBluetooth;)V
-Landroid/bluetooth/IBluetoothManagerCallback$Stub$Proxy;->onBrEdrDown()V
-Landroid/bluetooth/IBluetoothManagerCallback$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetoothManagerCallback;
-Landroid/bluetooth/IBluetoothManagerCallback$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/bluetooth/IBluetoothManagerCallback$Stub;->TRANSACTION_onBluetoothServiceDown:I
-Landroid/bluetooth/IBluetoothManagerCallback$Stub;->TRANSACTION_onBluetoothServiceUp:I
-Landroid/bluetooth/IBluetoothManagerCallback$Stub;->TRANSACTION_onBrEdrDown:I
-Landroid/bluetooth/IBluetoothManagerCallback;->onBluetoothServiceDown()V
-Landroid/bluetooth/IBluetoothManagerCallback;->onBluetoothServiceUp(Landroid/bluetooth/IBluetooth;)V
-Landroid/bluetooth/IBluetoothManagerCallback;->onBrEdrDown()V
-Landroid/bluetooth/IBluetoothMap$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/bluetooth/IBluetoothMap$Stub$Proxy;->connect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothMap$Stub$Proxy;->disconnect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothMap$Stub$Proxy;->getClient()Landroid/bluetooth/BluetoothDevice;
-Landroid/bluetooth/IBluetoothMap$Stub$Proxy;->getConnectedDevices()Ljava/util/List;
-Landroid/bluetooth/IBluetoothMap$Stub$Proxy;->getConnectionState(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothMap$Stub$Proxy;->getDevicesMatchingConnectionStates([I)Ljava/util/List;
-Landroid/bluetooth/IBluetoothMap$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
-Landroid/bluetooth/IBluetoothMap$Stub$Proxy;->getPriority(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothMap$Stub$Proxy;->getState()I
-Landroid/bluetooth/IBluetoothMap$Stub$Proxy;->isConnected(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothMap$Stub$Proxy;->mRemote:Landroid/os/IBinder;
-Landroid/bluetooth/IBluetoothMap$Stub$Proxy;->setPriority(Landroid/bluetooth/BluetoothDevice;I)Z
-Landroid/bluetooth/IBluetoothMap$Stub;-><init>()V
-Landroid/bluetooth/IBluetoothMap$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetoothMap;
-Landroid/bluetooth/IBluetoothMap$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/bluetooth/IBluetoothMap$Stub;->TRANSACTION_connect:I
-Landroid/bluetooth/IBluetoothMap$Stub;->TRANSACTION_disconnect:I
-Landroid/bluetooth/IBluetoothMap$Stub;->TRANSACTION_getClient:I
-Landroid/bluetooth/IBluetoothMap$Stub;->TRANSACTION_getConnectedDevices:I
-Landroid/bluetooth/IBluetoothMap$Stub;->TRANSACTION_getConnectionState:I
-Landroid/bluetooth/IBluetoothMap$Stub;->TRANSACTION_getDevicesMatchingConnectionStates:I
-Landroid/bluetooth/IBluetoothMap$Stub;->TRANSACTION_getPriority:I
-Landroid/bluetooth/IBluetoothMap$Stub;->TRANSACTION_getState:I
-Landroid/bluetooth/IBluetoothMap$Stub;->TRANSACTION_isConnected:I
-Landroid/bluetooth/IBluetoothMap$Stub;->TRANSACTION_setPriority:I
-Landroid/bluetooth/IBluetoothMap;->connect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothMap;->disconnect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothMap;->getClient()Landroid/bluetooth/BluetoothDevice;
-Landroid/bluetooth/IBluetoothMap;->getConnectedDevices()Ljava/util/List;
-Landroid/bluetooth/IBluetoothMap;->getConnectionState(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothMap;->getDevicesMatchingConnectionStates([I)Ljava/util/List;
-Landroid/bluetooth/IBluetoothMap;->getPriority(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothMap;->getState()I
-Landroid/bluetooth/IBluetoothMap;->isConnected(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothMap;->setPriority(Landroid/bluetooth/BluetoothDevice;I)Z
-Landroid/bluetooth/IBluetoothMapClient$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/bluetooth/IBluetoothMapClient$Stub$Proxy;->connect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothMapClient$Stub$Proxy;->disconnect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothMapClient$Stub$Proxy;->getConnectedDevices()Ljava/util/List;
-Landroid/bluetooth/IBluetoothMapClient$Stub$Proxy;->getConnectionState(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothMapClient$Stub$Proxy;->getDevicesMatchingConnectionStates([I)Ljava/util/List;
-Landroid/bluetooth/IBluetoothMapClient$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
-Landroid/bluetooth/IBluetoothMapClient$Stub$Proxy;->getPriority(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothMapClient$Stub$Proxy;->getUnreadMessages(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothMapClient$Stub$Proxy;->isConnected(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothMapClient$Stub$Proxy;->mRemote:Landroid/os/IBinder;
-Landroid/bluetooth/IBluetoothMapClient$Stub$Proxy;->sendMessage(Landroid/bluetooth/BluetoothDevice;[Landroid/net/Uri;Ljava/lang/String;Landroid/app/PendingIntent;Landroid/app/PendingIntent;)Z
-Landroid/bluetooth/IBluetoothMapClient$Stub$Proxy;->setPriority(Landroid/bluetooth/BluetoothDevice;I)Z
-Landroid/bluetooth/IBluetoothMapClient$Stub;-><init>()V
-Landroid/bluetooth/IBluetoothMapClient$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetoothMapClient;
-Landroid/bluetooth/IBluetoothMapClient$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/bluetooth/IBluetoothMapClient$Stub;->TRANSACTION_connect:I
-Landroid/bluetooth/IBluetoothMapClient$Stub;->TRANSACTION_disconnect:I
-Landroid/bluetooth/IBluetoothMapClient$Stub;->TRANSACTION_getConnectedDevices:I
-Landroid/bluetooth/IBluetoothMapClient$Stub;->TRANSACTION_getConnectionState:I
-Landroid/bluetooth/IBluetoothMapClient$Stub;->TRANSACTION_getDevicesMatchingConnectionStates:I
-Landroid/bluetooth/IBluetoothMapClient$Stub;->TRANSACTION_getPriority:I
-Landroid/bluetooth/IBluetoothMapClient$Stub;->TRANSACTION_getUnreadMessages:I
-Landroid/bluetooth/IBluetoothMapClient$Stub;->TRANSACTION_isConnected:I
-Landroid/bluetooth/IBluetoothMapClient$Stub;->TRANSACTION_sendMessage:I
-Landroid/bluetooth/IBluetoothMapClient$Stub;->TRANSACTION_setPriority:I
-Landroid/bluetooth/IBluetoothMapClient;->connect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothMapClient;->disconnect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothMapClient;->getConnectedDevices()Ljava/util/List;
-Landroid/bluetooth/IBluetoothMapClient;->getConnectionState(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothMapClient;->getDevicesMatchingConnectionStates([I)Ljava/util/List;
-Landroid/bluetooth/IBluetoothMapClient;->getPriority(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothMapClient;->getUnreadMessages(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothMapClient;->isConnected(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothMapClient;->sendMessage(Landroid/bluetooth/BluetoothDevice;[Landroid/net/Uri;Ljava/lang/String;Landroid/app/PendingIntent;Landroid/app/PendingIntent;)Z
-Landroid/bluetooth/IBluetoothMapClient;->setPriority(Landroid/bluetooth/BluetoothDevice;I)Z
-Landroid/bluetooth/IBluetoothPan$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/bluetooth/IBluetoothPan$Stub$Proxy;->connect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothPan$Stub$Proxy;->disconnect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothPan$Stub$Proxy;->getConnectedDevices()Ljava/util/List;
-Landroid/bluetooth/IBluetoothPan$Stub$Proxy;->getConnectionState(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothPan$Stub$Proxy;->getDevicesMatchingConnectionStates([I)Ljava/util/List;
-Landroid/bluetooth/IBluetoothPan$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
-Landroid/bluetooth/IBluetoothPan$Stub$Proxy;->isTetheringOn()Z
-Landroid/bluetooth/IBluetoothPan$Stub$Proxy;->mRemote:Landroid/os/IBinder;
-Landroid/bluetooth/IBluetoothPan$Stub$Proxy;->setBluetoothTethering(Z)V
-Landroid/bluetooth/IBluetoothPan$Stub;-><init>()V
-Landroid/bluetooth/IBluetoothPan$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetoothPan;
-Landroid/bluetooth/IBluetoothPan$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/bluetooth/IBluetoothPan$Stub;->TRANSACTION_connect:I
-Landroid/bluetooth/IBluetoothPan$Stub;->TRANSACTION_disconnect:I
-Landroid/bluetooth/IBluetoothPan$Stub;->TRANSACTION_getConnectedDevices:I
-Landroid/bluetooth/IBluetoothPan$Stub;->TRANSACTION_getConnectionState:I
-Landroid/bluetooth/IBluetoothPan$Stub;->TRANSACTION_getDevicesMatchingConnectionStates:I
-Landroid/bluetooth/IBluetoothPan$Stub;->TRANSACTION_isTetheringOn:I
-Landroid/bluetooth/IBluetoothPan$Stub;->TRANSACTION_setBluetoothTethering:I
-Landroid/bluetooth/IBluetoothPan;->connect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothPan;->disconnect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothPan;->getConnectedDevices()Ljava/util/List;
-Landroid/bluetooth/IBluetoothPan;->getConnectionState(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothPan;->getDevicesMatchingConnectionStates([I)Ljava/util/List;
-Landroid/bluetooth/IBluetoothPan;->isTetheringOn()Z
-Landroid/bluetooth/IBluetoothPan;->setBluetoothTethering(Z)V
-Landroid/bluetooth/IBluetoothPbap$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/bluetooth/IBluetoothPbap$Stub$Proxy;->disconnect(Landroid/bluetooth/BluetoothDevice;)V
-Landroid/bluetooth/IBluetoothPbap$Stub$Proxy;->getConnectedDevices()Ljava/util/List;
-Landroid/bluetooth/IBluetoothPbap$Stub$Proxy;->getConnectionState(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothPbap$Stub$Proxy;->getDevicesMatchingConnectionStates([I)Ljava/util/List;
-Landroid/bluetooth/IBluetoothPbap$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
-Landroid/bluetooth/IBluetoothPbap$Stub$Proxy;->mRemote:Landroid/os/IBinder;
-Landroid/bluetooth/IBluetoothPbap$Stub;-><init>()V
-Landroid/bluetooth/IBluetoothPbap$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/bluetooth/IBluetoothPbap$Stub;->TRANSACTION_disconnect:I
-Landroid/bluetooth/IBluetoothPbap$Stub;->TRANSACTION_getConnectedDevices:I
-Landroid/bluetooth/IBluetoothPbap$Stub;->TRANSACTION_getConnectionState:I
-Landroid/bluetooth/IBluetoothPbap$Stub;->TRANSACTION_getDevicesMatchingConnectionStates:I
-Landroid/bluetooth/IBluetoothPbap;->disconnect(Landroid/bluetooth/BluetoothDevice;)V
-Landroid/bluetooth/IBluetoothPbap;->getConnectedDevices()Ljava/util/List;
-Landroid/bluetooth/IBluetoothPbap;->getConnectionState(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothPbap;->getDevicesMatchingConnectionStates([I)Ljava/util/List;
-Landroid/bluetooth/IBluetoothPbapClient$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/bluetooth/IBluetoothPbapClient$Stub$Proxy;->connect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothPbapClient$Stub$Proxy;->disconnect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothPbapClient$Stub$Proxy;->getConnectedDevices()Ljava/util/List;
-Landroid/bluetooth/IBluetoothPbapClient$Stub$Proxy;->getConnectionState(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothPbapClient$Stub$Proxy;->getDevicesMatchingConnectionStates([I)Ljava/util/List;
-Landroid/bluetooth/IBluetoothPbapClient$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
-Landroid/bluetooth/IBluetoothPbapClient$Stub$Proxy;->getPriority(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothPbapClient$Stub$Proxy;->mRemote:Landroid/os/IBinder;
-Landroid/bluetooth/IBluetoothPbapClient$Stub$Proxy;->setPriority(Landroid/bluetooth/BluetoothDevice;I)Z
-Landroid/bluetooth/IBluetoothPbapClient$Stub;-><init>()V
-Landroid/bluetooth/IBluetoothPbapClient$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetoothPbapClient;
-Landroid/bluetooth/IBluetoothPbapClient$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/bluetooth/IBluetoothPbapClient$Stub;->TRANSACTION_connect:I
-Landroid/bluetooth/IBluetoothPbapClient$Stub;->TRANSACTION_disconnect:I
-Landroid/bluetooth/IBluetoothPbapClient$Stub;->TRANSACTION_getConnectedDevices:I
-Landroid/bluetooth/IBluetoothPbapClient$Stub;->TRANSACTION_getConnectionState:I
-Landroid/bluetooth/IBluetoothPbapClient$Stub;->TRANSACTION_getDevicesMatchingConnectionStates:I
-Landroid/bluetooth/IBluetoothPbapClient$Stub;->TRANSACTION_getPriority:I
-Landroid/bluetooth/IBluetoothPbapClient$Stub;->TRANSACTION_setPriority:I
-Landroid/bluetooth/IBluetoothPbapClient;->connect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothPbapClient;->disconnect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothPbapClient;->getConnectedDevices()Ljava/util/List;
-Landroid/bluetooth/IBluetoothPbapClient;->getConnectionState(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothPbapClient;->getDevicesMatchingConnectionStates([I)Ljava/util/List;
-Landroid/bluetooth/IBluetoothPbapClient;->getPriority(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothPbapClient;->setPriority(Landroid/bluetooth/BluetoothDevice;I)Z
-Landroid/bluetooth/IBluetoothProfileServiceConnection$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/bluetooth/IBluetoothProfileServiceConnection$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
-Landroid/bluetooth/IBluetoothProfileServiceConnection$Stub$Proxy;->mRemote:Landroid/os/IBinder;
-Landroid/bluetooth/IBluetoothProfileServiceConnection$Stub$Proxy;->onServiceConnected(Landroid/content/ComponentName;Landroid/os/IBinder;)V
-Landroid/bluetooth/IBluetoothProfileServiceConnection$Stub$Proxy;->onServiceDisconnected(Landroid/content/ComponentName;)V
-Landroid/bluetooth/IBluetoothProfileServiceConnection$Stub;-><init>()V
-Landroid/bluetooth/IBluetoothProfileServiceConnection$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetoothProfileServiceConnection;
-Landroid/bluetooth/IBluetoothProfileServiceConnection$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/bluetooth/IBluetoothProfileServiceConnection$Stub;->TRANSACTION_onServiceConnected:I
-Landroid/bluetooth/IBluetoothProfileServiceConnection$Stub;->TRANSACTION_onServiceDisconnected:I
-Landroid/bluetooth/IBluetoothProfileServiceConnection;->onServiceConnected(Landroid/content/ComponentName;Landroid/os/IBinder;)V
-Landroid/bluetooth/IBluetoothProfileServiceConnection;->onServiceDisconnected(Landroid/content/ComponentName;)V
-Landroid/bluetooth/IBluetoothSap$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/bluetooth/IBluetoothSap$Stub$Proxy;->connect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothSap$Stub$Proxy;->disconnect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothSap$Stub$Proxy;->getClient()Landroid/bluetooth/BluetoothDevice;
-Landroid/bluetooth/IBluetoothSap$Stub$Proxy;->getConnectedDevices()Ljava/util/List;
-Landroid/bluetooth/IBluetoothSap$Stub$Proxy;->getConnectionState(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothSap$Stub$Proxy;->getDevicesMatchingConnectionStates([I)Ljava/util/List;
-Landroid/bluetooth/IBluetoothSap$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
-Landroid/bluetooth/IBluetoothSap$Stub$Proxy;->getPriority(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothSap$Stub$Proxy;->getState()I
-Landroid/bluetooth/IBluetoothSap$Stub$Proxy;->isConnected(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothSap$Stub$Proxy;->mRemote:Landroid/os/IBinder;
-Landroid/bluetooth/IBluetoothSap$Stub$Proxy;->setPriority(Landroid/bluetooth/BluetoothDevice;I)Z
-Landroid/bluetooth/IBluetoothSap$Stub;-><init>()V
-Landroid/bluetooth/IBluetoothSap$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetoothSap;
-Landroid/bluetooth/IBluetoothSap$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/bluetooth/IBluetoothSap$Stub;->TRANSACTION_connect:I
-Landroid/bluetooth/IBluetoothSap$Stub;->TRANSACTION_disconnect:I
-Landroid/bluetooth/IBluetoothSap$Stub;->TRANSACTION_getClient:I
-Landroid/bluetooth/IBluetoothSap$Stub;->TRANSACTION_getConnectedDevices:I
-Landroid/bluetooth/IBluetoothSap$Stub;->TRANSACTION_getConnectionState:I
-Landroid/bluetooth/IBluetoothSap$Stub;->TRANSACTION_getDevicesMatchingConnectionStates:I
-Landroid/bluetooth/IBluetoothSap$Stub;->TRANSACTION_getPriority:I
-Landroid/bluetooth/IBluetoothSap$Stub;->TRANSACTION_getState:I
-Landroid/bluetooth/IBluetoothSap$Stub;->TRANSACTION_isConnected:I
-Landroid/bluetooth/IBluetoothSap$Stub;->TRANSACTION_setPriority:I
-Landroid/bluetooth/IBluetoothSap;->connect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothSap;->disconnect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothSap;->getClient()Landroid/bluetooth/BluetoothDevice;
-Landroid/bluetooth/IBluetoothSap;->getConnectedDevices()Ljava/util/List;
-Landroid/bluetooth/IBluetoothSap;->getConnectionState(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothSap;->getDevicesMatchingConnectionStates([I)Ljava/util/List;
-Landroid/bluetooth/IBluetoothSap;->getPriority(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetoothSap;->getState()I
-Landroid/bluetooth/IBluetoothSap;->isConnected(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/IBluetoothSap;->setPriority(Landroid/bluetooth/BluetoothDevice;I)Z
-Landroid/bluetooth/IBluetoothSocketManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/bluetooth/IBluetoothSocketManager$Stub$Proxy;->connectSocket(Landroid/bluetooth/BluetoothDevice;ILandroid/os/ParcelUuid;II)Landroid/os/ParcelFileDescriptor;
-Landroid/bluetooth/IBluetoothSocketManager$Stub$Proxy;->createSocketChannel(ILjava/lang/String;Landroid/os/ParcelUuid;II)Landroid/os/ParcelFileDescriptor;
-Landroid/bluetooth/IBluetoothSocketManager$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
-Landroid/bluetooth/IBluetoothSocketManager$Stub$Proxy;->mRemote:Landroid/os/IBinder;
-Landroid/bluetooth/IBluetoothSocketManager$Stub$Proxy;->requestMaximumTxDataLength(Landroid/bluetooth/BluetoothDevice;)V
-Landroid/bluetooth/IBluetoothSocketManager$Stub;-><init>()V
-Landroid/bluetooth/IBluetoothSocketManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetoothSocketManager;
-Landroid/bluetooth/IBluetoothSocketManager$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/bluetooth/IBluetoothSocketManager$Stub;->TRANSACTION_connectSocket:I
-Landroid/bluetooth/IBluetoothSocketManager$Stub;->TRANSACTION_createSocketChannel:I
-Landroid/bluetooth/IBluetoothSocketManager$Stub;->TRANSACTION_requestMaximumTxDataLength:I
-Landroid/bluetooth/IBluetoothSocketManager;->connectSocket(Landroid/bluetooth/BluetoothDevice;ILandroid/os/ParcelUuid;II)Landroid/os/ParcelFileDescriptor;
-Landroid/bluetooth/IBluetoothSocketManager;->createSocketChannel(ILjava/lang/String;Landroid/os/ParcelUuid;II)Landroid/os/ParcelFileDescriptor;
-Landroid/bluetooth/IBluetoothSocketManager;->requestMaximumTxDataLength(Landroid/bluetooth/BluetoothDevice;)V
-Landroid/bluetooth/IBluetoothStateChangeCallback$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/bluetooth/IBluetoothStateChangeCallback$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
-Landroid/bluetooth/IBluetoothStateChangeCallback$Stub$Proxy;->mRemote:Landroid/os/IBinder;
-Landroid/bluetooth/IBluetoothStateChangeCallback$Stub$Proxy;->onBluetoothStateChange(Z)V
-Landroid/bluetooth/IBluetoothStateChangeCallback$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetoothStateChangeCallback;
-Landroid/bluetooth/IBluetoothStateChangeCallback$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/bluetooth/IBluetoothStateChangeCallback$Stub;->TRANSACTION_onBluetoothStateChange:I
-Landroid/bluetooth/IBluetoothStateChangeCallback;->onBluetoothStateChange(Z)V
-Landroid/bluetooth/le/AdvertiseCallback;->ADVERTISE_SUCCESS:I
-Landroid/bluetooth/le/AdvertiseData$Builder;->mIncludeDeviceName:Z
-Landroid/bluetooth/le/AdvertiseData$Builder;->mIncludeTxPowerLevel:Z
-Landroid/bluetooth/le/AdvertiseData$Builder;->mManufacturerSpecificData:Landroid/util/SparseArray;
-Landroid/bluetooth/le/AdvertiseData$Builder;->mServiceData:Ljava/util/Map;
-Landroid/bluetooth/le/AdvertiseData$Builder;->mServiceUuids:Ljava/util/List;
-Landroid/bluetooth/le/AdvertiseData;-><init>(Ljava/util/List;Landroid/util/SparseArray;Ljava/util/Map;ZZ)V
-Landroid/bluetooth/le/AdvertiseData;->mIncludeDeviceName:Z
-Landroid/bluetooth/le/AdvertiseData;->mIncludeTxPowerLevel:Z
-Landroid/bluetooth/le/AdvertiseData;->mManufacturerSpecificData:Landroid/util/SparseArray;
-Landroid/bluetooth/le/AdvertiseData;->mServiceData:Ljava/util/Map;
-Landroid/bluetooth/le/AdvertiseData;->mServiceUuids:Ljava/util/List;
-Landroid/bluetooth/le/AdvertiseSettings$Builder;->mConnectable:Z
-Landroid/bluetooth/le/AdvertiseSettings$Builder;->mMode:I
-Landroid/bluetooth/le/AdvertiseSettings$Builder;->mTimeoutMillis:I
-Landroid/bluetooth/le/AdvertiseSettings$Builder;->mTxPowerLevel:I
-Landroid/bluetooth/le/AdvertiseSettings;-><init>(IIZI)V
-Landroid/bluetooth/le/AdvertiseSettings;-><init>(Landroid/os/Parcel;)V
-Landroid/bluetooth/le/AdvertiseSettings;->LIMITED_ADVERTISING_MAX_MILLIS:I
-Landroid/bluetooth/le/AdvertiseSettings;->mAdvertiseConnectable:Z
-Landroid/bluetooth/le/AdvertiseSettings;->mAdvertiseMode:I
-Landroid/bluetooth/le/AdvertiseSettings;->mAdvertiseTimeoutMillis:I
-Landroid/bluetooth/le/AdvertiseSettings;->mAdvertiseTxPowerLevel:I
-Landroid/bluetooth/le/AdvertisingSet;-><init>(ILandroid/bluetooth/IBluetoothManager;)V
-Landroid/bluetooth/le/AdvertisingSet;->getAdvertiserId()I
-Landroid/bluetooth/le/AdvertisingSet;->getOwnAddress()V
-Landroid/bluetooth/le/AdvertisingSet;->mAdvertiserId:I
-Landroid/bluetooth/le/AdvertisingSet;->mGatt:Landroid/bluetooth/IBluetoothGatt;
-Landroid/bluetooth/le/AdvertisingSet;->setAdvertiserId(I)V
-Landroid/bluetooth/le/AdvertisingSet;->TAG:Ljava/lang/String;
-Landroid/bluetooth/le/AdvertisingSetCallback;->onOwnAddressRead(Landroid/bluetooth/le/AdvertisingSet;ILjava/lang/String;)V
-Landroid/bluetooth/le/AdvertisingSetParameters$Builder;->mConnectable:Z
-Landroid/bluetooth/le/AdvertisingSetParameters$Builder;->mIncludeTxPower:Z
-Landroid/bluetooth/le/AdvertisingSetParameters$Builder;->mInterval:I
-Landroid/bluetooth/le/AdvertisingSetParameters$Builder;->mIsAnonymous:Z
-Landroid/bluetooth/le/AdvertisingSetParameters$Builder;->mIsLegacy:Z
-Landroid/bluetooth/le/AdvertisingSetParameters$Builder;->mPrimaryPhy:I
-Landroid/bluetooth/le/AdvertisingSetParameters$Builder;->mScannable:Z
-Landroid/bluetooth/le/AdvertisingSetParameters$Builder;->mSecondaryPhy:I
-Landroid/bluetooth/le/AdvertisingSetParameters$Builder;->mTxPowerLevel:I
-Landroid/bluetooth/le/AdvertisingSetParameters;-><init>(Landroid/os/Parcel;)V
-Landroid/bluetooth/le/AdvertisingSetParameters;-><init>(ZZZZZIIII)V
-Landroid/bluetooth/le/AdvertisingSetParameters;->LIMITED_ADVERTISING_MAX_MILLIS:I
-Landroid/bluetooth/le/AdvertisingSetParameters;->mConnectable:Z
-Landroid/bluetooth/le/AdvertisingSetParameters;->mIncludeTxPower:Z
-Landroid/bluetooth/le/AdvertisingSetParameters;->mInterval:I
-Landroid/bluetooth/le/AdvertisingSetParameters;->mIsAnonymous:Z
-Landroid/bluetooth/le/AdvertisingSetParameters;->mIsLegacy:Z
-Landroid/bluetooth/le/AdvertisingSetParameters;->mPrimaryPhy:I
-Landroid/bluetooth/le/AdvertisingSetParameters;->mScannable:Z
-Landroid/bluetooth/le/AdvertisingSetParameters;->mSecondaryPhy:I
-Landroid/bluetooth/le/AdvertisingSetParameters;->mTxPowerLevel:I
-Landroid/bluetooth/le/BluetoothLeAdvertiser;-><init>(Landroid/bluetooth/IBluetoothManager;)V
-Landroid/bluetooth/le/BluetoothLeAdvertiser;->byteLength([B)I
-Landroid/bluetooth/le/BluetoothLeAdvertiser;->cleanup()V
-Landroid/bluetooth/le/BluetoothLeAdvertiser;->FLAGS_FIELD_BYTES:I
-Landroid/bluetooth/le/BluetoothLeAdvertiser;->mAdvertisingSets:Ljava/util/Map;
-Landroid/bluetooth/le/BluetoothLeAdvertiser;->MANUFACTURER_SPECIFIC_DATA_LENGTH:I
-Landroid/bluetooth/le/BluetoothLeAdvertiser;->MAX_ADVERTISING_DATA_BYTES:I
-Landroid/bluetooth/le/BluetoothLeAdvertiser;->MAX_LEGACY_ADVERTISING_DATA_BYTES:I
-Landroid/bluetooth/le/BluetoothLeAdvertiser;->mBluetoothAdapter:Landroid/bluetooth/BluetoothAdapter;
-Landroid/bluetooth/le/BluetoothLeAdvertiser;->mBluetoothManager:Landroid/bluetooth/IBluetoothManager;
-Landroid/bluetooth/le/BluetoothLeAdvertiser;->mCallbackWrappers:Ljava/util/Map;
-Landroid/bluetooth/le/BluetoothLeAdvertiser;->mHandler:Landroid/os/Handler;
-Landroid/bluetooth/le/BluetoothLeAdvertiser;->mLegacyAdvertisers:Ljava/util/Map;
-Landroid/bluetooth/le/BluetoothLeAdvertiser;->OVERHEAD_BYTES_PER_FIELD:I
-Landroid/bluetooth/le/BluetoothLeAdvertiser;->postStartFailure(Landroid/bluetooth/le/AdvertiseCallback;I)V
-Landroid/bluetooth/le/BluetoothLeAdvertiser;->postStartSetFailure(Landroid/os/Handler;Landroid/bluetooth/le/AdvertisingSetCallback;I)V
-Landroid/bluetooth/le/BluetoothLeAdvertiser;->postStartSuccess(Landroid/bluetooth/le/AdvertiseCallback;Landroid/bluetooth/le/AdvertiseSettings;)V
-Landroid/bluetooth/le/BluetoothLeAdvertiser;->TAG:Ljava/lang/String;
-Landroid/bluetooth/le/BluetoothLeAdvertiser;->totalBytes(Landroid/bluetooth/le/AdvertiseData;Z)I
-Landroid/bluetooth/le/BluetoothLeAdvertiser;->wrap(Landroid/bluetooth/le/AdvertisingSetCallback;Landroid/os/Handler;)Landroid/bluetooth/le/IAdvertisingSetCallback;
-Landroid/bluetooth/le/BluetoothLeAdvertiser;->wrapOldCallback(Landroid/bluetooth/le/AdvertiseCallback;Landroid/bluetooth/le/AdvertiseSettings;)Landroid/bluetooth/le/AdvertisingSetCallback;
-Landroid/bluetooth/le/BluetoothLeScanner$BleScanCallbackWrapper;->flushPendingBatchResults()V
-Landroid/bluetooth/le/BluetoothLeScanner$BleScanCallbackWrapper;->mBluetoothGatt:Landroid/bluetooth/IBluetoothGatt;
-Landroid/bluetooth/le/BluetoothLeScanner$BleScanCallbackWrapper;->mFilters:Ljava/util/List;
-Landroid/bluetooth/le/BluetoothLeScanner$BleScanCallbackWrapper;->mResultStorages:Ljava/util/List;
-Landroid/bluetooth/le/BluetoothLeScanner$BleScanCallbackWrapper;->mScanCallback:Landroid/bluetooth/le/ScanCallback;
-Landroid/bluetooth/le/BluetoothLeScanner$BleScanCallbackWrapper;->mScannerId:I
-Landroid/bluetooth/le/BluetoothLeScanner$BleScanCallbackWrapper;->mSettings:Landroid/bluetooth/le/ScanSettings;
-Landroid/bluetooth/le/BluetoothLeScanner$BleScanCallbackWrapper;->mWorkSource:Landroid/os/WorkSource;
-Landroid/bluetooth/le/BluetoothLeScanner$BleScanCallbackWrapper;->onBatchScanResults(Ljava/util/List;)V
-Landroid/bluetooth/le/BluetoothLeScanner$BleScanCallbackWrapper;->onFoundOrLost(ZLandroid/bluetooth/le/ScanResult;)V
-Landroid/bluetooth/le/BluetoothLeScanner$BleScanCallbackWrapper;->onScanManagerErrorCallback(I)V
-Landroid/bluetooth/le/BluetoothLeScanner$BleScanCallbackWrapper;->onScannerRegistered(II)V
-Landroid/bluetooth/le/BluetoothLeScanner$BleScanCallbackWrapper;->onScanResult(Landroid/bluetooth/le/ScanResult;)V
-Landroid/bluetooth/le/BluetoothLeScanner$BleScanCallbackWrapper;->REGISTRATION_CALLBACK_TIMEOUT_MILLIS:I
-Landroid/bluetooth/le/BluetoothLeScanner$BleScanCallbackWrapper;->startRegistration()V
-Landroid/bluetooth/le/BluetoothLeScanner$BleScanCallbackWrapper;->stopLeScan()V
-Landroid/bluetooth/le/BluetoothLeScanner;-><init>(Landroid/bluetooth/IBluetoothManager;)V
-Landroid/bluetooth/le/BluetoothLeScanner;->cleanup()V
-Landroid/bluetooth/le/BluetoothLeScanner;->DBG:Z
-Landroid/bluetooth/le/BluetoothLeScanner;->isHardwareResourcesAvailableForScan(Landroid/bluetooth/le/ScanSettings;)Z
-Landroid/bluetooth/le/BluetoothLeScanner;->isSettingsAndFilterComboAllowed(Landroid/bluetooth/le/ScanSettings;Ljava/util/List;)Z
-Landroid/bluetooth/le/BluetoothLeScanner;->isSettingsConfigAllowedForScan(Landroid/bluetooth/le/ScanSettings;)Z
-Landroid/bluetooth/le/BluetoothLeScanner;->mBluetoothAdapter:Landroid/bluetooth/BluetoothAdapter;
-Landroid/bluetooth/le/BluetoothLeScanner;->mBluetoothManager:Landroid/bluetooth/IBluetoothManager;
-Landroid/bluetooth/le/BluetoothLeScanner;->mHandler:Landroid/os/Handler;
-Landroid/bluetooth/le/BluetoothLeScanner;->mLeScanClients:Ljava/util/Map;
-Landroid/bluetooth/le/BluetoothLeScanner;->postCallbackError(Landroid/bluetooth/le/ScanCallback;I)V
-Landroid/bluetooth/le/BluetoothLeScanner;->postCallbackErrorOrReturn(Landroid/bluetooth/le/ScanCallback;I)I
-Landroid/bluetooth/le/BluetoothLeScanner;->startScan(Ljava/util/List;Landroid/bluetooth/le/ScanSettings;Landroid/os/WorkSource;Landroid/bluetooth/le/ScanCallback;Landroid/app/PendingIntent;Ljava/util/List;)I
-Landroid/bluetooth/le/BluetoothLeScanner;->TAG:Ljava/lang/String;
-Landroid/bluetooth/le/BluetoothLeScanner;->VDBG:Z
-Landroid/bluetooth/le/BluetoothLeUtils;-><init>()V
-Landroid/bluetooth/le/BluetoothLeUtils;->checkAdapterStateOn(Landroid/bluetooth/BluetoothAdapter;)V
-Landroid/bluetooth/le/BluetoothLeUtils;->equals(Landroid/util/SparseArray;Landroid/util/SparseArray;)Z
-Landroid/bluetooth/le/BluetoothLeUtils;->equals(Ljava/util/Map;Ljava/util/Map;)Z
-Landroid/bluetooth/le/BluetoothLeUtils;->toString(Landroid/util/SparseArray;)Ljava/lang/String;
-Landroid/bluetooth/le/BluetoothLeUtils;->toString(Ljava/util/Map;)Ljava/lang/String;
-Landroid/bluetooth/le/IAdvertisingSetCallback$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/bluetooth/le/IAdvertisingSetCallback$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
-Landroid/bluetooth/le/IAdvertisingSetCallback$Stub$Proxy;->mRemote:Landroid/os/IBinder;
-Landroid/bluetooth/le/IAdvertisingSetCallback$Stub$Proxy;->onAdvertisingDataSet(II)V
-Landroid/bluetooth/le/IAdvertisingSetCallback$Stub$Proxy;->onAdvertisingEnabled(IZI)V
-Landroid/bluetooth/le/IAdvertisingSetCallback$Stub$Proxy;->onAdvertisingParametersUpdated(III)V
-Landroid/bluetooth/le/IAdvertisingSetCallback$Stub$Proxy;->onAdvertisingSetStarted(III)V
-Landroid/bluetooth/le/IAdvertisingSetCallback$Stub$Proxy;->onAdvertisingSetStopped(I)V
-Landroid/bluetooth/le/IAdvertisingSetCallback$Stub$Proxy;->onOwnAddressRead(IILjava/lang/String;)V
-Landroid/bluetooth/le/IAdvertisingSetCallback$Stub$Proxy;->onPeriodicAdvertisingDataSet(II)V
-Landroid/bluetooth/le/IAdvertisingSetCallback$Stub$Proxy;->onPeriodicAdvertisingEnabled(IZI)V
-Landroid/bluetooth/le/IAdvertisingSetCallback$Stub$Proxy;->onPeriodicAdvertisingParametersUpdated(II)V
-Landroid/bluetooth/le/IAdvertisingSetCallback$Stub$Proxy;->onScanResponseDataSet(II)V
-Landroid/bluetooth/le/IAdvertisingSetCallback$Stub;-><init>()V
-Landroid/bluetooth/le/IAdvertisingSetCallback$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/le/IAdvertisingSetCallback;
-Landroid/bluetooth/le/IAdvertisingSetCallback$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/bluetooth/le/IAdvertisingSetCallback$Stub;->TRANSACTION_onAdvertisingDataSet:I
-Landroid/bluetooth/le/IAdvertisingSetCallback$Stub;->TRANSACTION_onAdvertisingEnabled:I
-Landroid/bluetooth/le/IAdvertisingSetCallback$Stub;->TRANSACTION_onAdvertisingParametersUpdated:I
-Landroid/bluetooth/le/IAdvertisingSetCallback$Stub;->TRANSACTION_onAdvertisingSetStarted:I
-Landroid/bluetooth/le/IAdvertisingSetCallback$Stub;->TRANSACTION_onAdvertisingSetStopped:I
-Landroid/bluetooth/le/IAdvertisingSetCallback$Stub;->TRANSACTION_onOwnAddressRead:I
-Landroid/bluetooth/le/IAdvertisingSetCallback$Stub;->TRANSACTION_onPeriodicAdvertisingDataSet:I
-Landroid/bluetooth/le/IAdvertisingSetCallback$Stub;->TRANSACTION_onPeriodicAdvertisingEnabled:I
-Landroid/bluetooth/le/IAdvertisingSetCallback$Stub;->TRANSACTION_onPeriodicAdvertisingParametersUpdated:I
-Landroid/bluetooth/le/IAdvertisingSetCallback$Stub;->TRANSACTION_onScanResponseDataSet:I
-Landroid/bluetooth/le/IAdvertisingSetCallback;->onAdvertisingDataSet(II)V
-Landroid/bluetooth/le/IAdvertisingSetCallback;->onAdvertisingEnabled(IZI)V
-Landroid/bluetooth/le/IAdvertisingSetCallback;->onAdvertisingParametersUpdated(III)V
-Landroid/bluetooth/le/IAdvertisingSetCallback;->onAdvertisingSetStarted(III)V
-Landroid/bluetooth/le/IAdvertisingSetCallback;->onAdvertisingSetStopped(I)V
-Landroid/bluetooth/le/IAdvertisingSetCallback;->onOwnAddressRead(IILjava/lang/String;)V
-Landroid/bluetooth/le/IAdvertisingSetCallback;->onPeriodicAdvertisingDataSet(II)V
-Landroid/bluetooth/le/IAdvertisingSetCallback;->onPeriodicAdvertisingEnabled(IZI)V
-Landroid/bluetooth/le/IAdvertisingSetCallback;->onPeriodicAdvertisingParametersUpdated(II)V
-Landroid/bluetooth/le/IAdvertisingSetCallback;->onScanResponseDataSet(II)V
-Landroid/bluetooth/le/IPeriodicAdvertisingCallback$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/bluetooth/le/IPeriodicAdvertisingCallback$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
-Landroid/bluetooth/le/IPeriodicAdvertisingCallback$Stub$Proxy;->mRemote:Landroid/os/IBinder;
-Landroid/bluetooth/le/IPeriodicAdvertisingCallback$Stub$Proxy;->onPeriodicAdvertisingReport(Landroid/bluetooth/le/PeriodicAdvertisingReport;)V
-Landroid/bluetooth/le/IPeriodicAdvertisingCallback$Stub$Proxy;->onSyncEstablished(ILandroid/bluetooth/BluetoothDevice;IIII)V
-Landroid/bluetooth/le/IPeriodicAdvertisingCallback$Stub$Proxy;->onSyncLost(I)V
-Landroid/bluetooth/le/IPeriodicAdvertisingCallback$Stub;-><init>()V
-Landroid/bluetooth/le/IPeriodicAdvertisingCallback$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/le/IPeriodicAdvertisingCallback;
-Landroid/bluetooth/le/IPeriodicAdvertisingCallback$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/bluetooth/le/IPeriodicAdvertisingCallback$Stub;->TRANSACTION_onPeriodicAdvertisingReport:I
-Landroid/bluetooth/le/IPeriodicAdvertisingCallback$Stub;->TRANSACTION_onSyncEstablished:I
-Landroid/bluetooth/le/IPeriodicAdvertisingCallback$Stub;->TRANSACTION_onSyncLost:I
-Landroid/bluetooth/le/IPeriodicAdvertisingCallback;->onPeriodicAdvertisingReport(Landroid/bluetooth/le/PeriodicAdvertisingReport;)V
-Landroid/bluetooth/le/IPeriodicAdvertisingCallback;->onSyncEstablished(ILandroid/bluetooth/BluetoothDevice;IIII)V
-Landroid/bluetooth/le/IPeriodicAdvertisingCallback;->onSyncLost(I)V
-Landroid/bluetooth/le/IScannerCallback$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/bluetooth/le/IScannerCallback$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
-Landroid/bluetooth/le/IScannerCallback$Stub$Proxy;->mRemote:Landroid/os/IBinder;
-Landroid/bluetooth/le/IScannerCallback$Stub$Proxy;->onBatchScanResults(Ljava/util/List;)V
-Landroid/bluetooth/le/IScannerCallback$Stub$Proxy;->onFoundOrLost(ZLandroid/bluetooth/le/ScanResult;)V
-Landroid/bluetooth/le/IScannerCallback$Stub$Proxy;->onScanManagerErrorCallback(I)V
-Landroid/bluetooth/le/IScannerCallback$Stub$Proxy;->onScannerRegistered(II)V
-Landroid/bluetooth/le/IScannerCallback$Stub$Proxy;->onScanResult(Landroid/bluetooth/le/ScanResult;)V
-Landroid/bluetooth/le/IScannerCallback$Stub;-><init>()V
-Landroid/bluetooth/le/IScannerCallback$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/le/IScannerCallback;
-Landroid/bluetooth/le/IScannerCallback$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/bluetooth/le/IScannerCallback$Stub;->TRANSACTION_onBatchScanResults:I
-Landroid/bluetooth/le/IScannerCallback$Stub;->TRANSACTION_onFoundOrLost:I
-Landroid/bluetooth/le/IScannerCallback$Stub;->TRANSACTION_onScanManagerErrorCallback:I
-Landroid/bluetooth/le/IScannerCallback$Stub;->TRANSACTION_onScannerRegistered:I
-Landroid/bluetooth/le/IScannerCallback$Stub;->TRANSACTION_onScanResult:I
-Landroid/bluetooth/le/IScannerCallback;->onBatchScanResults(Ljava/util/List;)V
-Landroid/bluetooth/le/IScannerCallback;->onFoundOrLost(ZLandroid/bluetooth/le/ScanResult;)V
-Landroid/bluetooth/le/IScannerCallback;->onScanManagerErrorCallback(I)V
-Landroid/bluetooth/le/IScannerCallback;->onScannerRegistered(II)V
-Landroid/bluetooth/le/IScannerCallback;->onScanResult(Landroid/bluetooth/le/ScanResult;)V
-Landroid/bluetooth/le/PeriodicAdvertisingCallback;-><init>()V
-Landroid/bluetooth/le/PeriodicAdvertisingCallback;->onPeriodicAdvertisingReport(Landroid/bluetooth/le/PeriodicAdvertisingReport;)V
-Landroid/bluetooth/le/PeriodicAdvertisingCallback;->onSyncEstablished(ILandroid/bluetooth/BluetoothDevice;IIII)V
-Landroid/bluetooth/le/PeriodicAdvertisingCallback;->onSyncLost(I)V
-Landroid/bluetooth/le/PeriodicAdvertisingCallback;->SYNC_NO_RESOURCES:I
-Landroid/bluetooth/le/PeriodicAdvertisingCallback;->SYNC_NO_RESPONSE:I
-Landroid/bluetooth/le/PeriodicAdvertisingCallback;->SYNC_SUCCESS:I
-Landroid/bluetooth/le/PeriodicAdvertisingManager;-><init>(Landroid/bluetooth/IBluetoothManager;)V
-Landroid/bluetooth/le/PeriodicAdvertisingManager;->mBluetoothAdapter:Landroid/bluetooth/BluetoothAdapter;
-Landroid/bluetooth/le/PeriodicAdvertisingManager;->mBluetoothManager:Landroid/bluetooth/IBluetoothManager;
-Landroid/bluetooth/le/PeriodicAdvertisingManager;->mCallbackWrappers:Ljava/util/Map;
-Landroid/bluetooth/le/PeriodicAdvertisingManager;->registerSync(Landroid/bluetooth/le/ScanResult;IILandroid/bluetooth/le/PeriodicAdvertisingCallback;)V
-Landroid/bluetooth/le/PeriodicAdvertisingManager;->registerSync(Landroid/bluetooth/le/ScanResult;IILandroid/bluetooth/le/PeriodicAdvertisingCallback;Landroid/os/Handler;)V
-Landroid/bluetooth/le/PeriodicAdvertisingManager;->SKIP_MAX:I
-Landroid/bluetooth/le/PeriodicAdvertisingManager;->SKIP_MIN:I
-Landroid/bluetooth/le/PeriodicAdvertisingManager;->SYNC_STARTING:I
-Landroid/bluetooth/le/PeriodicAdvertisingManager;->TAG:Ljava/lang/String;
-Landroid/bluetooth/le/PeriodicAdvertisingManager;->TIMEOUT_MAX:I
-Landroid/bluetooth/le/PeriodicAdvertisingManager;->TIMEOUT_MIN:I
-Landroid/bluetooth/le/PeriodicAdvertisingManager;->unregisterSync(Landroid/bluetooth/le/PeriodicAdvertisingCallback;)V
-Landroid/bluetooth/le/PeriodicAdvertisingManager;->wrap(Landroid/bluetooth/le/PeriodicAdvertisingCallback;Landroid/os/Handler;)Landroid/bluetooth/le/IPeriodicAdvertisingCallback;
-Landroid/bluetooth/le/PeriodicAdvertisingParameters$Builder;->mIncludeTxPower:Z
-Landroid/bluetooth/le/PeriodicAdvertisingParameters$Builder;->mInterval:I
-Landroid/bluetooth/le/PeriodicAdvertisingParameters;-><init>(Landroid/os/Parcel;)V
-Landroid/bluetooth/le/PeriodicAdvertisingParameters;-><init>(ZI)V
-Landroid/bluetooth/le/PeriodicAdvertisingParameters;->INTERVAL_MAX:I
-Landroid/bluetooth/le/PeriodicAdvertisingParameters;->INTERVAL_MIN:I
-Landroid/bluetooth/le/PeriodicAdvertisingParameters;->mIncludeTxPower:Z
-Landroid/bluetooth/le/PeriodicAdvertisingParameters;->mInterval:I
-Landroid/bluetooth/le/PeriodicAdvertisingReport;-><init>(IIIILandroid/bluetooth/le/ScanRecord;)V
-Landroid/bluetooth/le/PeriodicAdvertisingReport;-><init>(Landroid/os/Parcel;)V
-Landroid/bluetooth/le/PeriodicAdvertisingReport;->CREATOR:Landroid/os/Parcelable$Creator;
-Landroid/bluetooth/le/PeriodicAdvertisingReport;->DATA_COMPLETE:I
-Landroid/bluetooth/le/PeriodicAdvertisingReport;->DATA_INCOMPLETE_TRUNCATED:I
-Landroid/bluetooth/le/PeriodicAdvertisingReport;->getData()Landroid/bluetooth/le/ScanRecord;
-Landroid/bluetooth/le/PeriodicAdvertisingReport;->getDataStatus()I
-Landroid/bluetooth/le/PeriodicAdvertisingReport;->getRssi()I
-Landroid/bluetooth/le/PeriodicAdvertisingReport;->getSyncHandle()I
-Landroid/bluetooth/le/PeriodicAdvertisingReport;->getTimestampNanos()J
-Landroid/bluetooth/le/PeriodicAdvertisingReport;->getTxPower()I
-Landroid/bluetooth/le/PeriodicAdvertisingReport;->mData:Landroid/bluetooth/le/ScanRecord;
-Landroid/bluetooth/le/PeriodicAdvertisingReport;->mDataStatus:I
-Landroid/bluetooth/le/PeriodicAdvertisingReport;->mRssi:I
-Landroid/bluetooth/le/PeriodicAdvertisingReport;->mSyncHandle:I
-Landroid/bluetooth/le/PeriodicAdvertisingReport;->mTimestampNanos:J
-Landroid/bluetooth/le/PeriodicAdvertisingReport;->mTxPower:I
-Landroid/bluetooth/le/PeriodicAdvertisingReport;->readFromParcel(Landroid/os/Parcel;)V
-Landroid/bluetooth/le/ResultStorageDescriptor;-><init>(Landroid/os/Parcel;)V
-Landroid/bluetooth/le/ResultStorageDescriptor;->mLength:I
-Landroid/bluetooth/le/ResultStorageDescriptor;->mOffset:I
-Landroid/bluetooth/le/ResultStorageDescriptor;->mType:I
-Landroid/bluetooth/le/ResultStorageDescriptor;->ReadFromParcel(Landroid/os/Parcel;)V
-Landroid/bluetooth/le/ScanCallback;->NO_ERROR:I
-Landroid/bluetooth/le/ScanCallback;->SCAN_FAILED_OUT_OF_HARDWARE_RESOURCES:I
-Landroid/bluetooth/le/ScanCallback;->SCAN_FAILED_SCANNING_TOO_FREQUENTLY:I
-Landroid/bluetooth/le/ScanFilter$Builder;->mDeviceAddress:Ljava/lang/String;
-Landroid/bluetooth/le/ScanFilter$Builder;->mDeviceName:Ljava/lang/String;
-Landroid/bluetooth/le/ScanFilter$Builder;->mManufacturerData:[B
-Landroid/bluetooth/le/ScanFilter$Builder;->mManufacturerDataMask:[B
-Landroid/bluetooth/le/ScanFilter$Builder;->mManufacturerId:I
-Landroid/bluetooth/le/ScanFilter$Builder;->mServiceData:[B
-Landroid/bluetooth/le/ScanFilter$Builder;->mServiceDataMask:[B
-Landroid/bluetooth/le/ScanFilter$Builder;->mServiceDataUuid:Landroid/os/ParcelUuid;
-Landroid/bluetooth/le/ScanFilter$Builder;->mServiceUuid:Landroid/os/ParcelUuid;
-Landroid/bluetooth/le/ScanFilter$Builder;->mUuidMask:Landroid/os/ParcelUuid;
-Landroid/bluetooth/le/ScanFilter;-><init>(Ljava/lang/String;Ljava/lang/String;Landroid/os/ParcelUuid;Landroid/os/ParcelUuid;Landroid/os/ParcelUuid;[B[BI[B[B)V
-Landroid/bluetooth/le/ScanFilter;->EMPTY:Landroid/bluetooth/le/ScanFilter;
-Landroid/bluetooth/le/ScanFilter;->isAllFieldsEmpty()Z
-Landroid/bluetooth/le/ScanFilter;->matchesPartialData([B[B[B)Z
-Landroid/bluetooth/le/ScanFilter;->matchesServiceUuid(Ljava/util/UUID;Ljava/util/UUID;Ljava/util/UUID;)Z
-Landroid/bluetooth/le/ScanFilter;->matchesServiceUuids(Landroid/os/ParcelUuid;Landroid/os/ParcelUuid;Ljava/util/List;)Z
-Landroid/bluetooth/le/ScanFilter;->mDeviceAddress:Ljava/lang/String;
-Landroid/bluetooth/le/ScanFilter;->mDeviceName:Ljava/lang/String;
-Landroid/bluetooth/le/ScanFilter;->mManufacturerData:[B
-Landroid/bluetooth/le/ScanFilter;->mManufacturerDataMask:[B
-Landroid/bluetooth/le/ScanFilter;->mManufacturerId:I
-Landroid/bluetooth/le/ScanFilter;->mServiceData:[B
-Landroid/bluetooth/le/ScanFilter;->mServiceDataMask:[B
-Landroid/bluetooth/le/ScanFilter;->mServiceDataUuid:Landroid/os/ParcelUuid;
-Landroid/bluetooth/le/ScanFilter;->mServiceUuid:Landroid/os/ParcelUuid;
-Landroid/bluetooth/le/ScanFilter;->mServiceUuidMask:Landroid/os/ParcelUuid;
-Landroid/bluetooth/le/ScanRecord;-><init>(Ljava/util/List;Landroid/util/SparseArray;Ljava/util/Map;IILjava/lang/String;[B)V
-Landroid/bluetooth/le/ScanRecord;->DATA_TYPE_FLAGS:I
-Landroid/bluetooth/le/ScanRecord;->DATA_TYPE_LOCAL_NAME_COMPLETE:I
-Landroid/bluetooth/le/ScanRecord;->DATA_TYPE_LOCAL_NAME_SHORT:I
-Landroid/bluetooth/le/ScanRecord;->DATA_TYPE_MANUFACTURER_SPECIFIC_DATA:I
-Landroid/bluetooth/le/ScanRecord;->DATA_TYPE_SERVICE_DATA_128_BIT:I
-Landroid/bluetooth/le/ScanRecord;->DATA_TYPE_SERVICE_DATA_16_BIT:I
-Landroid/bluetooth/le/ScanRecord;->DATA_TYPE_SERVICE_DATA_32_BIT:I
-Landroid/bluetooth/le/ScanRecord;->DATA_TYPE_SERVICE_UUIDS_128_BIT_COMPLETE:I
-Landroid/bluetooth/le/ScanRecord;->DATA_TYPE_SERVICE_UUIDS_128_BIT_PARTIAL:I
-Landroid/bluetooth/le/ScanRecord;->DATA_TYPE_SERVICE_UUIDS_16_BIT_COMPLETE:I
-Landroid/bluetooth/le/ScanRecord;->DATA_TYPE_SERVICE_UUIDS_16_BIT_PARTIAL:I
-Landroid/bluetooth/le/ScanRecord;->DATA_TYPE_SERVICE_UUIDS_32_BIT_COMPLETE:I
-Landroid/bluetooth/le/ScanRecord;->DATA_TYPE_SERVICE_UUIDS_32_BIT_PARTIAL:I
-Landroid/bluetooth/le/ScanRecord;->DATA_TYPE_TX_POWER_LEVEL:I
-Landroid/bluetooth/le/ScanRecord;->extractBytes([BII)[B
-Landroid/bluetooth/le/ScanRecord;->mAdvertiseFlags:I
-Landroid/bluetooth/le/ScanRecord;->mBytes:[B
-Landroid/bluetooth/le/ScanRecord;->mDeviceName:Ljava/lang/String;
-Landroid/bluetooth/le/ScanRecord;->mManufacturerSpecificData:Landroid/util/SparseArray;
-Landroid/bluetooth/le/ScanRecord;->mServiceData:Ljava/util/Map;
-Landroid/bluetooth/le/ScanRecord;->mServiceUuids:Ljava/util/List;
-Landroid/bluetooth/le/ScanRecord;->mTxPowerLevel:I
-Landroid/bluetooth/le/ScanRecord;->parseServiceUuid([BIIILjava/util/List;)I
-Landroid/bluetooth/le/ScanRecord;->TAG:Ljava/lang/String;
-Landroid/bluetooth/le/ScanResult;-><init>(Landroid/os/Parcel;)V
-Landroid/bluetooth/le/ScanResult;->ET_CONNECTABLE_MASK:I
-Landroid/bluetooth/le/ScanResult;->ET_LEGACY_MASK:I
-Landroid/bluetooth/le/ScanResult;->mAdvertisingSid:I
-Landroid/bluetooth/le/ScanResult;->mDevice:Landroid/bluetooth/BluetoothDevice;
-Landroid/bluetooth/le/ScanResult;->mEventType:I
-Landroid/bluetooth/le/ScanResult;->mPeriodicAdvertisingInterval:I
-Landroid/bluetooth/le/ScanResult;->mPrimaryPhy:I
-Landroid/bluetooth/le/ScanResult;->mRssi:I
-Landroid/bluetooth/le/ScanResult;->mScanRecord:Landroid/bluetooth/le/ScanRecord;
-Landroid/bluetooth/le/ScanResult;->mSecondaryPhy:I
-Landroid/bluetooth/le/ScanResult;->mTimestampNanos:J
-Landroid/bluetooth/le/ScanResult;->mTxPower:I
-Landroid/bluetooth/le/ScanResult;->readFromParcel(Landroid/os/Parcel;)V
-Landroid/bluetooth/le/ScanSettings$Builder;->isValidCallbackType(I)Z
-Landroid/bluetooth/le/ScanSettings$Builder;->mCallbackType:I
-Landroid/bluetooth/le/ScanSettings$Builder;->mLegacy:Z
-Landroid/bluetooth/le/ScanSettings$Builder;->mMatchMode:I
-Landroid/bluetooth/le/ScanSettings$Builder;->mNumOfMatchesPerFilter:I
-Landroid/bluetooth/le/ScanSettings$Builder;->mPhy:I
-Landroid/bluetooth/le/ScanSettings$Builder;->mReportDelayMillis:J
-Landroid/bluetooth/le/ScanSettings$Builder;->mScanMode:I
-Landroid/bluetooth/le/ScanSettings$Builder;->mScanResultType:I
-Landroid/bluetooth/le/ScanSettings;-><init>(IIIJIIZI)V
-Landroid/bluetooth/le/ScanSettings;-><init>(Landroid/os/Parcel;)V
-Landroid/bluetooth/le/ScanSettings;->getMatchMode()I
-Landroid/bluetooth/le/ScanSettings;->getNumOfMatches()I
-Landroid/bluetooth/le/ScanSettings;->mCallbackType:I
-Landroid/bluetooth/le/ScanSettings;->mLegacy:Z
-Landroid/bluetooth/le/ScanSettings;->mMatchMode:I
-Landroid/bluetooth/le/ScanSettings;->mNumOfMatchesPerFilter:I
-Landroid/bluetooth/le/ScanSettings;->mPhy:I
-Landroid/bluetooth/le/ScanSettings;->mReportDelayMillis:J
-Landroid/bluetooth/le/ScanSettings;->mScanMode:I
-Landroid/bluetooth/le/ScanSettings;->mScanResultType:I
-Landroid/bluetooth/le/TruncatedFilter;->mFilter:Landroid/bluetooth/le/ScanFilter;
-Landroid/bluetooth/le/TruncatedFilter;->mStorageDescriptors:Ljava/util/List;
-Landroid/bluetooth/OobData;-><init>()V
-Landroid/bluetooth/OobData;-><init>(Landroid/os/Parcel;)V
-Landroid/bluetooth/OobData;->CREATOR:Landroid/os/Parcelable$Creator;
-Landroid/bluetooth/OobData;->getLeBluetoothDeviceAddress()[B
-Landroid/bluetooth/OobData;->getLeSecureConnectionsConfirmation()[B
-Landroid/bluetooth/OobData;->getLeSecureConnectionsRandom()[B
-Landroid/bluetooth/OobData;->getSecurityManagerTk()[B
-Landroid/bluetooth/OobData;->mLeBluetoothDeviceAddress:[B
-Landroid/bluetooth/OobData;->mLeSecureConnectionsConfirmation:[B
-Landroid/bluetooth/OobData;->mLeSecureConnectionsRandom:[B
-Landroid/bluetooth/OobData;->mSecurityManagerTk:[B
-Landroid/bluetooth/OobData;->setLeBluetoothDeviceAddress([B)V
-Landroid/bluetooth/OobData;->setLeSecureConnectionsConfirmation([B)V
-Landroid/bluetooth/OobData;->setLeSecureConnectionsRandom([B)V
-Landroid/bluetooth/OobData;->setSecurityManagerTk([B)V
-Landroid/bluetooth/SdpMasRecord$MessageType;-><init>()V
-Landroid/bluetooth/SdpMasRecord$MessageType;->EMAIL:I
-Landroid/bluetooth/SdpMasRecord$MessageType;->MMS:I
-Landroid/bluetooth/SdpMasRecord$MessageType;->SMS_CDMA:I
-Landroid/bluetooth/SdpMasRecord$MessageType;->SMS_GSM:I
-Landroid/bluetooth/SdpMasRecord;-><init>(IIIIIILjava/lang/String;)V
-Landroid/bluetooth/SdpMasRecord;-><init>(Landroid/os/Parcel;)V
-Landroid/bluetooth/SdpMasRecord;->CREATOR:Landroid/os/Parcelable$Creator;
-Landroid/bluetooth/SdpMasRecord;->getL2capPsm()I
-Landroid/bluetooth/SdpMasRecord;->getMasInstanceId()I
-Landroid/bluetooth/SdpMasRecord;->getProfileVersion()I
-Landroid/bluetooth/SdpMasRecord;->getRfcommCannelNumber()I
-Landroid/bluetooth/SdpMasRecord;->getServiceName()Ljava/lang/String;
-Landroid/bluetooth/SdpMasRecord;->getSupportedFeatures()I
-Landroid/bluetooth/SdpMasRecord;->getSupportedMessageTypes()I
-Landroid/bluetooth/SdpMasRecord;->mL2capPsm:I
-Landroid/bluetooth/SdpMasRecord;->mMasInstanceId:I
-Landroid/bluetooth/SdpMasRecord;->mProfileVersion:I
-Landroid/bluetooth/SdpMasRecord;->mRfcommChannelNumber:I
-Landroid/bluetooth/SdpMasRecord;->mServiceName:Ljava/lang/String;
-Landroid/bluetooth/SdpMasRecord;->msgSupported(I)Z
-Landroid/bluetooth/SdpMasRecord;->mSupportedFeatures:I
-Landroid/bluetooth/SdpMasRecord;->mSupportedMessageTypes:I
-Landroid/bluetooth/SdpMnsRecord;-><init>(IIIILjava/lang/String;)V
-Landroid/bluetooth/SdpMnsRecord;-><init>(Landroid/os/Parcel;)V
-Landroid/bluetooth/SdpMnsRecord;->CREATOR:Landroid/os/Parcelable$Creator;
-Landroid/bluetooth/SdpMnsRecord;->getL2capPsm()I
-Landroid/bluetooth/SdpMnsRecord;->getProfileVersion()I
-Landroid/bluetooth/SdpMnsRecord;->getRfcommChannelNumber()I
-Landroid/bluetooth/SdpMnsRecord;->getServiceName()Ljava/lang/String;
-Landroid/bluetooth/SdpMnsRecord;->getSupportedFeatures()I
-Landroid/bluetooth/SdpMnsRecord;->mL2capPsm:I
-Landroid/bluetooth/SdpMnsRecord;->mProfileVersion:I
-Landroid/bluetooth/SdpMnsRecord;->mRfcommChannelNumber:I
-Landroid/bluetooth/SdpMnsRecord;->mServiceName:Ljava/lang/String;
-Landroid/bluetooth/SdpMnsRecord;->mSupportedFeatures:I
-Landroid/bluetooth/SdpOppOpsRecord;-><init>(Landroid/os/Parcel;)V
-Landroid/bluetooth/SdpOppOpsRecord;-><init>(Ljava/lang/String;III[B)V
-Landroid/bluetooth/SdpOppOpsRecord;->CREATOR:Landroid/os/Parcelable$Creator;
-Landroid/bluetooth/SdpOppOpsRecord;->getFormatsList()[B
-Landroid/bluetooth/SdpOppOpsRecord;->getL2capPsm()I
-Landroid/bluetooth/SdpOppOpsRecord;->getProfileVersion()I
-Landroid/bluetooth/SdpOppOpsRecord;->getRfcommChannel()I
-Landroid/bluetooth/SdpOppOpsRecord;->getServiceName()Ljava/lang/String;
-Landroid/bluetooth/SdpOppOpsRecord;->mFormatsList:[B
-Landroid/bluetooth/SdpOppOpsRecord;->mL2capPsm:I
-Landroid/bluetooth/SdpOppOpsRecord;->mProfileVersion:I
-Landroid/bluetooth/SdpOppOpsRecord;->mRfcommChannel:I
-Landroid/bluetooth/SdpOppOpsRecord;->mServiceName:Ljava/lang/String;
-Landroid/bluetooth/SdpPseRecord;-><init>(IIIIILjava/lang/String;)V
-Landroid/bluetooth/SdpPseRecord;-><init>(Landroid/os/Parcel;)V
-Landroid/bluetooth/SdpPseRecord;->CREATOR:Landroid/os/Parcelable$Creator;
-Landroid/bluetooth/SdpPseRecord;->getL2capPsm()I
-Landroid/bluetooth/SdpPseRecord;->getProfileVersion()I
-Landroid/bluetooth/SdpPseRecord;->getRfcommChannelNumber()I
-Landroid/bluetooth/SdpPseRecord;->getServiceName()Ljava/lang/String;
-Landroid/bluetooth/SdpPseRecord;->getSupportedFeatures()I
-Landroid/bluetooth/SdpPseRecord;->getSupportedRepositories()I
-Landroid/bluetooth/SdpPseRecord;->mL2capPsm:I
-Landroid/bluetooth/SdpPseRecord;->mProfileVersion:I
-Landroid/bluetooth/SdpPseRecord;->mRfcommChannelNumber:I
-Landroid/bluetooth/SdpPseRecord;->mServiceName:Ljava/lang/String;
-Landroid/bluetooth/SdpPseRecord;->mSupportedFeatures:I
-Landroid/bluetooth/SdpPseRecord;->mSupportedRepositories:I
-Landroid/bluetooth/SdpRecord;-><init>(I[B)V
-Landroid/bluetooth/SdpRecord;-><init>(Landroid/os/Parcel;)V
-Landroid/bluetooth/SdpRecord;->CREATOR:Landroid/os/Parcelable$Creator;
-Landroid/bluetooth/SdpRecord;->getRawData()[B
-Landroid/bluetooth/SdpRecord;->getRawSize()I
-Landroid/bluetooth/SdpRecord;->mRawData:[B
-Landroid/bluetooth/SdpRecord;->mRawSize:I
-Landroid/bluetooth/SdpSapsRecord;-><init>(IILjava/lang/String;)V
-Landroid/bluetooth/SdpSapsRecord;-><init>(Landroid/os/Parcel;)V
-Landroid/bluetooth/SdpSapsRecord;->CREATOR:Landroid/os/Parcelable$Creator;
-Landroid/bluetooth/SdpSapsRecord;->getProfileVersion()I
-Landroid/bluetooth/SdpSapsRecord;->getRfcommCannelNumber()I
-Landroid/bluetooth/SdpSapsRecord;->getServiceName()Ljava/lang/String;
-Landroid/bluetooth/SdpSapsRecord;->mProfileVersion:I
-Landroid/bluetooth/SdpSapsRecord;->mRfcommChannelNumber:I
-Landroid/bluetooth/SdpSapsRecord;->mServiceName:Ljava/lang/String;
-Landroid/bluetooth/UidTraffic;-><init>(I)V
-Landroid/bluetooth/UidTraffic;-><init>(IJJ)V
-Landroid/bluetooth/UidTraffic;-><init>(Landroid/os/Parcel;)V
-Landroid/bluetooth/UidTraffic;->addRxBytes(J)V
-Landroid/bluetooth/UidTraffic;->addTxBytes(J)V
-Landroid/bluetooth/UidTraffic;->CREATOR:Landroid/os/Parcelable$Creator;
-Landroid/bluetooth/UidTraffic;->getRxBytes()J
-Landroid/bluetooth/UidTraffic;->getTxBytes()J
-Landroid/bluetooth/UidTraffic;->getUid()I
-Landroid/bluetooth/UidTraffic;->mAppUid:I
-Landroid/bluetooth/UidTraffic;->mRxBytes:J
-Landroid/bluetooth/UidTraffic;->mTxBytes:J
-Landroid/bluetooth/UidTraffic;->setRxBytes(J)V
-Landroid/bluetooth/UidTraffic;->setTxBytes(J)V
Landroid/companion/AssociationRequest$Builder;->mDeviceFilters:Ljava/util/ArrayList;
Landroid/companion/AssociationRequest$Builder;->mSingleDevice:Z
Landroid/companion/AssociationRequest;-><init>(Landroid/os/Parcel;)V
diff --git a/boot/hiddenapi/hiddenapi-max-target-p.txt b/boot/hiddenapi/hiddenapi-max-target-p.txt
index 351e71d..4a66a7c 100644
--- a/boot/hiddenapi/hiddenapi-max-target-p.txt
+++ b/boot/hiddenapi/hiddenapi-max-target-p.txt
@@ -1,8 +1,6 @@
Landroid/app/IInstrumentationWatcher$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/IInstrumentationWatcher;
Landroid/app/ISearchManager$Stub;-><init>()V
Landroid/app/IUiModeManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/IUiModeManager;
-Landroid/bluetooth/IBluetooth$Stub;-><init>()V
-Landroid/bluetooth/IBluetoothA2dp$Stub;-><init>()V
Landroid/content/IIntentReceiver$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/IIntentReceiver;
Landroid/content/IIntentSender$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/IIntentSender;
Landroid/os/storage/IObbActionListener$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/storage/IObbActionListener;
diff --git a/boot/hiddenapi/hiddenapi-max-target-r-loprio.txt b/boot/hiddenapi/hiddenapi-max-target-r-loprio.txt
index 20d7cc0..dbc3b51 100644
--- a/boot/hiddenapi/hiddenapi-max-target-r-loprio.txt
+++ b/boot/hiddenapi/hiddenapi-max-target-r-loprio.txt
@@ -3,9 +3,6 @@
Landroid/app/IActivityManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/IActivityManager;
Landroid/app/IInstrumentationWatcher$Stub;-><init>()V
Landroid/app/INotificationManager$Stub;->TRANSACTION_enqueueNotificationWithTag:I
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->getConnectionState(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_enable:I
-Landroid/bluetooth/IBluetoothManager$Stub;->TRANSACTION_enable:I
Landroid/companion/ICompanionDeviceDiscoveryService$Stub;-><init>()V
Landroid/content/om/IOverlayManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/om/IOverlayManager;
Landroid/content/pm/IPackageManager$Stub;->TRANSACTION_getApplicationInfo:I
diff --git a/boot/hiddenapi/hiddenapi-unsupported.txt b/boot/hiddenapi/hiddenapi-unsupported.txt
index 033afb6..f619913 100644
--- a/boot/hiddenapi/hiddenapi-unsupported.txt
+++ b/boot/hiddenapi/hiddenapi-unsupported.txt
@@ -62,19 +62,6 @@
Landroid/app/job/IJobService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/job/IJobService;
Landroid/app/trust/ITrustManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/app/usage/IUsageStatsManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/usage/IUsageStatsManager;
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->getAddress()Ljava/lang/String;
-Landroid/bluetooth/IBluetooth$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetooth;
-Landroid/bluetooth/IBluetoothA2dp$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetoothA2dp;
-Landroid/bluetooth/IBluetoothCallback$Stub;-><init>()V
-Landroid/bluetooth/IBluetoothGattCallback$Stub;-><init>()V
-Landroid/bluetooth/IBluetoothGattCallback$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetoothGattCallback;
-Landroid/bluetooth/IBluetoothHeadset$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetoothHeadset;
-Landroid/bluetooth/IBluetoothHidDeviceCallback$Stub;-><init>()V
-Landroid/bluetooth/IBluetoothManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/bluetooth/IBluetoothManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetoothManager;
-Landroid/bluetooth/IBluetoothManagerCallback$Stub;-><init>()V
-Landroid/bluetooth/IBluetoothPbap$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetoothPbap;
-Landroid/bluetooth/IBluetoothStateChangeCallback$Stub;-><init>()V
Landroid/content/IClipboard$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/content/IClipboard$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/IClipboard;
Landroid/content/IContentService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp
index 9c6402a..738b9cf 100644
--- a/cmds/idmap2/tests/IdmapTests.cpp
+++ b/cmds/idmap2/tests/IdmapTests.cpp
@@ -37,7 +37,6 @@
#include "idmap2/Idmap.h"
#include "idmap2/LogInfo.h"
-using android::Res_value;
using ::testing::NotNull;
using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
diff --git a/cmds/idmap2/tests/ResourceMappingTests.cpp b/cmds/idmap2/tests/ResourceMappingTests.cpp
index 5a1d808..32b3d13 100644
--- a/cmds/idmap2/tests/ResourceMappingTests.cpp
+++ b/cmds/idmap2/tests/ResourceMappingTests.cpp
@@ -29,8 +29,6 @@
#include "idmap2/LogInfo.h"
#include "idmap2/ResourceMapping.h"
-using android::Res_value;
-
using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
namespace android::idmap2 {
diff --git a/core/api/current.txt b/core/api/current.txt
index ddfbb44..698c1ce 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -189,6 +189,7 @@
field public static final String START_VIEW_APP_FEATURES = "android.permission.START_VIEW_APP_FEATURES";
field public static final String START_VIEW_PERMISSION_USAGE = "android.permission.START_VIEW_PERMISSION_USAGE";
field public static final String STATUS_BAR = "android.permission.STATUS_BAR";
+ field public static final String SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE = "android.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE";
field public static final String SYSTEM_ALERT_WINDOW = "android.permission.SYSTEM_ALERT_WINDOW";
field public static final String TRANSMIT_IR = "android.permission.TRANSMIT_IR";
field public static final String UNINSTALL_SHORTCUT = "com.android.launcher.permission.UNINSTALL_SHORTCUT";
@@ -3247,7 +3248,7 @@
method public int getNonInteractiveUiTimeoutMillis();
method public android.content.pm.ResolveInfo getResolveInfo();
method public String getSettingsActivityName();
- method @Nullable public String getTileServiceClassName();
+ method @Nullable public String getTileServiceName();
method public boolean isAccessibilityTool();
method public String loadDescription(android.content.pm.PackageManager);
method @Nullable public CharSequence loadIntro(@NonNull android.content.pm.PackageManager);
@@ -5559,11 +5560,11 @@
public final class GameState implements android.os.Parcelable {
ctor public GameState(boolean, int);
- ctor public GameState(boolean, int, @Nullable String, @NonNull android.os.Bundle);
+ ctor public GameState(boolean, int, int, int);
method public int describeContents();
- method @Nullable public String getDescription();
- method @NonNull public android.os.Bundle getMetadata();
+ method public int getLabel();
method public int getMode();
+ method public int getQuality();
method public boolean isLoading();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.GameState> CREATOR;
@@ -5677,6 +5678,7 @@
}
public class KeyguardManager {
+ method @RequiresPermission(android.Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE) public void addKeyguardLockedStateListener(@NonNull java.util.concurrent.Executor, @NonNull android.app.KeyguardManager.KeyguardLockedStateListener);
method @Deprecated public android.content.Intent createConfirmDeviceCredentialIntent(CharSequence, CharSequence);
method @Deprecated @RequiresPermission(android.Manifest.permission.DISABLE_KEYGUARD) public void exitKeyguardSecurely(android.app.KeyguardManager.OnKeyguardExitResult);
method @Deprecated public boolean inKeyguardRestrictedInputMode();
@@ -5685,6 +5687,7 @@
method public boolean isKeyguardLocked();
method public boolean isKeyguardSecure();
method @Deprecated public android.app.KeyguardManager.KeyguardLock newKeyguardLock(String);
+ method @RequiresPermission(android.Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE) public void removeKeyguardLockedStateListener(@NonNull android.app.KeyguardManager.KeyguardLockedStateListener);
method public void requestDismissKeyguard(@NonNull android.app.Activity, @Nullable android.app.KeyguardManager.KeyguardDismissCallback);
}
@@ -5700,6 +5703,10 @@
method @Deprecated @RequiresPermission(android.Manifest.permission.DISABLE_KEYGUARD) public void reenableKeyguard();
}
+ @java.lang.FunctionalInterface public static interface KeyguardManager.KeyguardLockedStateListener {
+ method public void onKeyguardLockedStateChanged(boolean);
+ }
+
@Deprecated public static interface KeyguardManager.OnKeyguardExitResult {
method @Deprecated public void onKeyguardExitResult(boolean);
}
@@ -7383,12 +7390,12 @@
method @NonNull public java.util.List<java.lang.String> getDelegatedScopes(@Nullable android.content.ComponentName, @NonNull String);
method @Nullable public String getDeviceManagerRoleHolderPackageName();
method public CharSequence getDeviceOwnerLockScreenInfo();
- method @Nullable public android.graphics.drawable.Drawable getDrawable(@NonNull String, @NonNull String, @NonNull java.util.concurrent.Callable<android.graphics.drawable.Drawable>);
- method @Nullable public android.graphics.drawable.Drawable getDrawable(@NonNull String, @NonNull String, @NonNull String, @NonNull java.util.concurrent.Callable<android.graphics.drawable.Drawable>);
+ method @Nullable public android.graphics.drawable.Drawable getDrawable(@NonNull String, @NonNull String, @NonNull java.util.function.Supplier<android.graphics.drawable.Drawable>);
+ method @Nullable public android.graphics.drawable.Drawable getDrawable(@NonNull String, @NonNull String, @NonNull String, @NonNull java.util.function.Supplier<android.graphics.drawable.Drawable>);
method @Nullable public android.graphics.drawable.Icon getDrawableAsIcon(@NonNull String, @NonNull String, @NonNull String, @Nullable android.graphics.drawable.Icon);
method @Nullable public android.graphics.drawable.Icon getDrawableAsIcon(@NonNull String, @NonNull String, @Nullable android.graphics.drawable.Icon);
- method @Nullable public android.graphics.drawable.Drawable getDrawableForDensity(@NonNull String, @NonNull String, int, @NonNull java.util.concurrent.Callable<android.graphics.drawable.Drawable>);
- method @Nullable public android.graphics.drawable.Drawable getDrawableForDensity(@NonNull String, @NonNull String, @NonNull String, int, @NonNull java.util.concurrent.Callable<android.graphics.drawable.Drawable>);
+ method @Nullable public android.graphics.drawable.Drawable getDrawableForDensity(@NonNull String, @NonNull String, int, @NonNull java.util.function.Supplier<android.graphics.drawable.Drawable>);
+ method @Nullable public android.graphics.drawable.Drawable getDrawableForDensity(@NonNull String, @NonNull String, @NonNull String, int, @NonNull java.util.function.Supplier<android.graphics.drawable.Drawable>);
method public CharSequence getEndUserSessionMessage(@NonNull android.content.ComponentName);
method @NonNull public String getEnrollmentSpecificId();
method @Nullable public android.app.admin.FactoryResetProtectionPolicy getFactoryResetProtectionPolicy(@Nullable android.content.ComponentName);
@@ -7697,9 +7704,10 @@
field public static final String EXTRA_PROVISIONING_WIFI_SECURITY_TYPE = "android.app.extra.PROVISIONING_WIFI_SECURITY_TYPE";
field public static final String EXTRA_PROVISIONING_WIFI_SSID = "android.app.extra.PROVISIONING_WIFI_SSID";
field public static final String EXTRA_PROVISIONING_WIFI_USER_CERTIFICATE = "android.app.extra.PROVISIONING_WIFI_USER_CERTIFICATE";
- field public static final String EXTRA_RESOURCE_ID = "android.app.extra.RESOURCE_ID";
- field public static final String EXTRA_RESOURCE_TYPE_DRAWABLE = "android.app.extra.RESOURCE_TYPE_DRAWABLE";
- field public static final String EXTRA_RESOURCE_TYPE_STRING = "android.app.extra.RESOURCE_TYPE_STRING";
+ field public static final String EXTRA_RESOURCE_IDS = "android.app.extra.RESOURCE_IDS";
+ field public static final String EXTRA_RESOURCE_TYPE = "android.app.extra.RESOURCE_TYPE";
+ field public static final int EXTRA_RESOURCE_TYPE_DRAWABLE = 1; // 0x1
+ field public static final int EXTRA_RESOURCE_TYPE_STRING = 2; // 0x2
field public static final String EXTRA_RESULT_LAUNCH_INTENT = "android.app.extra.RESULT_LAUNCH_INTENT";
field public static final int FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY = 1; // 0x1
field public static final int FLAG_MANAGED_CAN_ACCESS_PARENT = 2; // 0x2
@@ -10321,7 +10329,6 @@
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";
@@ -14390,6 +14397,8 @@
method @NonNull @Size(min=3) public abstract float[] fromXyz(@NonNull @Size(min=3) float[]);
method @NonNull public static android.graphics.ColorSpace get(@NonNull android.graphics.ColorSpace.Named);
method @IntRange(from=1, to=4) public int getComponentCount();
+ method public int getDataSpace();
+ method @Nullable public static android.graphics.ColorSpace getFromDataSpace(int);
method @IntRange(from=android.graphics.ColorSpace.MIN_ID, to=android.graphics.ColorSpace.MAX_ID) public int getId();
method public abstract float getMaxValue(@IntRange(from=0, to=3) int);
method public abstract float getMinValue(@IntRange(from=0, to=3) int);
@@ -17389,7 +17398,7 @@
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REQUEST_MAX_NUM_OUTPUT_RAW;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REQUEST_PARTIAL_RESULT_COUNT;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Byte> REQUEST_PIPELINE_MAX_DEPTH;
- field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REQUEST_RECOMMENDED_TEN_BIT_DYNAMIC_RANGE_PROFILE;
+ field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Long> REQUEST_RECOMMENDED_TEN_BIT_DYNAMIC_RANGE_PROFILE;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Float> SCALER_AVAILABLE_MAX_DIGITAL_ZOOM;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> SCALER_AVAILABLE_ROTATE_AND_CROP_MODES;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> SCALER_AVAILABLE_STREAM_USE_CASES;
@@ -18109,22 +18118,23 @@
}
public final class DynamicRangeProfiles {
- ctor public DynamicRangeProfiles(@NonNull int[]);
- method @NonNull public java.util.Set<java.lang.Integer> getProfileCaptureRequestConstraints(int);
- method @NonNull public java.util.Set<java.lang.Integer> getSupportedProfiles();
- field public static final int DOLBY_VISION_10B_HDR_OEM = 64; // 0x40
- field public static final int DOLBY_VISION_10B_HDR_OEM_PO = 128; // 0x80
- field public static final int DOLBY_VISION_10B_HDR_REF = 16; // 0x10
- field public static final int DOLBY_VISION_10B_HDR_REF_PO = 32; // 0x20
- field public static final int DOLBY_VISION_8B_HDR_OEM = 1024; // 0x400
- field public static final int DOLBY_VISION_8B_HDR_OEM_PO = 2048; // 0x800
- field public static final int DOLBY_VISION_8B_HDR_REF = 256; // 0x100
- field public static final int DOLBY_VISION_8B_HDR_REF_PO = 512; // 0x200
- field public static final int HDR10 = 4; // 0x4
- field public static final int HDR10_PLUS = 8; // 0x8
- field public static final int HLG10 = 2; // 0x2
- field public static final int PUBLIC_MAX = 4096; // 0x1000
- field public static final int STANDARD = 1; // 0x1
+ ctor public DynamicRangeProfiles(@NonNull long[]);
+ method @NonNull public java.util.Set<java.lang.Long> getProfileCaptureRequestConstraints(long);
+ method @NonNull public java.util.Set<java.lang.Long> getSupportedProfiles();
+ method public boolean isExtraLatencyPresent(long);
+ field public static final long DOLBY_VISION_10B_HDR_OEM = 64L; // 0x40L
+ field public static final long DOLBY_VISION_10B_HDR_OEM_PO = 128L; // 0x80L
+ field public static final long DOLBY_VISION_10B_HDR_REF = 16L; // 0x10L
+ field public static final long DOLBY_VISION_10B_HDR_REF_PO = 32L; // 0x20L
+ field public static final long DOLBY_VISION_8B_HDR_OEM = 1024L; // 0x400L
+ field public static final long DOLBY_VISION_8B_HDR_OEM_PO = 2048L; // 0x800L
+ field public static final long DOLBY_VISION_8B_HDR_REF = 256L; // 0x100L
+ field public static final long DOLBY_VISION_8B_HDR_REF_PO = 512L; // 0x200L
+ field public static final long HDR10 = 4L; // 0x4L
+ field public static final long HDR10_PLUS = 8L; // 0x8L
+ field public static final long HLG10 = 2L; // 0x2L
+ field public static final long PUBLIC_MAX = 4096L; // 0x1000L
+ field public static final long STANDARD = 1L; // 0x1L
}
public final class ExtensionSessionConfiguration {
@@ -18231,7 +18241,7 @@
method @NonNull public static java.util.Collection<android.hardware.camera2.params.OutputConfiguration> createInstancesForMultiResolutionOutput(@NonNull android.hardware.camera2.MultiResolutionImageReader);
method public int describeContents();
method public void enableSurfaceSharing();
- method public int getDynamicRangeProfile();
+ method public long getDynamicRangeProfile();
method public int getMaxSharedSurfaceCount();
method public int getMirrorMode();
method public int getStreamUseCase();
@@ -18241,7 +18251,7 @@
method public int getTimestampBase();
method public void removeSensorPixelModeUsed(int);
method public void removeSurface(@NonNull android.view.Surface);
- method public void setDynamicRangeProfile(int);
+ method public void setDynamicRangeProfile(long);
method public void setMirrorMode(int);
method public void setPhysicalCameraId(@Nullable String);
method public void setStreamUseCase(int);
@@ -30684,7 +30694,7 @@
public class BaseBundle {
method public void clear();
method public boolean containsKey(String);
- method @Nullable public Object get(String);
+ method @Deprecated @Nullable public Object get(String);
method public boolean getBoolean(String);
method public boolean getBoolean(String, boolean);
method @Nullable public boolean[] getBooleanArray(@Nullable String);
@@ -30926,16 +30936,21 @@
method public float getFloat(String, float);
method @Nullable public float[] getFloatArray(@Nullable String);
method @Nullable public java.util.ArrayList<java.lang.Integer> getIntegerArrayList(@Nullable String);
- method @Nullable public <T extends android.os.Parcelable> T getParcelable(@Nullable String);
- method @Nullable public android.os.Parcelable[] getParcelableArray(@Nullable String);
- method @Nullable public <T extends android.os.Parcelable> java.util.ArrayList<T> getParcelableArrayList(@Nullable String);
- method @Nullable public java.io.Serializable getSerializable(@Nullable String);
+ method @Deprecated @Nullable public <T extends android.os.Parcelable> T getParcelable(@Nullable String);
+ method @Nullable public <T> T getParcelable(@Nullable String, @NonNull Class<T>);
+ method @Deprecated @Nullable public android.os.Parcelable[] getParcelableArray(@Nullable String);
+ method @Nullable public <T> T[] getParcelableArray(@Nullable String, @NonNull Class<T>);
+ method @Deprecated @Nullable public <T extends android.os.Parcelable> java.util.ArrayList<T> getParcelableArrayList(@Nullable String);
+ method @Nullable public <T> java.util.ArrayList<T> getParcelableArrayList(@Nullable String, @NonNull Class<T>);
+ method @Deprecated @Nullable public java.io.Serializable getSerializable(@Nullable String);
+ method @Nullable public <T extends java.io.Serializable> T getSerializable(@Nullable String, @NonNull Class<T>);
method public short getShort(String);
method public short getShort(String, short);
method @Nullable public short[] getShortArray(@Nullable String);
method @Nullable public android.util.Size getSize(@Nullable String);
method @Nullable public android.util.SizeF getSizeF(@Nullable String);
- method @Nullable public <T extends android.os.Parcelable> android.util.SparseArray<T> getSparseParcelableArray(@Nullable String);
+ method @Deprecated @Nullable public <T extends android.os.Parcelable> android.util.SparseArray<T> getSparseParcelableArray(@Nullable String);
+ method @Nullable public <T> android.util.SparseArray<T> getSparseParcelableArray(@Nullable String, @NonNull Class<T>);
method @Nullable public java.util.ArrayList<java.lang.String> getStringArrayList(@Nullable String);
method public boolean hasFileDescriptors();
method public void putAll(android.os.Bundle);
@@ -31784,7 +31799,7 @@
method public android.os.PowerManager.WakeLock newWakeLock(int, String);
method @RequiresPermission(android.Manifest.permission.REBOOT) public void reboot(@Nullable String);
method public void removeThermalStatusListener(@NonNull android.os.PowerManager.OnThermalStatusChangedListener);
- field public static final int ACQUIRE_CAUSES_WAKEUP = 268435456; // 0x10000000
+ field @Deprecated public static final int ACQUIRE_CAUSES_WAKEUP = 268435456; // 0x10000000
field public static final String ACTION_DEVICE_IDLE_MODE_CHANGED = "android.os.action.DEVICE_IDLE_MODE_CHANGED";
field public static final String ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED = "android.os.action.LIGHT_DEVICE_IDLE_MODE_CHANGED";
field public static final String ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED = "android.os.action.LOW_POWER_STANDBY_ENABLED_CHANGED";
@@ -35435,8 +35450,8 @@
field public static final String EXTRA_WIFI_NETWORK_RESULT_LIST = "android.provider.extra.WIFI_NETWORK_RESULT_LIST";
field public static final String INTENT_CATEGORY_USAGE_ACCESS_CONFIG = "android.intent.category.USAGE_ACCESS_CONFIG";
field public static final String METADATA_USAGE_ACCESS_REASON = "android.settings.metadata.USAGE_ACCESS_REASON";
- field public static final String SUPERVISOR_VERIFICATION_SETTING_BIOMETRICS = "supervisor_restricted_biometrics_controller";
- field public static final String SUPERVISOR_VERIFICATION_SETTING_UNKNOWN = "";
+ field public static final int SUPERVISOR_VERIFICATION_SETTING_BIOMETRICS = 1; // 0x1
+ field public static final int SUPERVISOR_VERIFICATION_SETTING_UNKNOWN = 0; // 0x0
}
public static final class Settings.Global extends android.provider.Settings.NameValueTable {
@@ -49285,7 +49300,7 @@
method @NonNull public android.view.SurfaceControl.Transaction setDataSpace(@NonNull android.view.SurfaceControl, int);
method @NonNull public android.view.SurfaceControl.Transaction setFrameRate(@NonNull android.view.SurfaceControl, @FloatRange(from=0.0) float, int);
method @NonNull public android.view.SurfaceControl.Transaction setFrameRate(@NonNull android.view.SurfaceControl, @FloatRange(from=0.0) float, int, int);
- method @NonNull public android.view.SurfaceControl.Transaction setGeometry(@NonNull android.view.SurfaceControl, @Nullable android.graphics.Rect, @Nullable android.graphics.Rect, int);
+ method @Deprecated @NonNull public android.view.SurfaceControl.Transaction setGeometry(@NonNull android.view.SurfaceControl, @Nullable android.graphics.Rect, @Nullable android.graphics.Rect, int);
method @NonNull public android.view.SurfaceControl.Transaction setLayer(@NonNull android.view.SurfaceControl, @IntRange(from=java.lang.Integer.MIN_VALUE, to=java.lang.Integer.MAX_VALUE) int);
method @NonNull public android.view.SurfaceControl.Transaction setOpaque(@NonNull android.view.SurfaceControl, boolean);
method @NonNull public android.view.SurfaceControl.Transaction setPosition(@NonNull android.view.SurfaceControl, float, float);
@@ -53105,7 +53120,7 @@
field public static final int RESULT_SHOWN = 2; // 0x2
field public static final int RESULT_UNCHANGED_HIDDEN = 1; // 0x1
field public static final int RESULT_UNCHANGED_SHOWN = 0; // 0x0
- field public static final int SHOW_FORCED = 2; // 0x2
+ field @Deprecated public static final int SHOW_FORCED = 2; // 0x2
field public static final int SHOW_IMPLICIT = 1; // 0x1
}
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 594f46b..7ec239d 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -413,6 +413,7 @@
public class StorageManager {
method public long computeStorageCacheBytes(@NonNull java.io.File);
+ method @Nullable public String getCloudMediaProvider();
method public void notifyAppIoBlocked(@NonNull java.util.UUID, int, int, int);
method public void notifyAppIoResumed(@NonNull java.util.UUID, int, int, int);
method public void setCloudMediaProvider(@Nullable String);
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 2c0e641..76cac5f 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -915,10 +915,10 @@
public class StatusBarManager {
method @NonNull @RequiresPermission(android.Manifest.permission.STATUS_BAR) public android.app.StatusBarManager.DisableInfo getDisableInfo();
- method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public int getNavBarModeOverride();
+ method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public int getNavBarMode();
method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void registerNearbyMediaDevicesProvider(@NonNull android.media.NearbyMediaDevicesProvider);
method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setDisabledForSetup(boolean);
- method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setNavBarModeOverride(int);
+ method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setNavBarMode(int);
method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void unregisterNearbyMediaDevicesProvider(@NonNull android.media.NearbyMediaDevicesProvider);
method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void updateMediaTapToTransferReceiverDisplay(int, @NonNull android.media.MediaRoute2Info, @Nullable android.graphics.drawable.Icon, @Nullable CharSequence);
method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void updateMediaTapToTransferSenderDisplay(int, @NonNull android.media.MediaRoute2Info, @Nullable java.util.concurrent.Executor, @Nullable Runnable);
@@ -933,8 +933,8 @@
field public static final int MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_FAILED = 7; // 0x7
field public static final int MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED = 5; // 0x5
field public static final int MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED = 3; // 0x3
- field public static final int NAV_BAR_MODE_OVERRIDE_KIDS = 1; // 0x1
- field public static final int NAV_BAR_MODE_OVERRIDE_NONE = 0; // 0x0
+ field public static final int NAV_BAR_MODE_DEFAULT = 0; // 0x0
+ field public static final int NAV_BAR_MODE_KIDS = 1; // 0x1
}
public static final class StatusBarManager.DisableInfo {
@@ -1059,10 +1059,10 @@
ctor public DevicePolicyDrawableResource(@NonNull android.content.Context, @NonNull String, @NonNull String, @NonNull String, @DrawableRes int);
ctor public DevicePolicyDrawableResource(@NonNull android.content.Context, @NonNull String, @NonNull String, @DrawableRes int);
method public int describeContents();
- method @DrawableRes public int getCallingPackageResourceId();
method @NonNull public String getDrawableId();
method @NonNull public String getDrawableSource();
method @NonNull public String getDrawableStyle();
+ method @DrawableRes public int getResourceIdInCallingPackage();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.DevicePolicyDrawableResource> CREATOR;
}
@@ -1088,8 +1088,8 @@
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_ADMIN_POLICY}) public java.util.List<java.lang.String> getPermittedInputMethodsForCurrentUser();
method @Nullable public android.content.ComponentName getProfileOwner() throws java.lang.IllegalArgumentException;
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS}) public String getProfileOwnerNameAsUser(int) throws java.lang.IllegalArgumentException;
- method @Nullable public String getString(@NonNull String, @NonNull java.util.concurrent.Callable<java.lang.String>);
- method @Nullable public String getString(@NonNull String, @NonNull java.util.concurrent.Callable<java.lang.String>, @NonNull java.lang.Object...);
+ method @Nullable public String getString(@NonNull String, @NonNull java.util.function.Supplier<java.lang.String>);
+ method @Nullable public String getString(@NonNull String, @NonNull java.util.function.Supplier<java.lang.String>, @NonNull java.lang.Object...);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS}) public int getUserProvisioningState();
method public boolean isDeviceManaged();
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isDeviceProvisioned();
@@ -1239,7 +1239,7 @@
public final class DevicePolicyStringResource implements android.os.Parcelable {
ctor public DevicePolicyStringResource(@NonNull android.content.Context, @NonNull String, @StringRes int);
method public int describeContents();
- method public int getCallingPackageResourceId();
+ method public int getResourceIdInCallingPackage();
method @NonNull public String getStringId();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.DevicePolicyStringResource> CREATOR;
@@ -2172,23 +2172,41 @@
field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.SmartspaceTarget> CREATOR;
field public static final int FEATURE_ALARM = 7; // 0x7
field public static final int FEATURE_BEDTIME_ROUTINE = 16; // 0x10
+ field public static final int FEATURE_BLAZE_BUILD_PROGRESS = 40; // 0x28
field public static final int FEATURE_CALENDAR = 2; // 0x2
field public static final int FEATURE_COMMUTE_TIME = 3; // 0x3
field public static final int FEATURE_CONSENT = 11; // 0xb
+ field public static final int FEATURE_CROSS_DEVICE_TIMER = 32; // 0x20
+ field public static final int FEATURE_DOORBELL = 30; // 0x1e
+ field public static final int FEATURE_DRIVING_MODE = 26; // 0x1a
+ field public static final int FEATURE_EARTHQUAKE_ALERT = 38; // 0x26
+ field public static final int FEATURE_EARTHQUAKE_OCCURRED = 41; // 0x29
field public static final int FEATURE_ETA_MONITORING = 18; // 0x12
field public static final int FEATURE_FITNESS_TRACKING = 17; // 0x11
+ field public static final int FEATURE_FLASHLIGHT = 28; // 0x1c
field public static final int FEATURE_FLIGHT = 4; // 0x4
+ field public static final int FEATURE_GAS_STATION_PAYMENT = 24; // 0x18
+ field public static final int FEATURE_HOLIDAY_ALARM = 34; // 0x22
field public static final int FEATURE_LOYALTY_CARD = 14; // 0xe
field public static final int FEATURE_MEDIA = 15; // 0xf
+ field public static final int FEATURE_MEDIA_HEADS_UP = 36; // 0x24
+ field public static final int FEATURE_MEDIA_RESUME = 31; // 0x1f
field public static final int FEATURE_MISSED_CALL = 19; // 0x13
field public static final int FEATURE_ONBOARDING = 8; // 0x8
field public static final int FEATURE_PACKAGE_TRACKING = 20; // 0x14
+ field public static final int FEATURE_PAIRED_DEVICE_STATE = 25; // 0x19
field public static final int FEATURE_REMINDER = 6; // 0x6
+ field public static final int FEATURE_SAFETY_CHECK = 35; // 0x23
+ field public static final int FEATURE_SEVERE_WEATHER_ALERT = 33; // 0x21
field public static final int FEATURE_SHOPPING_LIST = 13; // 0xd
+ field public static final int FEATURE_SLEEP_SUMMARY = 27; // 0x1b
field public static final int FEATURE_SPORTS = 9; // 0x9
+ field public static final int FEATURE_STEP_COUNTING = 37; // 0x25
+ field public static final int FEATURE_STEP_DATE = 39; // 0x27
field public static final int FEATURE_STOCK_PRICE_CHANGE = 12; // 0xc
field public static final int FEATURE_STOPWATCH = 22; // 0x16
field public static final int FEATURE_TIMER = 21; // 0x15
+ field public static final int FEATURE_TIME_TO_LEAVE = 29; // 0x1d
field public static final int FEATURE_TIPS = 5; // 0x5
field public static final int FEATURE_UNDEFINED = 0; // 0x0
field public static final int FEATURE_UPCOMING_ALARM = 23; // 0x17
@@ -2254,22 +2272,12 @@
public class BaseTemplateData implements android.os.Parcelable {
method public int describeContents();
method public int getLayoutWeight();
- method @Nullable public android.app.smartspace.uitemplatedata.BaseTemplateData.SubItemLoggingInfo getPrimaryLoggingInfo();
- method @Nullable public android.app.smartspace.uitemplatedata.TapAction getPrimaryTapAction();
- method @Nullable public android.app.smartspace.uitemplatedata.Icon getSubtitleIcon();
- method @Nullable public android.app.smartspace.uitemplatedata.Text getSubtitleText();
- method @Nullable public android.app.smartspace.uitemplatedata.Text getSupplementalAlarmText();
- method @Nullable public android.app.smartspace.uitemplatedata.Icon getSupplementalIcon();
- method @Nullable public android.app.smartspace.uitemplatedata.BaseTemplateData.SubItemLoggingInfo getSupplementalLoggingInfo();
- method @Nullable public android.app.smartspace.uitemplatedata.Icon getSupplementalSubtitleIcon();
- method @Nullable public android.app.smartspace.uitemplatedata.BaseTemplateData.SubItemLoggingInfo getSupplementalSubtitleLoggingInfo();
- method @Nullable public android.app.smartspace.uitemplatedata.TapAction getSupplementalSubtitleTapAction();
- method @Nullable public android.app.smartspace.uitemplatedata.Text getSupplementalSubtitleText();
- method @Nullable public android.app.smartspace.uitemplatedata.TapAction getSupplementalTapAction();
- method @Nullable public android.app.smartspace.uitemplatedata.Text getSupplementalText();
+ method @Nullable public android.app.smartspace.uitemplatedata.BaseTemplateData.SubItemInfo getPrimaryItem();
+ method @Nullable public android.app.smartspace.uitemplatedata.BaseTemplateData.SubItemInfo getSubtitleItem();
+ method @Nullable public android.app.smartspace.uitemplatedata.BaseTemplateData.SubItemInfo getSubtitleSupplementalItem();
+ method @Nullable public android.app.smartspace.uitemplatedata.BaseTemplateData.SubItemInfo getSupplementalAlarmItem();
+ method @Nullable public android.app.smartspace.uitemplatedata.BaseTemplateData.SubItemInfo getSupplementalLineItem();
method public int getTemplateType();
- method @Nullable public android.app.smartspace.uitemplatedata.Icon getTitleIcon();
- method @Nullable public android.app.smartspace.uitemplatedata.Text getTitleText();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.uitemplatedata.BaseTemplateData> CREATOR;
}
@@ -2278,27 +2286,37 @@
ctor public BaseTemplateData.Builder(int);
method @NonNull public android.app.smartspace.uitemplatedata.BaseTemplateData build();
method @NonNull public android.app.smartspace.uitemplatedata.BaseTemplateData.Builder setLayoutWeight(int);
- method @NonNull public android.app.smartspace.uitemplatedata.BaseTemplateData.Builder setPrimaryLoggingInfo(@NonNull android.app.smartspace.uitemplatedata.BaseTemplateData.SubItemLoggingInfo);
- method @NonNull public android.app.smartspace.uitemplatedata.BaseTemplateData.Builder setPrimaryTapAction(@NonNull android.app.smartspace.uitemplatedata.TapAction);
- method @NonNull public android.app.smartspace.uitemplatedata.BaseTemplateData.Builder setSubtitleIcon(@NonNull android.app.smartspace.uitemplatedata.Icon);
- method @NonNull public android.app.smartspace.uitemplatedata.BaseTemplateData.Builder setSubtitleText(@NonNull android.app.smartspace.uitemplatedata.Text);
- method @NonNull public android.app.smartspace.uitemplatedata.BaseTemplateData.Builder setSupplementalAlarmText(@NonNull android.app.smartspace.uitemplatedata.Text);
- method @NonNull public android.app.smartspace.uitemplatedata.BaseTemplateData.Builder setSupplementalIcon(@NonNull android.app.smartspace.uitemplatedata.Icon);
- method @NonNull public android.app.smartspace.uitemplatedata.BaseTemplateData.Builder setSupplementalLoggingInfo(@NonNull android.app.smartspace.uitemplatedata.BaseTemplateData.SubItemLoggingInfo);
- method @NonNull public android.app.smartspace.uitemplatedata.BaseTemplateData.Builder setSupplementalSubtitleIcon(@NonNull android.app.smartspace.uitemplatedata.Icon);
- method @NonNull public android.app.smartspace.uitemplatedata.BaseTemplateData.Builder setSupplementalSubtitleLoggingInfo(@NonNull android.app.smartspace.uitemplatedata.BaseTemplateData.SubItemLoggingInfo);
- method @NonNull public android.app.smartspace.uitemplatedata.BaseTemplateData.Builder setSupplementalSubtitleTapAction(@NonNull android.app.smartspace.uitemplatedata.TapAction);
- method @NonNull public android.app.smartspace.uitemplatedata.BaseTemplateData.Builder setSupplementalSubtitleText(@NonNull android.app.smartspace.uitemplatedata.Text);
- method @NonNull public android.app.smartspace.uitemplatedata.BaseTemplateData.Builder setSupplementalTapAction(@NonNull android.app.smartspace.uitemplatedata.TapAction);
- method @NonNull public android.app.smartspace.uitemplatedata.BaseTemplateData.Builder setSupplementalText(@NonNull android.app.smartspace.uitemplatedata.Text);
- method @NonNull public android.app.smartspace.uitemplatedata.BaseTemplateData.Builder setTitleIcon(@NonNull android.app.smartspace.uitemplatedata.Icon);
- method @NonNull public android.app.smartspace.uitemplatedata.BaseTemplateData.Builder setTitleText(@NonNull android.app.smartspace.uitemplatedata.Text);
+ method @NonNull public android.app.smartspace.uitemplatedata.BaseTemplateData.Builder setPrimaryItem(@NonNull android.app.smartspace.uitemplatedata.BaseTemplateData.SubItemInfo);
+ method @NonNull public android.app.smartspace.uitemplatedata.BaseTemplateData.Builder setSubtitleItem(@NonNull android.app.smartspace.uitemplatedata.BaseTemplateData.SubItemInfo);
+ method @NonNull public android.app.smartspace.uitemplatedata.BaseTemplateData.Builder setSubtitleSupplementalItem(@NonNull android.app.smartspace.uitemplatedata.BaseTemplateData.SubItemInfo);
+ method @NonNull public android.app.smartspace.uitemplatedata.BaseTemplateData.Builder setSupplementalAlarmItem(@NonNull android.app.smartspace.uitemplatedata.BaseTemplateData.SubItemInfo);
+ method @NonNull public android.app.smartspace.uitemplatedata.BaseTemplateData.Builder setSupplementalLineItem(@NonNull android.app.smartspace.uitemplatedata.BaseTemplateData.SubItemInfo);
+ }
+
+ public static final class BaseTemplateData.SubItemInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method @Nullable public android.app.smartspace.uitemplatedata.Icon getIcon();
+ method @Nullable public android.app.smartspace.uitemplatedata.BaseTemplateData.SubItemLoggingInfo getLoggingInfo();
+ method @Nullable public android.app.smartspace.uitemplatedata.TapAction getTapAction();
+ method @Nullable public android.app.smartspace.uitemplatedata.Text getText();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.uitemplatedata.BaseTemplateData.SubItemInfo> CREATOR;
+ }
+
+ public static final class BaseTemplateData.SubItemInfo.Builder {
+ ctor public BaseTemplateData.SubItemInfo.Builder();
+ method @NonNull public android.app.smartspace.uitemplatedata.BaseTemplateData.SubItemInfo build();
+ method @NonNull public android.app.smartspace.uitemplatedata.BaseTemplateData.SubItemInfo.Builder setIcon(@NonNull android.app.smartspace.uitemplatedata.Icon);
+ method @NonNull public android.app.smartspace.uitemplatedata.BaseTemplateData.SubItemInfo.Builder setLoggingInfo(@NonNull android.app.smartspace.uitemplatedata.BaseTemplateData.SubItemLoggingInfo);
+ method @NonNull public android.app.smartspace.uitemplatedata.BaseTemplateData.SubItemInfo.Builder setTapAction(@NonNull android.app.smartspace.uitemplatedata.TapAction);
+ method @NonNull public android.app.smartspace.uitemplatedata.BaseTemplateData.SubItemInfo.Builder setText(@NonNull android.app.smartspace.uitemplatedata.Text);
}
public static final class BaseTemplateData.SubItemLoggingInfo implements android.os.Parcelable {
method public int describeContents();
method public int getFeatureType();
method public int getInstanceId();
+ method @Nullable public CharSequence getPackageName();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.uitemplatedata.BaseTemplateData.SubItemLoggingInfo> CREATOR;
}
@@ -2306,6 +2324,7 @@
public static final class BaseTemplateData.SubItemLoggingInfo.Builder {
ctor public BaseTemplateData.SubItemLoggingInfo.Builder(int, int);
method @NonNull public android.app.smartspace.uitemplatedata.BaseTemplateData.SubItemLoggingInfo build();
+ method @NonNull public android.app.smartspace.uitemplatedata.BaseTemplateData.SubItemLoggingInfo.Builder setPackageName(@NonNull CharSequence);
}
public final class CarouselTemplateData extends android.app.smartspace.uitemplatedata.BaseTemplateData {
@@ -2793,7 +2812,7 @@
method public void addActivityListener(@NonNull android.companion.virtual.VirtualDeviceManager.ActivityListener, @NonNull java.util.concurrent.Executor);
method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void close();
method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.companion.virtual.audio.VirtualAudioDevice createVirtualAudioDevice(@NonNull android.hardware.display.VirtualDisplay, @Nullable java.util.concurrent.Executor, @Nullable android.companion.virtual.audio.VirtualAudioDevice.AudioConfigurationChangeCallback);
- method @Nullable public android.hardware.display.VirtualDisplay createVirtualDisplay(@IntRange(from=1) int, @IntRange(from=1) int, @IntRange(from=1) int, @Nullable android.view.Surface, int, @NonNull java.util.concurrent.Executor, @Nullable android.hardware.display.VirtualDisplay.Callback);
+ method @Nullable public android.hardware.display.VirtualDisplay createVirtualDisplay(@IntRange(from=1) int, @IntRange(from=1) int, @IntRange(from=1) int, @Nullable android.view.Surface, int, @Nullable java.util.concurrent.Executor, @Nullable android.hardware.display.VirtualDisplay.Callback);
method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualKeyboard createVirtualKeyboard(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualMouse createVirtualMouse(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualTouchscreen createVirtualTouchscreen(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
@@ -2804,11 +2823,14 @@
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
@@ -2817,8 +2839,8 @@
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>);
}
@@ -3016,6 +3038,7 @@
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";
@@ -5889,16 +5912,16 @@
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;
@@ -5917,8 +5940,8 @@
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);
}
@@ -10299,6 +10322,7 @@
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 9757b2f..22637ca 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1073,7 +1073,7 @@
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
}
@@ -2347,6 +2347,8 @@
public abstract class DreamOverlayService extends android.app.Service {
ctor public DreamOverlayService();
+ method @Nullable public final CharSequence getDreamLabel();
+ method public final boolean isPreviewMode();
method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
method public abstract void onStartDream(@NonNull android.view.WindowManager.LayoutParams);
method public final void requestExit();
@@ -2960,6 +2962,7 @@
public final class AutofillManager {
field public static final String DEVICE_CONFIG_AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES = "compat_mode_allowed_packages";
+ field public static final String DEVICE_CONFIG_AUTOFILL_DIALOG_ENABLED = "autofill_dialog_enabled";
field public static final String DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES = "smart_suggestion_supported_modes";
field public static final int FLAG_SMART_SUGGESTION_OFF = 0; // 0x0
field public static final int FLAG_SMART_SUGGESTION_SYSTEM = 1; // 0x1
@@ -3082,6 +3085,7 @@
method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public java.util.List<android.view.inputmethod.InputMethodInfo> getInputMethodListAsUser(int);
method public boolean hasActiveInputConnection(@Nullable android.view.View);
method public boolean isInputMethodPickerShown();
+ field public static final long CLEAR_SHOW_FORCED_FLAG_WHEN_LEAVING = 214016041L; // 0xcc1a029L
}
}
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 8af68d7..530de0f 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -83,11 +83,13 @@
* @attr ref android.R.styleable#AccessibilityService_canRequestFilterKeyEvents
* @attr ref android.R.styleable#AccessibilityService_canRequestTouchExplorationMode
* @attr ref android.R.styleable#AccessibilityService_canRetrieveWindowContent
+ * @attr ref android.R.styleable#AccessibilityService_intro
* @attr ref android.R.styleable#AccessibilityService_description
* @attr ref android.R.styleable#AccessibilityService_summary
* @attr ref android.R.styleable#AccessibilityService_notificationTimeout
* @attr ref android.R.styleable#AccessibilityService_packageNames
* @attr ref android.R.styleable#AccessibilityService_settingsActivity
+ * @attr ref android.R.styleable#AccessibilityService_tileService
* @attr ref android.R.styleable#AccessibilityService_nonInteractiveUiTimeout
* @attr ref android.R.styleable#AccessibilityService_interactiveUiTimeout
* @attr ref android.R.styleable#AccessibilityService_canTakeScreenshot
@@ -547,11 +549,11 @@
private String mSettingsActivityName;
/**
- * The class name of {@link android.service.quicksettings.TileService} is associated with this
+ * The name of {@link android.service.quicksettings.TileService} is associated with this
* accessibility service for one to one mapping. It is used by system settings to remind users
* this accessibility service has a {@link android.service.quicksettings.TileService}.
*/
- private String mTileServiceClassName;
+ private String mTileServiceName;
/**
* Bit mask with capabilities of this service.
@@ -740,7 +742,7 @@
}
mIsAccessibilityTool = asAttributes.getBoolean(
R.styleable.AccessibilityService_isAccessibilityTool, false);
- mTileServiceClassName = asAttributes.getString(
+ mTileServiceName = asAttributes.getString(
com.android.internal.R.styleable.AccessibilityService_tileService);
peekedValue = asAttributes.peekValue(
com.android.internal.R.styleable.AccessibilityService_intro);
@@ -850,14 +852,14 @@
}
/**
- * Gets the class name of {@link android.service.quicksettings.TileService} is associated with
+ * Gets the name of {@link android.service.quicksettings.TileService} is associated with
* this accessibility service.
*
- * @return The class names of {@link android.service.quicksettings.TileService}.
+ * @return The name of {@link android.service.quicksettings.TileService}.
*/
@Nullable
- public String getTileServiceClassName() {
- return mTileServiceClassName;
+ public String getTileServiceName() {
+ return mTileServiceName;
}
/**
@@ -1146,7 +1148,7 @@
parcel.writeInt(mHtmlDescriptionRes);
parcel.writeString(mNonLocalizedDescription);
parcel.writeBoolean(mIsAccessibilityTool);
- parcel.writeString(mTileServiceClassName);
+ parcel.writeString(mTileServiceName);
parcel.writeInt(mIntroResId);
}
@@ -1170,7 +1172,7 @@
mHtmlDescriptionRes = parcel.readInt();
mNonLocalizedDescription = parcel.readString();
mIsAccessibilityTool = parcel.readBoolean();
- mTileServiceClassName = parcel.readString();
+ mTileServiceName = parcel.readString();
mIntroResId = parcel.readInt();
}
@@ -1224,7 +1226,7 @@
stringBuilder.append(", ");
stringBuilder.append("settingsActivityName: ").append(mSettingsActivityName);
stringBuilder.append(", ");
- stringBuilder.append("tileServiceClassName: ").append(mTileServiceClassName);
+ stringBuilder.append("tileServiceName: ").append(mTileServiceName);
stringBuilder.append(", ");
stringBuilder.append("summary: ").append(mNonLocalizedSummary);
stringBuilder.append(", ");
diff --git a/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java b/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java
index 9a73219..4e6cfb35 100644
--- a/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java
@@ -101,11 +101,11 @@
private String mSettingsActivityName;
/**
- * The class name of {@link android.service.quicksettings.TileService} is associated with this
+ * The name of {@link android.service.quicksettings.TileService} is associated with this
* accessibility shortcut target for one to one mapping. It is used by system settings to remind
* users this accessibility service has a {@link android.service.quicksettings.TileService}.
*/
- private String mTileServiceClassName;
+ private String mTileServiceName;
/**
* Creates a new instance.
@@ -163,7 +163,7 @@
mSettingsActivityName = asAttributes.getString(
com.android.internal.R.styleable.AccessibilityShortcutTarget_settingsActivity);
// Get tile service class name
- mTileServiceClassName = asAttributes.getString(
+ mTileServiceName = asAttributes.getString(
com.android.internal.R.styleable.AccessibilityShortcutTarget_tileService);
// Gets intro
mIntroResId = asAttributes.getResourceId(
@@ -287,14 +287,14 @@
}
/**
- * Gets the class name of {@link android.service.quicksettings.TileService} is associated with
+ * Gets the name of {@link android.service.quicksettings.TileService} is associated with
* this accessibility shortcut target.
*
- * @return The class names of {@link android.service.quicksettings.TileService}.
+ * @return The class name of {@link android.service.quicksettings.TileService}.
*/
@Nullable
- public String getTileServiceClassName() {
- return mTileServiceClassName;
+ public String getTileServiceName() {
+ return mTileServiceName;
}
/**
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 11663a5..bc979fc 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -7416,7 +7416,6 @@
} 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 61d1865..64f0301 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4469,12 +4469,6 @@
// 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/Application.java b/core/java/android/app/Application.java
index 9eb3e8f..7c337a4 100644
--- a/core/java/android/app/Application.java
+++ b/core/java/android/app/Application.java
@@ -29,14 +29,12 @@
import android.content.res.Configuration;
import android.os.Build;
import android.os.Bundle;
-import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
import android.view.autofill.AutofillManager;
-import com.android.internal.annotations.GuardedBy;
-
import java.util.ArrayList;
+import java.util.concurrent.atomic.AtomicReference;
/**
* Base class for maintaining global application state. You can provide your own
@@ -74,12 +72,8 @@
@UnsupportedAppUsage
public LoadedApk mLoadedApk;
- @GuardedBy("sInstances")
- private static final ArrayMap<Class<?>, Application> sInstances =
- DEBUG_DUP_APP_INSTANCES ? new ArrayMap<>(1) : null;
-
- // Only set when DEBUG_DUP_APP_INSTANCES is true.
- private StackTrace mConstructorStackTrace;
+ private static final AtomicReference<StackTrace> sConstructorStackTrace =
+ new AtomicReference<>();
public interface ActivityLifecycleCallbacks {
@@ -252,28 +246,20 @@
}
private void checkDuplicateInstances() {
- final Class<?> myClass = this.getClass();
-
- // We only activate this check for custom application classes.
- // Otherwise, it'd misfire if multiple apps share the same process, if all of them use
- // the same Application class (on the same classloader).
- if (myClass == Application.class) {
+ // STOPSHIP: Delete this check b/221248960
+ // Only run this check for gms-core.
+ if (!"com.google.android.gms".equals(ActivityThread.currentOpPackageName())) {
return;
}
- synchronized (sInstances) {
- final Application firstInstance = sInstances.get(myClass);
- if (firstInstance == null) {
- this.mConstructorStackTrace = new StackTrace("First ctor was called here");
- sInstances.put(myClass, this);
- return;
- }
- final StackTrace currentStackTrace = new StackTrace("Current ctor was called here",
- firstInstance.mConstructorStackTrace);
- this.mConstructorStackTrace = currentStackTrace;
- Slog.wtf(TAG, "Application ctor called twice for " + myClass
- + " first LoadedApk=" + firstInstance.getLoadedApkInfo(),
- currentStackTrace);
+
+ final StackTrace previousStackTrace = sConstructorStackTrace.getAndSet(
+ new StackTrace("Previous stack trace"));
+ if (previousStackTrace == null) {
+ // This is the first call.
+ return;
}
+ Slog.wtf(TAG, "Application ctor called twice for " + this.getClass(),
+ new StackTrace("Current stack trace", previousStackTrace));
}
private String getLoadedApkInfo() {
diff --git a/core/java/android/app/BroadcastOptions.java b/core/java/android/app/BroadcastOptions.java
index e31a566..8b3c9fa 100644
--- a/core/java/android/app/BroadcastOptions.java
+++ b/core/java/android/app/BroadcastOptions.java
@@ -523,6 +523,8 @@
* Sets whether events (such as posting a notification) originating from an app after it
* receives the broadcast while in background should be recorded as responses to the broadcast.
*
+ * <p> Note that this will only be considered when sending explicit broadcast intents.
+ *
* @param id ID to be used for the response events corresponding to this broadcast. If the
* value is {@code 0} (default), then response events will not be recorded. Otherwise,
* they will be recorded with the ID provided.
diff --git a/core/java/android/app/GameState.java b/core/java/android/app/GameState.java
index 979dd34..fe6e554 100644
--- a/core/java/android/app/GameState.java
+++ b/core/java/android/app/GameState.java
@@ -18,8 +18,6 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -88,12 +86,11 @@
// One of the states listed above.
private final @GameStateMode int mMode;
- // This is a game specific description. For example can be level or scene name.
- private final @Nullable String mDescription;
+ // A developer-supplied enum, e.g. to indicate level or scene.
+ private final int mLabel;
- // This contains any other game specific parameters not covered by the fields above. It can be
- // quality parameter data, settings, or game modes.
- private final @NonNull Bundle mMetaData;
+ // The developer-supplied enum, e.g. to indicate the current quality level.
+ private final int mQuality;
/**
* Create a GameState with the specified loading status.
@@ -101,29 +98,28 @@
* @param mode The game state mode of type @GameStateMode.
*/
public GameState(boolean isLoading, @GameStateMode int mode) {
- this(isLoading, mode, null, new Bundle());
+ this(isLoading, mode, -1, -1);
}
/**
* Create a GameState with the given state variables.
* @param isLoading Whether the game is in the loading state.
- * @param mode The game state mode of type @GameStateMode.
- * @param description An optional description of the state.
- * @param metaData Optional metadata.
+ * @param mode The game state mode.
+ * @param label An optional developer-supplied enum e.g. for the current level.
+ * @param quality An optional developer-supplied enum, e.g. for the current quality level.
*/
- public GameState(boolean isLoading, @GameStateMode int mode, @Nullable String description,
- @NonNull Bundle metaData) {
+ public GameState(boolean isLoading, @GameStateMode int mode, int label, int quality) {
mIsLoading = isLoading;
mMode = mode;
- mDescription = description;
- mMetaData = metaData;
+ mLabel = label;
+ mQuality = quality;
}
private GameState(Parcel in) {
mIsLoading = in.readBoolean();
mMode = in.readInt();
- mDescription = in.readString();
- mMetaData = in.readBundle();
+ mLabel = in.readInt();
+ mQuality = in.readInt();
}
/**
@@ -141,17 +137,19 @@
}
/**
- * @return The state description, or null if one is not set.
+ * @return The developer-supplied enum, e.g. to indicate level or scene. The default value (if
+ * not supplied) is -1.
*/
- public @Nullable String getDescription() {
- return mDescription;
+ public int getLabel() {
+ return mLabel;
}
/**
- * @return metadata associated with the state.
+ * @return The developer-supplied enum, e.g. to indicate the current quality level. The default
+ * value (if not suplied) is -1.
*/
- public @NonNull Bundle getMetadata() {
- return mMetaData;
+ public int getQuality() {
+ return mQuality;
}
@Override
@@ -163,8 +161,8 @@
public void writeToParcel(@NonNull Parcel parcel, int flags) {
parcel.writeBoolean(mIsLoading);
parcel.writeInt(mMode);
- parcel.writeString(mDescription);
- parcel.writeBundle(mMetaData);
+ parcel.writeInt(mLabel);
+ parcel.writeInt(mQuality);
}
/**
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 7c48a57..fe0edfe 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -510,7 +510,6 @@
void noteAlarmFinish(in IIntentSender sender, in WorkSource workSource, int sourceUid, in String tag);
@UnsupportedAppUsage
int getPackageProcessState(in String packageName, in String callingPackage);
- void updateDeviceOwner(in String packageName);
// Start of N transactions
// Start Binder transaction tracking for all applications.
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index 490afc1..ef9a2f2 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -299,7 +299,7 @@
* a short predefined amount of time.
*/
void registerRemoteAnimationForNextActivityStart(in String packageName,
- in RemoteAnimationAdapter adapter);
+ in RemoteAnimationAdapter adapter, in IBinder launchCookie);
/**
* Registers remote animations for a display.
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 9910000..87ba197 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -52,6 +52,7 @@
import android.view.WindowManagerGlobal;
import com.android.internal.policy.IKeyguardDismissCallback;
+import com.android.internal.policy.IKeyguardLockedStateListener;
import com.android.internal.util.Preconditions;
import com.android.internal.widget.IWeakEscrowTokenActivatedListener;
import com.android.internal.widget.IWeakEscrowTokenRemovedListener;
@@ -183,6 +184,10 @@
})
@interface LockTypes {}
+ // TODO(b/220379118): register only one binder listener and keep a map of listener to executor.
+ private final ArrayMap<KeyguardLockedStateListener, IKeyguardLockedStateListener>
+ mKeyguardLockedStateListeners = new ArrayMap<>();
+
/**
* Get an intent to prompt the user to confirm credentials (pin, pattern, password or biometrics
* if enrolled) for the current user of the device. The caller is expected to launch this
@@ -534,7 +539,7 @@
/**
* Return whether the keyguard is currently locked.
*
- * @return true if keyguard is locked.
+ * @return {@code true} if the keyguard is locked.
*/
public boolean isKeyguardLocked() {
try {
@@ -550,7 +555,7 @@
*
* <p>See also {@link #isDeviceSecure()} which ignores SIM locked states.
*
- * @return true if a PIN, pattern or password is set or a SIM card is locked.
+ * @return {@code true} if a PIN, pattern or password is set or a SIM card is locked.
*/
public boolean isKeyguardSecure() {
try {
@@ -565,7 +570,7 @@
* keyguard password emergency screen). When in such mode, certain keys,
* such as the Home key and the right soft keys, don't work.
*
- * @return true if in keyguard restricted input mode.
+ * @return {@code true} if in keyguard restricted input mode.
* @deprecated Use {@link #isKeyguardLocked()} instead.
*/
public boolean inKeyguardRestrictedInputMode() {
@@ -576,7 +581,7 @@
* Returns whether the device is currently locked and requires a PIN, pattern or
* password to unlock.
*
- * @return true if unlocking the device currently requires a PIN, pattern or
+ * @return {@code true} if unlocking the device currently requires a PIN, pattern or
* password.
*/
public boolean isDeviceLocked() {
@@ -603,7 +608,7 @@
*
* <p>See also {@link #isKeyguardSecure} which treats SIM locked states as secure.
*
- * @return true if a PIN, pattern or password was set.
+ * @return {@code true} if a PIN, pattern or password was set.
*/
public boolean isDeviceSecure() {
return isDeviceSecure(mContext.getUserId());
@@ -762,7 +767,7 @@
* as the output of String#getBytes
* @param complexity - complexity level imposed by the requester
* as defined in {@code DevicePolicyManager.PasswordComplexity}
- * @return true if the password is valid, false otherwise
+ * @return {@code true} if the password is valid, false otherwise
* @hide
*/
@RequiresPermission(Manifest.permission.SET_INITIAL_LOCK)
@@ -821,7 +826,7 @@
* as the output of String#getBytes
* @param complexity - complexity level imposed by the requester
* as defined in {@code DevicePolicyManager.PasswordComplexity}
- * @return true if the lock is successfully set, false otherwise
+ * @return {@code true} if the lock is successfully set, false otherwise
* @hide
*/
@RequiresPermission(Manifest.permission.SET_INITIAL_LOCK)
@@ -903,8 +908,8 @@
/**
* Remove a weak escrow token.
*
- * @return true if the given handle refers to a valid weak token previously returned from
- * {@link #addWeakEscrowToken}, whether it's active or not. return false otherwise.
+ * @return {@code true} if the given handle refers to a valid weak token previously returned
+ * from {@link #addWeakEscrowToken}, whether it's active or not. return false otherwise.
* @hide
*/
@RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE)
@@ -944,7 +949,7 @@
/**
* Register the given WeakEscrowTokenRemovedListener.
*
- * @return true if the listener is registered successfully, return false otherwise.
+ * @return {@code true} if the listener is registered successfully, return false otherwise.
* @hide
*/
@RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE)
@@ -982,7 +987,7 @@
/**
* Unregister the given WeakEscrowTokenRemovedListener.
*
- * @return true if the listener is unregistered successfully, return false otherwise.
+ * @return {@code true} if the listener is unregistered successfully, return false otherwise.
* @hide
*/
@RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE)
@@ -1076,4 +1081,61 @@
throw new IllegalArgumentException("Unknown lock type " + lockType);
}
}
+
+ /**
+ * Listener for keyguard locked state changes.
+ */
+ @FunctionalInterface
+ public interface KeyguardLockedStateListener {
+ /**
+ * Callback function that executes when the keyguard locked state changes.
+ */
+ void onKeyguardLockedStateChanged(boolean isKeyguardLocked);
+ }
+
+ /**
+ * Registers a listener to execute when the keyguard visibility changes.
+ *
+ * @param listener The listener to add to receive keyguard visibility changes.
+ */
+ @RequiresPermission(Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE)
+ public void addKeyguardLockedStateListener(@NonNull @CallbackExecutor Executor executor,
+ @NonNull KeyguardLockedStateListener listener) {
+ synchronized (mKeyguardLockedStateListeners) {
+ try {
+ final IKeyguardLockedStateListener innerListener =
+ new IKeyguardLockedStateListener.Stub() {
+ @Override
+ public void onKeyguardLockedStateChanged(boolean isKeyguardLocked) {
+ executor.execute(
+ () -> listener.onKeyguardLockedStateChanged(isKeyguardLocked));
+ }
+ };
+ mWM.addKeyguardLockedStateListener(innerListener);
+ mKeyguardLockedStateListeners.put(listener, innerListener);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
+ * Unregisters a listener that executes when the keyguard visibility changes.
+ */
+ @RequiresPermission(Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE)
+ public void removeKeyguardLockedStateListener(@NonNull KeyguardLockedStateListener listener) {
+ synchronized (mKeyguardLockedStateListeners) {
+ IKeyguardLockedStateListener innerListener = mKeyguardLockedStateListeners.get(
+ listener);
+ if (innerListener == null) {
+ return;
+ }
+ try {
+ mWM.removeKeyguardLockedStateListener(innerListener);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ mKeyguardLockedStateListeners.remove(listener);
+ }
+ }
}
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 77c7c6f..cf259e57 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -160,6 +160,13 @@
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 @@
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 @@
}
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,18 +1369,16 @@
Slog.wtf(TAG, "App instance already created for package=" + mPackageName
+ " instance=" + cached);
}
- // TODO Return the cached one, unless it's for the wrong user?
- // For now, we just add WTF checks.
+ mApplication = cached;
+ return cached;
}
}
Application app = null;
- // Temporarily disable per-process app class to investigate b/185177290
-// final String myProcessName = Process.myProcessName();
-// String appClass = mApplicationInfo.getCustomApplicationClassNameForProcess(
-// myProcessName);
- String appClass = mApplicationInfo.className;
+ final String myProcessName = Process.myProcessName();
+ String appClass = mApplicationInfo.getCustomApplicationClassNameForProcess(
+ myProcessName);
if (forceDefaultAppClass || (appClass == null)) {
appClass = "android.app.Application";
}
@@ -1431,8 +1421,8 @@
}
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/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index 0326e11..e460638 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -324,15 +324,15 @@
public @interface RequestResult {}
/**
- * Constant for {@link #setNavBarModeOverride(int)} indicating the default navbar mode.
+ * Constant for {@link #setNavBarMode(int)} indicating the default navbar mode.
*
* @hide
*/
@SystemApi
- public static final int NAV_BAR_MODE_OVERRIDE_NONE = 0;
+ public static final int NAV_BAR_MODE_DEFAULT = 0;
/**
- * Constant for {@link #setNavBarModeOverride(int)} indicating kids navbar mode.
+ * Constant for {@link #setNavBarMode(int)} indicating kids navbar mode.
*
* <p>When used, back and home icons will change drawables and layout, recents will be hidden,
* and the navbar will remain visible when apps are in immersive mode.
@@ -340,15 +340,15 @@
* @hide
*/
@SystemApi
- public static final int NAV_BAR_MODE_OVERRIDE_KIDS = 1;
+ public static final int NAV_BAR_MODE_KIDS = 1;
/** @hide */
- @IntDef(prefix = {"NAV_BAR_MODE_OVERRIDE_"}, value = {
- NAV_BAR_MODE_OVERRIDE_NONE,
- NAV_BAR_MODE_OVERRIDE_KIDS
+ @IntDef(prefix = {"NAV_BAR_MODE_"}, value = {
+ NAV_BAR_MODE_DEFAULT,
+ NAV_BAR_MODE_KIDS
})
@Retention(RetentionPolicy.SOURCE)
- public @interface NavBarModeOverride {}
+ public @interface NavBarMode {}
/**
* State indicating that this sender device is close to a receiver device, so the user can
@@ -926,25 +926,23 @@
}
/**
- * Sets or removes the navigation bar mode override.
+ * Sets or removes the navigation bar mode.
*
- * @param navBarModeOverride the mode of the navigation bar override to be set.
+ * @param navBarMode the mode of the navigation bar to be set.
*
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.STATUS_BAR)
- public void setNavBarModeOverride(@NavBarModeOverride int navBarModeOverride) {
- if (navBarModeOverride != NAV_BAR_MODE_OVERRIDE_NONE
- && navBarModeOverride != NAV_BAR_MODE_OVERRIDE_KIDS) {
- throw new IllegalArgumentException(
- "Supplied navBarModeOverride not supported: " + navBarModeOverride);
+ public void setNavBarMode(@NavBarMode int navBarMode) {
+ if (navBarMode != NAV_BAR_MODE_DEFAULT && navBarMode != NAV_BAR_MODE_KIDS) {
+ throw new IllegalArgumentException("Supplied navBarMode not supported: " + navBarMode);
}
try {
final IStatusBarService svc = getService();
if (svc != null) {
- svc.setNavBarModeOverride(navBarModeOverride);
+ svc.setNavBarMode(navBarMode);
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -952,23 +950,23 @@
}
/**
- * Gets the navigation bar mode override. Returns default value if no override is set.
+ * Gets the navigation bar mode. Returns default value if no mode is set.
*
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.STATUS_BAR)
- public @NavBarModeOverride int getNavBarModeOverride() {
- int navBarModeOverride = NAV_BAR_MODE_OVERRIDE_NONE;
+ public @NavBarMode int getNavBarMode() {
+ int navBarMode = NAV_BAR_MODE_DEFAULT;
try {
final IStatusBarService svc = getService();
if (svc != null) {
- navBarModeOverride = svc.getNavBarModeOverride();
+ navBarMode = svc.getNavBarMode();
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
- return navBarModeOverride;
+ return navBarMode;
}
/**
diff --git a/core/java/android/app/admin/DevicePolicyDrawableResource.java b/core/java/android/app/admin/DevicePolicyDrawableResource.java
index 61ff11b..7fd8e89 100644
--- a/core/java/android/app/admin/DevicePolicyDrawableResource.java
+++ b/core/java/android/app/admin/DevicePolicyDrawableResource.java
@@ -38,7 +38,7 @@
@NonNull private final @DevicePolicyResources.UpdatableDrawableId String mDrawableId;
@NonNull private final @DevicePolicyResources.UpdatableDrawableStyle String mDrawableStyle;
@NonNull private final @DevicePolicyResources.UpdatableDrawableSource String mDrawableSource;
- private final @DrawableRes int mCallingPackageResourceId;
+ private final @DrawableRes int mResourceIdInCallingPackage;
@NonNull private ParcelableResource mResource;
/**
@@ -47,25 +47,25 @@
*
* <p>It will be used to update the drawable defined by {@code drawableId} with style
* {@code drawableStyle} located in source {@code drawableSource} to the drawable with ID
- * {@code callingPackageResourceId} in the calling package</p>
+ * {@code resourceIdInCallingPackage} in the calling package</p>
*
* @param drawableId The ID of the drawable to update.
* @param drawableStyle The style of the drawable to update.
* @param drawableSource The source of the drawable to update.
- * @param callingPackageResourceId The ID of the drawable resource in the calling package to
+ * @param resourceIdInCallingPackage The ID of the drawable resource in the calling package to
* use as an updated resource.
*
* @throws IllegalStateException if the resource with ID
- * {@code callingPackageResourceId} doesn't exist in the {@code context} package.
+ * {@code resourceIdInCallingPackage} doesn't exist in the {@code context} package.
*/
public DevicePolicyDrawableResource(
@NonNull Context context,
@NonNull @DevicePolicyResources.UpdatableDrawableId String drawableId,
@NonNull @DevicePolicyResources.UpdatableDrawableStyle String drawableStyle,
@NonNull @DevicePolicyResources.UpdatableDrawableSource String drawableSource,
- @DrawableRes int callingPackageResourceId) {
- this(drawableId, drawableStyle, drawableSource, callingPackageResourceId,
- new ParcelableResource(context, callingPackageResourceId,
+ @DrawableRes int resourceIdInCallingPackage) {
+ this(drawableId, drawableStyle, drawableSource, resourceIdInCallingPackage,
+ new ParcelableResource(context, resourceIdInCallingPackage,
ParcelableResource.RESOURCE_TYPE_DRAWABLE));
}
@@ -73,7 +73,7 @@
@NonNull @DevicePolicyResources.UpdatableDrawableId String drawableId,
@NonNull @DevicePolicyResources.UpdatableDrawableStyle String drawableStyle,
@NonNull @DevicePolicyResources.UpdatableDrawableSource String drawableSource,
- @DrawableRes int callingPackageResourceId,
+ @DrawableRes int resourceIdInCallingPackage,
@NonNull ParcelableResource resource) {
Objects.requireNonNull(drawableId);
@@ -84,7 +84,7 @@
this.mDrawableId = drawableId;
this.mDrawableStyle = drawableStyle;
this.mDrawableSource = drawableSource;
- this.mCallingPackageResourceId = callingPackageResourceId;
+ this.mResourceIdInCallingPackage = resourceIdInCallingPackage;
this.mResource = resource;
}
@@ -92,24 +92,24 @@
* Creates an object containing the required information for updating an enterprise drawable
* resource using {@link DevicePolicyManager#setDrawables}.
* <p>It will be used to update the drawable defined by {@code drawableId} with style
- * {@code drawableStyle} to the drawable with ID {@code callingPackageResourceId} in the
+ * {@code drawableStyle} to the drawable with ID {@code resourceIdInCallingPackage} in the
* calling package</p>
*
* @param drawableId The ID of the drawable to update.
* @param drawableStyle The style of the drawable to update.
- * @param callingPackageResourceId The ID of the drawable resource in the calling package to
+ * @param resourceIdInCallingPackage The ID of the drawable resource in the calling package to
* use as an updated resource.
*
* @throws IllegalStateException if the resource with ID
- * {@code callingPackageResourceId} doesn't exist in the calling package.
+ * {@code resourceIdInCallingPackage} doesn't exist in the calling package.
*/
public DevicePolicyDrawableResource(
@NonNull Context context,
@NonNull @DevicePolicyResources.UpdatableDrawableId String drawableId,
@NonNull @DevicePolicyResources.UpdatableDrawableStyle String drawableStyle,
- @DrawableRes int callingPackageResourceId) {
+ @DrawableRes int resourceIdInCallingPackage) {
this(context, drawableId, drawableStyle, Drawables.Source.UNDEFINED,
- callingPackageResourceId);
+ resourceIdInCallingPackage);
}
/**
@@ -144,8 +144,8 @@
* resource.
*/
@DrawableRes
- public int getCallingPackageResourceId() {
- return mCallingPackageResourceId;
+ public int getResourceIdInCallingPackage() {
+ return mResourceIdInCallingPackage;
}
/**
@@ -166,14 +166,14 @@
return mDrawableId.equals(other.mDrawableId)
&& mDrawableStyle.equals(other.mDrawableStyle)
&& mDrawableSource.equals(other.mDrawableSource)
- && mCallingPackageResourceId == other.mCallingPackageResourceId
+ && mResourceIdInCallingPackage == other.mResourceIdInCallingPackage
&& mResource.equals(other.mResource);
}
@Override
public int hashCode() {
- return Objects.hash(
- mDrawableId, mDrawableStyle, mDrawableSource, mCallingPackageResourceId, mResource);
+ return Objects.hash(mDrawableId, mDrawableStyle, mDrawableSource,
+ mResourceIdInCallingPackage, mResource);
}
@Override
@@ -186,7 +186,7 @@
dest.writeString(mDrawableId);
dest.writeString(mDrawableStyle);
dest.writeString(mDrawableSource);
- dest.writeInt(mCallingPackageResourceId);
+ dest.writeInt(mResourceIdInCallingPackage);
dest.writeTypedObject(mResource, flags);
}
@@ -197,11 +197,11 @@
String drawableId = in.readString();
String drawableStyle = in.readString();
String drawableSource = in.readString();
- int callingPackageResourceId = in.readInt();
+ int resourceIdInCallingPackage = in.readInt();
ParcelableResource resource = in.readTypedObject(ParcelableResource.CREATOR);
return new DevicePolicyDrawableResource(
- drawableId, drawableStyle, drawableSource, callingPackageResourceId,
+ drawableId, drawableStyle, drawableSource, resourceIdInCallingPackage,
resource);
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 753df3d..b944468 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -132,11 +132,11 @@
import java.util.Map;
import java.util.Objects;
import java.util.Set;
-import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
+import java.util.function.Supplier;
// TODO(b/172376923) - add CarDevicePolicyManager examples below (or remove reference to it).
/**
@@ -3611,42 +3611,45 @@
/**
* Broadcast action: notify system apps (e.g. settings, SysUI, etc) that the device management
- * resources with IDs {@link #EXTRA_RESOURCE_ID} has been updated, the updated resources can be
+ * resources with IDs {@link #EXTRA_RESOURCE_IDS} has been updated, the updated resources can be
* retrieved using {@link #getDrawable} and {@code #getString}.
*
* <p>This broadcast is sent to registered receivers only.
*
- * <p> The following extras will be included to identify the type of resource being updated:
- * <ul>
- * <li>{@link #EXTRA_RESOURCE_TYPE_DRAWABLE} for drawable resources</li>
- * <li>{@link #EXTRA_RESOURCE_TYPE_STRING} for string resources</li>
- * </ul>
+ * <p> {@link #EXTRA_RESOURCE_TYPE} will be included to identify the type of resource being
+ * updated.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_DEVICE_POLICY_RESOURCE_UPDATED =
"android.app.action.DEVICE_POLICY_RESOURCE_UPDATED";
/**
- * A boolean extra for {@link #ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to indicate that a
- * resource of type {@link Drawable} is being updated.
+ * An {@code int} extra for {@link #ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to indicate the type
+ * of the resource being updated, the type can be {@link #EXTRA_RESOURCE_TYPE_DRAWABLE} or
+ * {@link #EXTRA_RESOURCE_TYPE_STRING}
*/
- public static final String EXTRA_RESOURCE_TYPE_DRAWABLE =
- "android.app.extra.RESOURCE_TYPE_DRAWABLE";
+ public static final String EXTRA_RESOURCE_TYPE =
+ "android.app.extra.RESOURCE_TYPE";
/**
- * A boolean extra for {@link #ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to indicate that a
- * resource of type {@link String} is being updated.
+ * A {@code int} value for {@link #EXTRA_RESOURCE_TYPE} to indicate that a resource of type
+ * {@link Drawable} is being updated.
*/
- public static final String EXTRA_RESOURCE_TYPE_STRING =
- "android.app.extra.RESOURCE_TYPE_STRING";
+ public static final int EXTRA_RESOURCE_TYPE_DRAWABLE = 1;
+
+ /**
+ * A {@code int} value for {@link #EXTRA_RESOURCE_TYPE} to indicate that a resource of type
+ * {@link String} is being updated.
+ */
+ public static final int EXTRA_RESOURCE_TYPE_STRING = 2;
/**
* An integer array extra for {@link #ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to indicate which
- * resource IDs (see {@link DevicePolicyResources.UpdatableDrawableId} and
- * {@link DevicePolicyResources.UpdatableStringId}) have been updated.
+ * resource IDs (see {@link DevicePolicyResources.Drawables} and
+ * {@link DevicePolicyResources.Strings}) have been updated.
*/
- public static final String EXTRA_RESOURCE_ID =
- "android.app.extra.RESOURCE_ID";
+ public static final String EXTRA_RESOURCE_IDS =
+ "android.app.extra.RESOURCE_IDS";
/** @hide */
@NonNull
@@ -7024,10 +7027,10 @@
* management app can use {@link #ID_TYPE_BASE_INFO} to request inclusion of the general device
* information including manufacturer, model, brand, device and product in the attestation
* record.
- * Only device owner, profile owner on an organization-owned device and their delegated
- * certificate installers can use {@link #ID_TYPE_SERIAL}, {@link #ID_TYPE_IMEI} and
- * {@link #ID_TYPE_MEID} to request unique device identifiers to be attested (the serial number,
- * IMEI and MEID correspondingly), if supported by the device
+ * Only device owner, profile owner on an organization-owned device or affiliated user, and
+ * their delegated certificate installers can use {@link #ID_TYPE_SERIAL}, {@link #ID_TYPE_IMEI}
+ * and {@link #ID_TYPE_MEID} to request unique device identifiers to be attested (the serial
+ * number, IMEI and MEID correspondingly), if supported by the device
* (see {@link #isDeviceIdAttestationSupported()}).
* Additionally, device owner, profile owner on an organization-owned device and their delegated
* certificate installers can also request the attestation record to be signed using an
@@ -7913,6 +7916,10 @@
/**
* Returns the current runtime nearby notification streaming policy set by the device or profile
* owner.
+ * <p>
+ * The caller must be the target user's device owner/profile owner or hold the
+ * {@link android.Manifest.permission#READ_NEARBY_STREAMING_POLICY READ_NEARBY_STREAMING_POLICY}
+ * permission.
*/
@RequiresPermission(
value = android.Manifest.permission.READ_NEARBY_STREAMING_POLICY,
@@ -7956,6 +7963,10 @@
/**
* Returns the current runtime nearby app streaming policy set by the device or profile owner.
+ * <p>
+ * The caller must be the target user's device owner/profile owner or hold the
+ * {@link android.Manifest.permission#READ_NEARBY_STREAMING_POLICY READ_NEARBY_STREAMING_POLICY}
+ * permission.
*/
@RequiresPermission(
value = android.Manifest.permission.READ_NEARBY_STREAMING_POLICY,
@@ -15123,7 +15134,7 @@
* the combination of {@link DevicePolicyDrawableResource#getDrawableId()} and
* {@link DevicePolicyDrawableResource#getDrawableStyle()}, (see
* {@link DevicePolicyResources.Drawables} and {@link DevicePolicyResources.Drawables.Style}) to
- * the drawable with ID {@link DevicePolicyDrawableResource#getCallingPackageResourceId()},
+ * the drawable with ID {@link DevicePolicyDrawableResource#getResourceIdInCallingPackage()},
* meaning any system UI surface calling {@link #getDrawable}
* with {@code drawableId} and {@code drawableStyle} will get the new resource after this API
* is called.
@@ -15138,12 +15149,12 @@
* <p>Important notes to consider when using this API:
* <ul>
* <li>{@link #getDrawable} references the resource
- * {@link DevicePolicyDrawableResource#getCallingPackageResourceId()} in the
+ * {@link DevicePolicyDrawableResource#getResourceIdInCallingPackage()} in the
* calling package each time it gets called. You have to ensure that the resource is always
* available in the calling package as long as it is used as an updated resource.
* <li>You still have to re-call {@code setDrawables} even if you only make changes to the
* content of the resource with ID
- * {@link DevicePolicyDrawableResource#getCallingPackageResourceId()} as the content might be
+ * {@link DevicePolicyDrawableResource#getResourceIdInCallingPackage()} as the content might be
* cached and would need updating.
* </ul>
*
@@ -15204,7 +15215,7 @@
*
* <p>This API uses the screen density returned from {@link Resources#getConfiguration()}, to
* set a different value use
- * {@link #getDrawableForDensity(String, String, int, Callable)}.
+ * {@link #getDrawableForDensity(String, String, int, Supplier)}.
*
* <p>Callers should register for {@link #ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to get
* notified when a resource has been updated.
@@ -15221,16 +15232,16 @@
public Drawable getDrawable(
@NonNull @DevicePolicyResources.UpdatableDrawableId String drawableId,
@NonNull @DevicePolicyResources.UpdatableDrawableStyle String drawableStyle,
- @NonNull Callable<Drawable> defaultDrawableLoader) {
+ @NonNull Supplier<Drawable> defaultDrawableLoader) {
return getDrawable(
drawableId, drawableStyle, Drawables.Source.UNDEFINED, defaultDrawableLoader);
}
/**
- * Similar to {@link #getDrawable(String, String, Callable)}, but also accepts
+ * Similar to {@link #getDrawable(String, String, Supplier)}, but also accepts
* a {@code drawableSource} (see {@link DevicePolicyResources.Drawables.Source}) which
* could result in returning a different drawable than
- * {@link #getDrawable(String, String, Callable)}
+ * {@link #getDrawable(String, String, Supplier)}
* if an override was set for that specific source.
*
* <p>Calls to this API will not return {@code null} unless no updated drawable was found
@@ -15250,7 +15261,7 @@
@NonNull @DevicePolicyResources.UpdatableDrawableId String drawableId,
@NonNull @DevicePolicyResources.UpdatableDrawableStyle String drawableStyle,
@NonNull @DevicePolicyResources.UpdatableDrawableSource String drawableSource,
- @NonNull Callable<Drawable> defaultDrawableLoader) {
+ @NonNull Supplier<Drawable> defaultDrawableLoader) {
Objects.requireNonNull(drawableId, "drawableId can't be null");
Objects.requireNonNull(drawableStyle, "drawableStyle can't be null");
@@ -15285,7 +15296,7 @@
}
/**
- * Similar to {@link #getDrawable(String, String, Callable)}, but also accepts
+ * Similar to {@link #getDrawable(String, String, Supplier)}, but also accepts
* {@code density}. See {@link Resources#getDrawableForDensity(int, int, Resources.Theme)}.
*
* <p>Calls to this API will not return {@code null} unless no updated drawable was found
@@ -15307,7 +15318,7 @@
@NonNull @DevicePolicyResources.UpdatableDrawableId String drawableId,
@NonNull @DevicePolicyResources.UpdatableDrawableStyle String drawableStyle,
int density,
- @NonNull Callable<Drawable> defaultDrawableLoader) {
+ @NonNull Supplier<Drawable> defaultDrawableLoader) {
return getDrawableForDensity(
drawableId,
drawableStyle,
@@ -15317,7 +15328,7 @@
}
/**
- * Similar to {@link #getDrawable(String, String, String, Callable)}, but also accepts
+ * Similar to {@link #getDrawable(String, String, String, Supplier)}, but also accepts
* {@code density}. See {@link Resources#getDrawableForDensity(int, int, Resources.Theme)}.
*
* <p>Calls to this API will not return {@code null} unless no updated drawable was found
@@ -15341,7 +15352,7 @@
@NonNull @DevicePolicyResources.UpdatableDrawableStyle String drawableStyle,
@NonNull @DevicePolicyResources.UpdatableDrawableSource String drawableSource,
int density,
- @NonNull Callable<Drawable> defaultDrawableLoader) {
+ @NonNull Supplier<Drawable> defaultDrawableLoader) {
Objects.requireNonNull(drawableId, "drawableId can't be null");
Objects.requireNonNull(drawableStyle, "drawableStyle can't be null");
@@ -15372,7 +15383,7 @@
}
/**
- * Similar to {@link #getDrawable(String, String, String, Callable)} but returns an
+ * Similar to {@link #getDrawable(String, String, String, Supplier)} but returns an
* {@link Icon} instead of a {@link Drawable}.
*
* @param drawableId The drawable ID to get the updated resource for.
@@ -15414,7 +15425,7 @@
}
/**
- * Similar to {@link #getDrawable(String, String, Callable)} but returns an {@link Icon}
+ * Similar to {@link #getDrawable(String, String, Supplier)} but returns an {@link Icon}
* instead of a {@link Drawable}.
*
* @param drawableId The drawable ID to get the updated resource for.
@@ -15520,7 +15531,7 @@
@Nullable
public String getString(
@NonNull @DevicePolicyResources.UpdatableStringId String stringId,
- @NonNull Callable<String> defaultStringLoader) {
+ @NonNull Supplier<String> defaultStringLoader) {
Objects.requireNonNull(stringId, "stringId can't be null");
Objects.requireNonNull(defaultStringLoader, "defaultStringLoader can't be null");
@@ -15547,7 +15558,7 @@
}
/**
- * Similar to {@link #getString(String, Callable)} but accepts {@code formatArgs} and returns a
+ * Similar to {@link #getString(String, Supplier)} but accepts {@code formatArgs} and returns a
* localized formatted string, substituting the format arguments as defined in
* {@link java.util.Formatter} and {@link java.lang.String#format}, (see
* {@link Resources#getString(int, Object...)}).
@@ -15567,7 +15578,7 @@
@SuppressLint("SamShouldBeLast")
public String getString(
@NonNull @DevicePolicyResources.UpdatableStringId String stringId,
- @NonNull Callable<String> defaultStringLoader,
+ @NonNull Supplier<String> defaultStringLoader,
@NonNull Object... formatArgs) {
Objects.requireNonNull(stringId, "stringId can't be null");
diff --git a/core/java/android/app/admin/DevicePolicyStringResource.java b/core/java/android/app/admin/DevicePolicyStringResource.java
index 5f09bfd..b36f1408 100644
--- a/core/java/android/app/admin/DevicePolicyStringResource.java
+++ b/core/java/android/app/admin/DevicePolicyStringResource.java
@@ -35,7 +35,7 @@
@SystemApi
public final class DevicePolicyStringResource implements Parcelable {
@NonNull private final @DevicePolicyResources.UpdatableStringId String mStringId;
- private final @StringRes int mCallingPackageResourceId;
+ private final @StringRes int mResourceIdInCallingPackage;
@NonNull private ParcelableResource mResource;
/**
@@ -43,32 +43,32 @@
* resource using {@link DevicePolicyManager#setStrings}.
*
* <p>It will be used to update the string defined by {@code stringId} to the string with ID
- * {@code callingPackageResourceId} in the calling package</p>
+ * {@code resourceIdInCallingPackage} in the calling package</p>
*
* @param stringId The ID of the string to update.
- * @param callingPackageResourceId The ID of the {@link StringRes} in the calling package to
+ * @param resourceIdInCallingPackage The ID of the {@link StringRes} in the calling package to
* use as an updated resource.
*
- * @throws IllegalStateException if the resource with ID {@code callingPackageResourceId}
+ * @throws IllegalStateException if the resource with ID {@code resourceIdInCallingPackage}
* doesn't exist in the {@code context} package.
*/
public DevicePolicyStringResource(
@NonNull Context context,
@NonNull @DevicePolicyResources.UpdatableStringId String stringId,
- @StringRes int callingPackageResourceId) {
- this(stringId, callingPackageResourceId, new ParcelableResource(
- context, callingPackageResourceId, ParcelableResource.RESOURCE_TYPE_STRING));
+ @StringRes int resourceIdInCallingPackage) {
+ this(stringId, resourceIdInCallingPackage, new ParcelableResource(
+ context, resourceIdInCallingPackage, ParcelableResource.RESOURCE_TYPE_STRING));
}
private DevicePolicyStringResource(
@NonNull @DevicePolicyResources.UpdatableStringId String stringId,
- @StringRes int callingPackageResourceId,
+ @StringRes int resourceIdInCallingPackage,
@NonNull ParcelableResource resource) {
Objects.requireNonNull(stringId, "stringId must be provided.");
Objects.requireNonNull(resource, "ParcelableResource must be provided.");
this.mStringId = stringId;
- this.mCallingPackageResourceId = callingPackageResourceId;
+ this.mResourceIdInCallingPackage = resourceIdInCallingPackage;
this.mResource = resource;
}
@@ -85,8 +85,8 @@
* Returns the ID of the {@link StringRes} in the calling package to use as an updated
* resource.
*/
- public int getCallingPackageResourceId() {
- return mCallingPackageResourceId;
+ public int getResourceIdInCallingPackage() {
+ return mResourceIdInCallingPackage;
}
/**
@@ -105,13 +105,13 @@
if (o == null || getClass() != o.getClass()) return false;
DevicePolicyStringResource other = (DevicePolicyStringResource) o;
return mStringId == other.mStringId
- && mCallingPackageResourceId == other.mCallingPackageResourceId
+ && mResourceIdInCallingPackage == other.mResourceIdInCallingPackage
&& mResource.equals(other.mResource);
}
@Override
public int hashCode() {
- return Objects.hash(mStringId, mCallingPackageResourceId, mResource);
+ return Objects.hash(mStringId, mResourceIdInCallingPackage, mResource);
}
@Override
@@ -122,7 +122,7 @@
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeString(mStringId);
- dest.writeInt(mCallingPackageResourceId);
+ dest.writeInt(mResourceIdInCallingPackage);
dest.writeTypedObject(mResource, flags);
}
@@ -131,10 +131,10 @@
@Override
public DevicePolicyStringResource createFromParcel(Parcel in) {
String stringId = in.readString();
- int callingPackageResourceId = in.readInt();
+ int resourceIdInCallingPackage = in.readInt();
ParcelableResource resource = in.readTypedObject(ParcelableResource.CREATOR);
- return new DevicePolicyStringResource(stringId, callingPackageResourceId, resource);
+ return new DevicePolicyStringResource(stringId, resourceIdInCallingPackage, resource);
}
@Override
diff --git a/core/java/android/app/admin/ParcelableResource.java b/core/java/android/app/admin/ParcelableResource.java
index 0b1b166..bcae284 100644
--- a/core/java/android/app/admin/ParcelableResource.java
+++ b/core/java/android/app/admin/ParcelableResource.java
@@ -39,7 +39,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
-import java.util.concurrent.Callable;
+import java.util.function.Supplier;
/**
* Used to store the required information to load a resource that was updated using
@@ -179,7 +179,7 @@
public Drawable getDrawable(
Context context,
int density,
- @NonNull Callable<Drawable> defaultDrawableLoader) {
+ @NonNull Supplier<Drawable> defaultDrawableLoader) {
// TODO(b/203548565): properly handle edge case when the device manager role holder is
// unavailable because it's being updated.
try {
@@ -203,7 +203,7 @@
@Nullable
public String getString(
Context context,
- @NonNull Callable<String> defaultStringLoader) {
+ @NonNull Supplier<String> defaultStringLoader) {
// TODO(b/203548565): properly handle edge case when the device manager role holder is
// unavailable because it's being updated.
try {
@@ -227,7 +227,7 @@
@Nullable
public String getString(
Context context,
- @NonNull Callable<String> defaultStringLoader,
+ @NonNull Supplier<String> defaultStringLoader,
@NonNull Object... formatArgs) {
// TODO(b/203548565): properly handle edge case when the device manager role holder is
// unavailable because it's being updated.
@@ -268,26 +268,18 @@
* returns the {@link Drawable} loaded from calling {@code defaultDrawableLoader}.
*/
@Nullable
- public static Drawable loadDefaultDrawable(@NonNull Callable<Drawable> defaultDrawableLoader) {
- try {
- Objects.requireNonNull(defaultDrawableLoader, "defaultDrawableLoader can't be null");
- return defaultDrawableLoader.call();
- } catch (Exception e) {
- throw new RuntimeException("Couldn't load default drawable: ", e);
- }
+ public static Drawable loadDefaultDrawable(@NonNull Supplier<Drawable> defaultDrawableLoader) {
+ Objects.requireNonNull(defaultDrawableLoader, "defaultDrawableLoader can't be null");
+ return defaultDrawableLoader.get();
}
/**
* returns the {@link String} loaded from calling {@code defaultStringLoader}.
*/
@Nullable
- public static String loadDefaultString(@NonNull Callable<String> defaultStringLoader) {
- try {
- Objects.requireNonNull(defaultStringLoader, "defaultStringLoader can't be null");
- return defaultStringLoader.call();
- } catch (Exception e) {
- throw new RuntimeException("Couldn't load default string: ", e);
- }
+ public static String loadDefaultString(@NonNull Supplier<String> defaultStringLoader) {
+ Objects.requireNonNull(defaultStringLoader, "defaultStringLoader can't be null");
+ return defaultStringLoader.get();
}
/**
diff --git a/core/java/android/app/smartspace/SmartspaceTarget.java b/core/java/android/app/smartspace/SmartspaceTarget.java
index fd7088f..be077435 100644
--- a/core/java/android/app/smartspace/SmartspaceTarget.java
+++ b/core/java/android/app/smartspace/SmartspaceTarget.java
@@ -159,6 +159,24 @@
public static final int FEATURE_TIMER = 21;
public static final int FEATURE_STOPWATCH = 22;
public static final int FEATURE_UPCOMING_ALARM = 23;
+ public static final int FEATURE_GAS_STATION_PAYMENT = 24;
+ public static final int FEATURE_PAIRED_DEVICE_STATE = 25;
+ public static final int FEATURE_DRIVING_MODE = 26;
+ public static final int FEATURE_SLEEP_SUMMARY = 27;
+ public static final int FEATURE_FLASHLIGHT = 28;
+ public static final int FEATURE_TIME_TO_LEAVE = 29;
+ public static final int FEATURE_DOORBELL = 30;
+ public static final int FEATURE_MEDIA_RESUME = 31;
+ public static final int FEATURE_CROSS_DEVICE_TIMER = 32;
+ public static final int FEATURE_SEVERE_WEATHER_ALERT = 33;
+ public static final int FEATURE_HOLIDAY_ALARM = 34;
+ public static final int FEATURE_SAFETY_CHECK = 35;
+ public static final int FEATURE_MEDIA_HEADS_UP = 36;
+ public static final int FEATURE_STEP_COUNTING = 37;
+ public static final int FEATURE_EARTHQUAKE_ALERT = 38;
+ public static final int FEATURE_STEP_DATE = 39;
+ public static final int FEATURE_BLAZE_BUILD_PROGRESS = 40;
+ public static final int FEATURE_EARTHQUAKE_OCCURRED = 41;
/**
* @hide
@@ -187,7 +205,25 @@
FEATURE_PACKAGE_TRACKING,
FEATURE_TIMER,
FEATURE_STOPWATCH,
- FEATURE_UPCOMING_ALARM
+ FEATURE_UPCOMING_ALARM,
+ FEATURE_GAS_STATION_PAYMENT,
+ FEATURE_PAIRED_DEVICE_STATE,
+ FEATURE_DRIVING_MODE,
+ FEATURE_SLEEP_SUMMARY,
+ FEATURE_FLASHLIGHT,
+ FEATURE_TIME_TO_LEAVE,
+ FEATURE_DOORBELL,
+ FEATURE_MEDIA_RESUME,
+ FEATURE_CROSS_DEVICE_TIMER,
+ FEATURE_SEVERE_WEATHER_ALERT,
+ FEATURE_HOLIDAY_ALARM,
+ FEATURE_SAFETY_CHECK,
+ FEATURE_MEDIA_HEADS_UP,
+ FEATURE_STEP_COUNTING,
+ FEATURE_EARTHQUAKE_ALERT,
+ FEATURE_STEP_DATE,
+ FEATURE_BLAZE_BUILD_PROGRESS,
+ FEATURE_EARTHQUAKE_OCCURRED
})
@Retention(RetentionPolicy.SOURCE)
public @interface FeatureType {
diff --git a/core/java/android/app/smartspace/uitemplatedata/BaseTemplateData.java b/core/java/android/app/smartspace/uitemplatedata/BaseTemplateData.java
index 584b176..e3cb67a 100644
--- a/core/java/android/app/smartspace/uitemplatedata/BaseTemplateData.java
+++ b/core/java/android/app/smartspace/uitemplatedata/BaseTemplateData.java
@@ -20,10 +20,12 @@
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
+import android.app.smartspace.SmartspaceTarget.FeatureType;
import android.app.smartspace.SmartspaceTarget.UiTemplateType;
import android.app.smartspace.SmartspaceUtils;
import android.os.Parcel;
import android.os.Parcelable;
+import android.text.TextUtils;
import java.util.Objects;
@@ -57,81 +59,39 @@
/**
* Title text and title icon are shown at the first row. When both are absent, the date view
* will be used, which has its own tap action applied to the title area.
+ *
+ * Primary tap action for the entire card, including the blank spaces, except: 1. When title is
+ * absent, the date view's default tap action is used; 2. Subtitle/Supplemental subtitle uses
+ * its own tap action if being set; 3. Secondary card uses its own tap action if being set.
*/
@Nullable
- private final Text mTitleText;
+ private final SubItemInfo mPrimaryItem;
- @Nullable
- private final Icon mTitleIcon;
/** Subtitle text and icon are shown at the second row. */
@Nullable
- private final Text mSubtitleText;
-
- @Nullable
- private final Icon mSubtitleIcon;
-
- /**
- * Primary tap action for the entire card, including the blank spaces, except: 1. When title is
- * absent, the date view's default tap action is used; 2. Supplemental subtitle uses its own tap
- * action if being set; 3. Secondary card uses its own tap action if being set.
- */
- @Nullable
- private final TapAction mPrimaryTapAction;
-
- /**
- * Primary logging info for the entire card. This will only be used when rendering a sub card
- * within the base card. For the base card itself, BcSmartspaceCardLoggingInfo should be used,
- * which has the display-specific info (e.g. display surface).
- */
- @Nullable
- private final SubItemLoggingInfo mPrimaryLoggingInfo;
+ private final SubItemInfo mSubtitleItem;
/**
* Supplemental subtitle text and icon are shown at the second row following the subtitle text.
* Mainly used for weather info on non-weather card.
*/
@Nullable
- private final Text mSupplementalSubtitleText;
-
- @Nullable
- private final Icon mSupplementalSubtitleIcon;
+ private final SubItemInfo mSubtitleSupplementalItem;
/**
- * Tap action for the supplemental subtitle's text and icon. Uses the primary tap action if
- * not being set.
+ * Supplemental line is shown at the third row.
*/
@Nullable
- private final TapAction mSupplementalSubtitleTapAction;
+ private final SubItemInfo mSupplementalLineItem;
/**
- * Logging info for the supplemental subtitle's are. Uses the primary logging info if not being
- * set.
+ * Supplemental alarm item is specifically used for holiday alarm, which is appended to "next
+ * alarm". This is also shown at the third row, but won't be shown the same time with
+ * mSupplementalLineItem.
*/
@Nullable
- private final SubItemLoggingInfo mSupplementalSubtitleLoggingInfo;
-
- @Nullable
- private final Text mSupplementalText;
-
- @Nullable
- private final Icon mSupplementalIcon;
-
- @Nullable
- private final TapAction mSupplementalTapAction;
-
- /**
- * Logging info for the supplemental line. Uses the primary logging info if not being set.
- */
- @Nullable
- private final SubItemLoggingInfo mSupplementalLoggingInfo;
-
- /**
- * Supplemental alarm text is specifically used for holiday alarm, which is appended to "next
- * alarm".
- */
- @Nullable
- private final Text mSupplementalAlarmText;
+ private final SubItemInfo mSupplementalAlarmItem;
/**
* The layout weight info for the card, which indicates how much space it should occupy on the
@@ -141,21 +101,11 @@
BaseTemplateData(@NonNull Parcel in) {
mTemplateType = in.readInt();
- mTitleText = in.readTypedObject(Text.CREATOR);
- mTitleIcon = in.readTypedObject(Icon.CREATOR);
- mSubtitleText = in.readTypedObject(Text.CREATOR);
- mSubtitleIcon = in.readTypedObject(Icon.CREATOR);
- mPrimaryTapAction = in.readTypedObject(TapAction.CREATOR);
- mPrimaryLoggingInfo = in.readTypedObject(SubItemLoggingInfo.CREATOR);
- mSupplementalSubtitleText = in.readTypedObject(Text.CREATOR);
- mSupplementalSubtitleIcon = in.readTypedObject(Icon.CREATOR);
- mSupplementalSubtitleTapAction = in.readTypedObject(TapAction.CREATOR);
- mSupplementalSubtitleLoggingInfo = in.readTypedObject(SubItemLoggingInfo.CREATOR);
- mSupplementalText = in.readTypedObject(Text.CREATOR);
- mSupplementalIcon = in.readTypedObject(Icon.CREATOR);
- mSupplementalTapAction = in.readTypedObject(TapAction.CREATOR);
- mSupplementalLoggingInfo = in.readTypedObject(SubItemLoggingInfo.CREATOR);
- mSupplementalAlarmText = in.readTypedObject(Text.CREATOR);
+ mPrimaryItem = in.readTypedObject(SubItemInfo.CREATOR);
+ mSubtitleItem = in.readTypedObject(SubItemInfo.CREATOR);
+ mSubtitleSupplementalItem = in.readTypedObject(SubItemInfo.CREATOR);
+ mSupplementalLineItem = in.readTypedObject(SubItemInfo.CREATOR);
+ mSupplementalAlarmItem = in.readTypedObject(SubItemInfo.CREATOR);
mLayoutWeight = in.readInt();
}
@@ -164,38 +114,18 @@
* SmartspaceDefaultUiTemplateData.Builder.
*/
BaseTemplateData(@UiTemplateType int templateType,
- @Nullable Text titleText,
- @Nullable Icon titleIcon,
- @Nullable Text subtitleText,
- @Nullable Icon subtitleIcon,
- @Nullable TapAction primaryTapAction,
- @Nullable SubItemLoggingInfo primaryLoggingInfo,
- @Nullable Text supplementalSubtitleText,
- @Nullable Icon supplementalSubtitleIcon,
- @Nullable TapAction supplementalSubtitleTapAction,
- @Nullable SubItemLoggingInfo supplementalSubtitleLoggingInfo,
- @Nullable Text supplementalText,
- @Nullable Icon supplementalIcon,
- @Nullable TapAction supplementalTapAction,
- @Nullable SubItemLoggingInfo supplementalLoggingInfo,
- @Nullable Text supplementalAlarmText,
+ @Nullable SubItemInfo primaryItem,
+ @Nullable SubItemInfo subtitleItem,
+ @Nullable SubItemInfo subtitleSupplementalItem,
+ @Nullable SubItemInfo supplementalLineItem,
+ @Nullable SubItemInfo supplementalAlarmItem,
int layoutWeight) {
mTemplateType = templateType;
- mTitleText = titleText;
- mTitleIcon = titleIcon;
- mSubtitleText = subtitleText;
- mSubtitleIcon = subtitleIcon;
- mPrimaryTapAction = primaryTapAction;
- mPrimaryLoggingInfo = primaryLoggingInfo;
- mSupplementalSubtitleText = supplementalSubtitleText;
- mSupplementalSubtitleIcon = supplementalSubtitleIcon;
- mSupplementalSubtitleTapAction = supplementalSubtitleTapAction;
- mSupplementalSubtitleLoggingInfo = supplementalSubtitleLoggingInfo;
- mSupplementalText = supplementalText;
- mSupplementalIcon = supplementalIcon;
- mSupplementalTapAction = supplementalTapAction;
- mSupplementalLoggingInfo = supplementalLoggingInfo;
- mSupplementalAlarmText = supplementalAlarmText;
+ mPrimaryItem = primaryItem;
+ mSubtitleItem = subtitleItem;
+ mSubtitleSupplementalItem = subtitleSupplementalItem;
+ mSupplementalLineItem = supplementalLineItem;
+ mSupplementalAlarmItem = supplementalAlarmItem;
mLayoutWeight = layoutWeight;
}
@@ -205,94 +135,34 @@
return mTemplateType;
}
- /** Returns the title's text. */
+ /** Returns the primary item (the first line). */
@Nullable
- public Text getTitleText() {
- return mTitleText;
+ public SubItemInfo getPrimaryItem() {
+ return mPrimaryItem;
}
- /** Returns the title's icon. */
+ /** Returns the subtitle item (the second line). */
@Nullable
- public Icon getTitleIcon() {
- return mTitleIcon;
+ public SubItemInfo getSubtitleItem() {
+ return mSubtitleItem;
}
- /** Returns the subtitle's text. */
+ /** Returns the subtitle's supplemental item (the second line following the subtitle). */
@Nullable
- public Text getSubtitleText() {
- return mSubtitleText;
+ public SubItemInfo getSubtitleSupplementalItem() {
+ return mSubtitleSupplementalItem;
}
- /** Returns the subtitle's icon. */
+ /** Returns the supplemental line item (the 3rd line). */
@Nullable
- public Icon getSubtitleIcon() {
- return mSubtitleIcon;
+ public SubItemInfo getSupplementalLineItem() {
+ return mSupplementalLineItem;
}
- /** Returns the card's primary tap action. */
+ /** Returns the supplemental alarm item (the 3rd line). */
@Nullable
- public TapAction getPrimaryTapAction() {
- return mPrimaryTapAction;
- }
-
- /** Returns the card's primary logging info. */
- @Nullable
- public SubItemLoggingInfo getPrimaryLoggingInfo() {
- return mPrimaryLoggingInfo;
- }
-
- /** Returns the supplemental subtitle's text. */
- @Nullable
- public Text getSupplementalSubtitleText() {
- return mSupplementalSubtitleText;
- }
-
- /** Returns the supplemental subtitle's icon. */
- @Nullable
- public Icon getSupplementalSubtitleIcon() {
- return mSupplementalSubtitleIcon;
- }
-
- /** Returns the supplemental subtitle's tap action. Can be null if not being set. */
- @Nullable
- public TapAction getSupplementalSubtitleTapAction() {
- return mSupplementalSubtitleTapAction;
- }
-
- /** Returns the card's supplemental title's logging info. */
- @Nullable
- public SubItemLoggingInfo getSupplementalSubtitleLoggingInfo() {
- return mSupplementalSubtitleLoggingInfo;
- }
-
- /** Returns the supplemental text. */
- @Nullable
- public Text getSupplementalText() {
- return mSupplementalText;
- }
-
- /** Returns the supplemental icon. */
- @Nullable
- public Icon getSupplementalIcon() {
- return mSupplementalIcon;
- }
-
- /** Returns the supplemental line's tap action. Can be null if not being set. */
- @Nullable
- public TapAction getSupplementalTapAction() {
- return mSupplementalTapAction;
- }
-
- /** Returns the card's supplemental line logging info. */
- @Nullable
- public SubItemLoggingInfo getSupplementalLoggingInfo() {
- return mSupplementalLoggingInfo;
- }
-
- /** Returns the supplemental alarm text. */
- @Nullable
- public Text getSupplementalAlarmText() {
- return mSupplementalAlarmText;
+ public SubItemInfo getSupplementalAlarmItem() {
+ return mSupplementalAlarmItem;
}
/** Returns the card layout weight info. Default weight is 0. */
@@ -325,21 +195,11 @@
@Override
public void writeToParcel(@NonNull Parcel out, int flags) {
out.writeInt(mTemplateType);
- out.writeTypedObject(mTitleText, flags);
- out.writeTypedObject(mTitleIcon, flags);
- out.writeTypedObject(mSubtitleText, flags);
- out.writeTypedObject(mSubtitleIcon, flags);
- out.writeTypedObject(mPrimaryTapAction, flags);
- out.writeTypedObject(mPrimaryLoggingInfo, flags);
- out.writeTypedObject(mSupplementalSubtitleText, flags);
- out.writeTypedObject(mSupplementalSubtitleIcon, flags);
- out.writeTypedObject(mSupplementalSubtitleTapAction, flags);
- out.writeTypedObject(mSupplementalSubtitleLoggingInfo, flags);
- out.writeTypedObject(mSupplementalText, flags);
- out.writeTypedObject(mSupplementalIcon, flags);
- out.writeTypedObject(mSupplementalTapAction, flags);
- out.writeTypedObject(mSupplementalLoggingInfo, flags);
- out.writeTypedObject(mSupplementalAlarmText, flags);
+ out.writeTypedObject(mPrimaryItem, flags);
+ out.writeTypedObject(mSubtitleItem, flags);
+ out.writeTypedObject(mSubtitleSupplementalItem, flags);
+ out.writeTypedObject(mSupplementalLineItem, flags);
+ out.writeTypedObject(mSupplementalAlarmItem, flags);
out.writeInt(mLayoutWeight);
}
@@ -348,58 +208,29 @@
if (this == o) return true;
if (!(o instanceof BaseTemplateData)) return false;
BaseTemplateData that = (BaseTemplateData) o;
- return mTemplateType == that.mTemplateType && SmartspaceUtils.isEqual(mTitleText,
- that.mTitleText)
- && Objects.equals(mTitleIcon, that.mTitleIcon)
- && SmartspaceUtils.isEqual(mSubtitleText, that.mSubtitleText)
- && Objects.equals(mSubtitleIcon, that.mSubtitleIcon)
- && Objects.equals(mPrimaryTapAction, that.mPrimaryTapAction)
- && Objects.equals(mPrimaryLoggingInfo, that.mPrimaryLoggingInfo)
- && SmartspaceUtils.isEqual(mSupplementalSubtitleText,
- that.mSupplementalSubtitleText)
- && Objects.equals(mSupplementalSubtitleIcon, that.mSupplementalSubtitleIcon)
- && Objects.equals(mSupplementalSubtitleTapAction,
- that.mSupplementalSubtitleTapAction)
- && Objects.equals(mSupplementalSubtitleLoggingInfo,
- that.mSupplementalSubtitleLoggingInfo)
- && SmartspaceUtils.isEqual(mSupplementalText,
- that.mSupplementalText)
- && Objects.equals(mSupplementalIcon, that.mSupplementalIcon)
- && Objects.equals(mSupplementalTapAction, that.mSupplementalTapAction)
- && Objects.equals(mSupplementalLoggingInfo, that.mSupplementalLoggingInfo)
- && SmartspaceUtils.isEqual(mSupplementalAlarmText, that.mSupplementalAlarmText)
- && mLayoutWeight == that.mLayoutWeight;
+ return mTemplateType == that.mTemplateType && mLayoutWeight == that.mLayoutWeight
+ && Objects.equals(mPrimaryItem, that.mPrimaryItem)
+ && Objects.equals(mSubtitleItem, that.mSubtitleItem)
+ && Objects.equals(mSubtitleSupplementalItem, that.mSubtitleSupplementalItem)
+ && Objects.equals(mSupplementalLineItem, that.mSupplementalLineItem)
+ && Objects.equals(mSupplementalAlarmItem, that.mSupplementalAlarmItem);
}
@Override
public int hashCode() {
- return Objects.hash(mTemplateType, mTitleText, mTitleIcon, mSubtitleText, mSubtitleIcon,
- mPrimaryTapAction, mPrimaryLoggingInfo, mSupplementalSubtitleText,
- mSupplementalSubtitleIcon, mSupplementalSubtitleTapAction,
- mSupplementalSubtitleLoggingInfo,
- mSupplementalText, mSupplementalIcon, mSupplementalTapAction,
- mSupplementalLoggingInfo, mSupplementalAlarmText, mLayoutWeight);
+ return Objects.hash(mTemplateType, mPrimaryItem, mSubtitleItem, mSubtitleSupplementalItem,
+ mSupplementalLineItem, mSupplementalAlarmItem, mLayoutWeight);
}
@Override
public String toString() {
- return "SmartspaceDefaultUiTemplateData{"
+ return "BaseTemplateData{"
+ "mTemplateType=" + mTemplateType
- + ", mTitleText=" + mTitleText
- + ", mTitleIcon=" + mTitleIcon
- + ", mSubtitleText=" + mSubtitleText
- + ", mSubTitleIcon=" + mSubtitleIcon
- + ", mPrimaryTapAction=" + mPrimaryTapAction
- + ", mPrimaryLoggingInfo=" + mPrimaryLoggingInfo
- + ", mSupplementalSubtitleText=" + mSupplementalSubtitleText
- + ", mSupplementalSubtitleIcon=" + mSupplementalSubtitleIcon
- + ", mSupplementalSubtitleTapAction=" + mSupplementalSubtitleTapAction
- + ", mSupplementalSubtitleLoggingInfo=" + mSupplementalSubtitleLoggingInfo
- + ", mSupplementalText=" + mSupplementalText
- + ", mSupplementalIcon=" + mSupplementalIcon
- + ", mSupplementalTapAction=" + mSupplementalTapAction
- + ", mSupplementalLoggingInfo=" + mSupplementalLoggingInfo
- + ", mSupplementalAlarmText=" + mSupplementalAlarmText
+ + ", mPrimaryItem=" + mPrimaryItem
+ + ", mSubtitleItem=" + mSubtitleItem
+ + ", mSubtitleSupplementalItem=" + mSubtitleSupplementalItem
+ + ", mSupplementalLineItem=" + mSupplementalLineItem
+ + ", mSupplementalAlarmItem=" + mSupplementalAlarmItem
+ ", mLayoutWeight=" + mLayoutWeight
+ '}';
}
@@ -414,21 +245,12 @@
public static class Builder {
@UiTemplateType
private final int mTemplateType;
- private Text mTitleText;
- private Icon mTitleIcon;
- private Text mSubtitleText;
- private Icon mSubtitleIcon;
- private TapAction mPrimaryTapAction;
- private SubItemLoggingInfo mPrimaryLoggingInfo;
- private Text mSupplementalSubtitleText;
- private Icon mSupplementalSubtitleIcon;
- private TapAction mSupplementalSubtitleTapAction;
- private SubItemLoggingInfo mSupplementalSubtitleLoggingInfo;
- private Text mSupplementalText;
- private Icon mSupplementalIcon;
- private TapAction mSupplementalTapAction;
- private SubItemLoggingInfo mSupplementalLoggingInfo;
- private Text mSupplementalAlarmText;
+
+ private SubItemInfo mPrimaryItem;
+ private SubItemInfo mSubtitleItem;
+ private SubItemInfo mSubtitleSupplementalItem;
+ private SubItemInfo mSupplementalLineItem;
+ private SubItemInfo mSupplementalAlarmItem;
private int mLayoutWeight;
/**
@@ -451,106 +273,36 @@
/** Should ONLY be used by the subclasses */
@Nullable
@SuppressLint("GetterOnBuilder")
- Text getTitleText() {
- return mTitleText;
+ SubItemInfo getPrimaryItem() {
+ return mPrimaryItem;
}
/** Should ONLY be used by the subclasses */
@Nullable
@SuppressLint("GetterOnBuilder")
- Icon getTitleIcon() {
- return mTitleIcon;
+ SubItemInfo getSubtitleItem() {
+ return mSubtitleItem;
}
/** Should ONLY be used by the subclasses */
@Nullable
@SuppressLint("GetterOnBuilder")
- Text getSubtitleText() {
- return mSubtitleText;
+ SubItemInfo getSubtitleSupplemtnalItem() {
+ return mSubtitleSupplementalItem;
}
/** Should ONLY be used by the subclasses */
@Nullable
@SuppressLint("GetterOnBuilder")
- Icon getSubtitleIcon() {
- return mSubtitleIcon;
+ SubItemInfo getSupplementalLineItem() {
+ return mSupplementalLineItem;
}
/** Should ONLY be used by the subclasses */
@Nullable
@SuppressLint("GetterOnBuilder")
- TapAction getPrimaryTapAction() {
- return mPrimaryTapAction;
- }
-
- /** Should ONLY be used by the subclasses */
- @Nullable
- @SuppressLint("GetterOnBuilder")
- SubItemLoggingInfo getPrimaryLoggingInfo() {
- return mPrimaryLoggingInfo;
- }
-
- /** Should ONLY be used by the subclasses */
- @Nullable
- @SuppressLint("GetterOnBuilder")
- Text getSupplementalSubtitleText() {
- return mSupplementalSubtitleText;
- }
-
- /** Should ONLY be used by the subclasses */
- @Nullable
- @SuppressLint("GetterOnBuilder")
- Icon getSupplementalSubtitleIcon() {
- return mSupplementalSubtitleIcon;
- }
-
- /** Should ONLY be used by the subclasses */
- @Nullable
- @SuppressLint("GetterOnBuilder")
- TapAction getSupplementalSubtitleTapAction() {
- return mSupplementalSubtitleTapAction;
- }
-
- /** Should ONLY be used by the subclasses */
- @Nullable
- @SuppressLint("GetterOnBuilder")
- SubItemLoggingInfo getSupplementalSubtitleLoggingInfo() {
- return mSupplementalSubtitleLoggingInfo;
- }
-
- /** Should ONLY be used by the subclasses */
- @Nullable
- @SuppressLint("GetterOnBuilder")
- Text getSupplementalText() {
- return mSupplementalText;
- }
-
- /** Should ONLY be used by the subclasses */
- @Nullable
- @SuppressLint("GetterOnBuilder")
- Icon getSupplementalIcon() {
- return mSupplementalIcon;
- }
-
- /** Should ONLY be used by the subclasses */
- @Nullable
- @SuppressLint("GetterOnBuilder")
- TapAction getSupplementalTapAction() {
- return mSupplementalTapAction;
- }
-
- /** Should ONLY be used by the subclasses */
- @Nullable
- @SuppressLint("GetterOnBuilder")
- SubItemLoggingInfo getSupplementalLoggingInfo() {
- return mSupplementalLoggingInfo;
- }
-
- /** Should ONLY be used by the subclasses */
- @Nullable
- @SuppressLint("GetterOnBuilder")
- Text getSupplementalAlarmText() {
- return mSupplementalAlarmText;
+ SubItemInfo getSupplementalAlarmItem() {
+ return mSupplementalAlarmItem;
}
/** Should ONLY be used by the subclasses */
@@ -560,144 +312,47 @@
}
/**
- * Sets the card title.
+ * Sets the card primary item.
*/
@NonNull
- public Builder setTitleText(@NonNull Text titleText) {
- mTitleText = titleText;
+ public Builder setPrimaryItem(@NonNull SubItemInfo primaryItem) {
+ mPrimaryItem = primaryItem;
return this;
}
/**
- * Sets the card title icon.
+ * Sets the card subtitle item.
*/
@NonNull
- public Builder setTitleIcon(@NonNull Icon titleIcon) {
- mTitleIcon = titleIcon;
+ public Builder setSubtitleItem(@NonNull SubItemInfo subtitleItem) {
+ mSubtitleItem = subtitleItem;
return this;
}
/**
- * Sets the card subtitle.
+ * Sets the card subtitle's supplemental item.
*/
@NonNull
- public Builder setSubtitleText(@NonNull Text subtitleText) {
- mSubtitleText = subtitleText;
+ public Builder setSubtitleSupplementalItem(@NonNull SubItemInfo subtitleSupplementalItem) {
+ mSubtitleSupplementalItem = subtitleSupplementalItem;
return this;
}
/**
- * Sets the card subtitle icon.
+ * Sets the card supplemental line item.
*/
@NonNull
- public Builder setSubtitleIcon(@NonNull Icon subtitleIcon) {
- mSubtitleIcon = subtitleIcon;
+ public Builder setSupplementalLineItem(@NonNull SubItemInfo supplementalLineItem) {
+ mSupplementalLineItem = supplementalLineItem;
return this;
}
/**
- * Sets the card primary tap action.
+ * Sets the card supplemental alarm item.
*/
@NonNull
- public Builder setPrimaryTapAction(@NonNull TapAction primaryTapAction) {
- mPrimaryTapAction = primaryTapAction;
- return this;
- }
-
- /**
- * Sets the card primary logging info.
- */
- @NonNull
- public Builder setPrimaryLoggingInfo(@NonNull SubItemLoggingInfo primaryLoggingInfo) {
- mPrimaryLoggingInfo = primaryLoggingInfo;
- return this;
- }
-
- /**
- * Sets the supplemental subtitle text.
- */
- @NonNull
- public Builder setSupplementalSubtitleText(
- @NonNull Text supplementalSubtitleText) {
- mSupplementalSubtitleText = supplementalSubtitleText;
- return this;
- }
-
- /**
- * Sets the supplemental subtitle icon.
- */
- @NonNull
- public Builder setSupplementalSubtitleIcon(
- @NonNull Icon supplementalSubtitleIcon) {
- mSupplementalSubtitleIcon = supplementalSubtitleIcon;
- return this;
- }
-
- /**
- * Sets the supplemental subtitle tap action. {@code mPrimaryTapAction} will be used if not
- * being set.
- */
- @NonNull
- public Builder setSupplementalSubtitleTapAction(
- @NonNull TapAction supplementalSubtitleTapAction) {
- mSupplementalSubtitleTapAction = supplementalSubtitleTapAction;
- return this;
- }
-
- /**
- * Sets the card supplemental title's logging info.
- */
- @NonNull
- public Builder setSupplementalSubtitleLoggingInfo(
- @NonNull SubItemLoggingInfo supplementalSubtitleLoggingInfo) {
- mSupplementalSubtitleLoggingInfo = supplementalSubtitleLoggingInfo;
- return this;
- }
-
- /**
- * Sets the supplemental text.
- */
- @NonNull
- public Builder setSupplementalText(@NonNull Text supplementalText) {
- mSupplementalText = supplementalText;
- return this;
- }
-
- /**
- * Sets the supplemental icon.
- */
- @NonNull
- public Builder setSupplementalIcon(@NonNull Icon supplementalIcon) {
- mSupplementalIcon = supplementalIcon;
- return this;
- }
-
- /**
- * Sets the supplemental line tap action. {@code mPrimaryTapAction} will be used if not
- * being set.
- */
- @NonNull
- public Builder setSupplementalTapAction(@NonNull TapAction supplementalTapAction) {
- mSupplementalTapAction = supplementalTapAction;
- return this;
- }
-
- /**
- * Sets the card supplemental line's logging info.
- */
- @NonNull
- public Builder setSupplementalLoggingInfo(
- @NonNull SubItemLoggingInfo supplementalLoggingInfo) {
- mSupplementalLoggingInfo = supplementalLoggingInfo;
- return this;
- }
-
- /**
- * Sets the supplemental alarm text.
- */
- @NonNull
- public Builder setSupplementalAlarmText(@NonNull Text supplementalAlarmText) {
- mSupplementalAlarmText = supplementalAlarmText;
+ public Builder setSupplementalAlarmItem(@NonNull SubItemInfo supplementalAlarmItem) {
+ mSupplementalAlarmItem = supplementalAlarmItem;
return this;
}
@@ -715,14 +370,197 @@
*/
@NonNull
public BaseTemplateData build() {
- return new BaseTemplateData(mTemplateType, mTitleText, mTitleIcon,
- mSubtitleText, mSubtitleIcon, mPrimaryTapAction,
- mPrimaryLoggingInfo,
- mSupplementalSubtitleText, mSupplementalSubtitleIcon,
- mSupplementalSubtitleTapAction, mSupplementalSubtitleLoggingInfo,
- mSupplementalText, mSupplementalIcon,
- mSupplementalTapAction, mSupplementalLoggingInfo,
- mSupplementalAlarmText, mLayoutWeight);
+ return new BaseTemplateData(
+ mTemplateType,
+ mPrimaryItem,
+ mSubtitleItem,
+ mSubtitleSupplementalItem,
+ mSupplementalLineItem,
+ mSupplementalAlarmItem,
+ mLayoutWeight);
+ }
+ }
+
+ /**
+ * Holds all the rendering and logging info needed for a sub item within the base card.
+ */
+ public static final class SubItemInfo implements Parcelable {
+
+ /** The text information for the subitem, which will be rendered as it's text content. */
+ @Nullable
+ private final Text mText;
+
+ /** The icon for the subitem, which will be rendered as a drawable in front of the text. */
+ @Nullable
+ private final Icon mIcon;
+
+ /** The tap action for the subitem. */
+ @Nullable
+ private final TapAction mTapAction;
+
+ /** The logging info for the subitem. */
+ @Nullable
+ private final SubItemLoggingInfo mLoggingInfo;
+
+ SubItemInfo(@NonNull Parcel in) {
+ mText = in.readTypedObject(Text.CREATOR);
+ mIcon = in.readTypedObject(Icon.CREATOR);
+ mTapAction = in.readTypedObject(TapAction.CREATOR);
+ mLoggingInfo = in.readTypedObject(SubItemLoggingInfo.CREATOR);
+ }
+
+ private SubItemInfo(@Nullable Text text,
+ @Nullable Icon icon,
+ @Nullable TapAction tapAction,
+ @Nullable SubItemLoggingInfo loggingInfo) {
+ mText = text;
+ mIcon = icon;
+ mTapAction = tapAction;
+ mLoggingInfo = loggingInfo;
+ }
+
+ /** Returns the subitem's text. */
+ @Nullable
+ public Text getText() {
+ return mText;
+ }
+
+ /** Returns the subitem's icon. */
+ @Nullable
+ public Icon getIcon() {
+ return mIcon;
+ }
+
+ /** Returns the subitem's tap action. */
+ @Nullable
+ public TapAction getTapAction() {
+ return mTapAction;
+ }
+
+ /** Returns the subitem's logging info. */
+ @Nullable
+ public SubItemLoggingInfo getLoggingInfo() {
+ return mLoggingInfo;
+ }
+
+ /**
+ * @see Parcelable.Creator
+ */
+ @NonNull
+ public static final Creator<SubItemInfo> CREATOR =
+ new Creator<SubItemInfo>() {
+ @Override
+ public SubItemInfo createFromParcel(Parcel in) {
+ return new SubItemInfo(in);
+ }
+
+ @Override
+ public SubItemInfo[] newArray(int size) {
+ return new SubItemInfo[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ out.writeTypedObject(mText, flags);
+ out.writeTypedObject(mIcon, flags);
+ out.writeTypedObject(mTapAction, flags);
+ out.writeTypedObject(mLoggingInfo, flags);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof SubItemInfo)) return false;
+ SubItemInfo that = (SubItemInfo) o;
+ return SmartspaceUtils.isEqual(mText, that.mText) && Objects.equals(mIcon,
+ that.mIcon) && Objects.equals(mTapAction, that.mTapAction)
+ && Objects.equals(mLoggingInfo, that.mLoggingInfo);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mText, mIcon, mTapAction, mLoggingInfo);
+ }
+
+ @Override
+ public String toString() {
+ return "SubItemInfo{"
+ + "mText=" + mText
+ + ", mIcon=" + mIcon
+ + ", mTapAction=" + mTapAction
+ + ", mLoggingInfo=" + mLoggingInfo
+ + '}';
+ }
+
+ /**
+ * A builder for {@link SubItemInfo} object.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final class Builder {
+
+ private Text mText;
+ private Icon mIcon;
+ private TapAction mTapAction;
+ private SubItemLoggingInfo mLoggingInfo;
+
+ /**
+ * Sets the sub item's text.
+ */
+ @NonNull
+ public Builder setText(@NonNull Text text) {
+ mText = text;
+ return this;
+ }
+
+ /**
+ * Sets the sub item's icon.
+ */
+ @NonNull
+ public Builder setIcon(@NonNull Icon icon) {
+ mIcon = icon;
+ return this;
+ }
+
+ /**
+ * Sets the sub item's tap action.
+ */
+ @NonNull
+ public Builder setTapAction(@NonNull TapAction tapAction) {
+ mTapAction = tapAction;
+ return this;
+ }
+
+ /**
+ * Sets the sub item's logging info.
+ */
+ @NonNull
+ public Builder setLoggingInfo(@NonNull SubItemLoggingInfo loggingInfo) {
+ mLoggingInfo = loggingInfo;
+ return this;
+ }
+
+ /**
+ * Builds a new {@link SubItemInfo} instance.
+ *
+ * @throws IllegalStateException if all the data field is empty.
+ */
+ @NonNull
+ public SubItemInfo build() {
+ if (SmartspaceUtils.isEmpty(mText) && mIcon == null && mTapAction == null
+ && mLoggingInfo == null) {
+ throw new IllegalStateException("SubItem data is empty");
+ }
+
+ return new SubItemInfo(mText, mIcon, mTapAction, mLoggingInfo);
+ }
}
}
@@ -735,27 +573,45 @@
/** A unique instance id for the sub item. */
private final int mInstanceId;
- /** The feature type for this sub item. */
+ /**
+ * {@link FeatureType} indicating the feature type of this subitem.
+ *
+ * @see FeatureType
+ */
+ @FeatureType
private final int mFeatureType;
+ /** The data source's package name for this sub item. */
+ @Nullable
+ private final CharSequence mPackageName;
+
SubItemLoggingInfo(@NonNull Parcel in) {
mInstanceId = in.readInt();
mFeatureType = in.readInt();
+ mPackageName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
}
- private SubItemLoggingInfo(int instanceId, int featureType) {
+ private SubItemLoggingInfo(int instanceId, @FeatureType int featureType,
+ @Nullable CharSequence packageName) {
mInstanceId = instanceId;
mFeatureType = featureType;
+ mPackageName = packageName;
}
public int getInstanceId() {
return mInstanceId;
}
+ @FeatureType
public int getFeatureType() {
return mFeatureType;
}
+ @Nullable
+ public CharSequence getPackageName() {
+ return mPackageName;
+ }
+
/**
* @see Parcelable.Creator
*/
@@ -782,6 +638,7 @@
public void writeToParcel(@NonNull Parcel out, int flags) {
out.writeInt(mInstanceId);
out.writeInt(mFeatureType);
+ TextUtils.writeToParcel(mPackageName, out, flags);
}
@Override
@@ -789,12 +646,13 @@
if (this == o) return true;
if (!(o instanceof SubItemLoggingInfo)) return false;
SubItemLoggingInfo that = (SubItemLoggingInfo) o;
- return mInstanceId == that.mInstanceId && mFeatureType == that.mFeatureType;
+ return mInstanceId == that.mInstanceId && mFeatureType == that.mFeatureType
+ && SmartspaceUtils.isEqual(mPackageName, that.mPackageName);
}
@Override
public int hashCode() {
- return Objects.hash(mInstanceId, mFeatureType);
+ return Objects.hash(mInstanceId, mFeatureType, mPackageName);
}
@Override
@@ -802,6 +660,7 @@
return "SubItemLoggingInfo{"
+ "mInstanceId=" + mInstanceId
+ ", mFeatureType=" + mFeatureType
+ + ", mPackageName=" + mPackageName
+ '}';
}
@@ -815,22 +674,32 @@
private final int mInstanceId;
private final int mFeatureType;
+ private CharSequence mPackageName;
/**
* A builder for {@link SubItemLoggingInfo}.
*
* @param instanceId A unique instance id for the sub item
- * @param featureType The feature type for this sub item
+ * @param featureType The feature type id for this sub item
*/
- public Builder(int instanceId, int featureType) {
+ public Builder(int instanceId, @FeatureType int featureType) {
mInstanceId = instanceId;
mFeatureType = featureType;
}
+ /**
+ * Sets the sub item's data source package name.
+ */
+ @NonNull
+ public Builder setPackageName(@NonNull CharSequence packageName) {
+ mPackageName = packageName;
+ return this;
+ }
+
/** Builds a new {@link SubItemLoggingInfo} instance. */
@NonNull
public SubItemLoggingInfo build() {
- return new SubItemLoggingInfo(mInstanceId, mFeatureType);
+ return new SubItemLoggingInfo(mInstanceId, mFeatureType, mPackageName);
}
}
}
diff --git a/core/java/android/app/smartspace/uitemplatedata/CarouselTemplateData.java b/core/java/android/app/smartspace/uitemplatedata/CarouselTemplateData.java
index fbdb7be..c1378f1 100644
--- a/core/java/android/app/smartspace/uitemplatedata/CarouselTemplateData.java
+++ b/core/java/android/app/smartspace/uitemplatedata/CarouselTemplateData.java
@@ -56,31 +56,16 @@
}
private CarouselTemplateData(@SmartspaceTarget.UiTemplateType int templateType,
- @Nullable Text titleText,
- @Nullable Icon titleIcon,
- @Nullable Text subtitleText,
- @Nullable Icon subtitleIcon,
- @Nullable TapAction primaryTapAction,
- @Nullable SubItemLoggingInfo primaryLoggingInfo,
- @Nullable Text supplementalSubtitleText,
- @Nullable Icon supplementalSubtitleIcon,
- @Nullable TapAction supplementalSubtitleTapAction,
- @Nullable SubItemLoggingInfo supplementalSubtitleLoggingInfo,
- @Nullable Text supplementalText,
- @Nullable Icon supplementalIcon,
- @Nullable TapAction supplementalTapAction,
- @Nullable SubItemLoggingInfo supplementalLoggingInfo,
- @Nullable Text supplementalAlarmText,
+ @Nullable SubItemInfo primaryItem,
+ @Nullable SubItemInfo subtitleItem,
+ @Nullable SubItemInfo subtitleSupplementalItem,
+ @Nullable SubItemInfo supplementalLineItem,
+ @Nullable SubItemInfo supplementalAlarmItem,
int layoutWeight,
@NonNull List<CarouselItem> carouselItems,
@Nullable TapAction carouselAction) {
- super(templateType, titleText, titleIcon, subtitleText, subtitleIcon,
- primaryTapAction, primaryLoggingInfo,
- supplementalSubtitleText, supplementalSubtitleIcon,
- supplementalSubtitleTapAction, supplementalSubtitleLoggingInfo,
- supplementalText, supplementalIcon,
- supplementalTapAction, supplementalLoggingInfo,
- supplementalAlarmText, layoutWeight);
+ super(templateType, primaryItem, subtitleItem, subtitleSupplementalItem,
+ supplementalLineItem, supplementalAlarmItem, layoutWeight);
mCarouselItems = carouselItems;
mCarouselAction = carouselAction;
@@ -190,14 +175,9 @@
throw new IllegalStateException("Carousel data is empty");
}
- return new CarouselTemplateData(getTemplateType(), getTitleText(),
- getTitleIcon(), getSubtitleText(), getSubtitleIcon(),
- getPrimaryTapAction(), getPrimaryLoggingInfo(),
- getSupplementalSubtitleText(), getSupplementalSubtitleIcon(),
- getSupplementalSubtitleTapAction(), getSupplementalSubtitleLoggingInfo(),
- getSupplementalText(), getSupplementalIcon(),
- getSupplementalTapAction(), getSupplementalLoggingInfo(),
- getSupplementalAlarmText(), getLayoutWeight(),
+ return new CarouselTemplateData(getTemplateType(), getPrimaryItem(),
+ getSubtitleItem(), getSubtitleSupplemtnalItem(),
+ getSupplementalLineItem(), getSupplementalAlarmItem(), getLayoutWeight(),
mCarouselItems, mCarouselAction);
}
}
diff --git a/core/java/android/app/smartspace/uitemplatedata/CombinedCardsTemplateData.java b/core/java/android/app/smartspace/uitemplatedata/CombinedCardsTemplateData.java
index 1d13066..836f414 100644
--- a/core/java/android/app/smartspace/uitemplatedata/CombinedCardsTemplateData.java
+++ b/core/java/android/app/smartspace/uitemplatedata/CombinedCardsTemplateData.java
@@ -51,30 +51,16 @@
}
private CombinedCardsTemplateData(@SmartspaceTarget.UiTemplateType int templateType,
- @Nullable Text titleText,
- @Nullable Icon titleIcon,
- @Nullable Text subtitleText,
- @Nullable Icon subtitleIcon,
- @Nullable TapAction primaryTapAction,
- @Nullable SubItemLoggingInfo primaryLoggingInfo,
- @Nullable Text supplementalSubtitleText,
- @Nullable Icon supplementalSubtitleIcon,
- @Nullable TapAction supplementalSubtitleTapAction,
- @Nullable SubItemLoggingInfo supplementalSubtitleLoggingInfo,
- @Nullable Text supplementalText,
- @Nullable Icon supplementalIcon,
- @Nullable TapAction supplementalTapAction,
- @Nullable SubItemLoggingInfo supplementalLoggingInfo,
- @Nullable Text supplementalAlarmText,
+ @Nullable SubItemInfo primaryItem,
+ @Nullable SubItemInfo subtitleItem,
+ @Nullable SubItemInfo subtitleSupplementalItem,
+ @Nullable SubItemInfo supplementalLineItem,
+ @Nullable SubItemInfo supplementalAlarmItem,
int layoutWeight,
@NonNull List<BaseTemplateData> combinedCardDataList) {
- super(templateType, titleText, titleIcon, subtitleText, subtitleIcon,
- primaryTapAction, primaryLoggingInfo,
- supplementalSubtitleText, supplementalSubtitleIcon,
- supplementalSubtitleTapAction, supplementalSubtitleLoggingInfo,
- supplementalText, supplementalIcon,
- supplementalTapAction, supplementalLoggingInfo,
- supplementalAlarmText, layoutWeight);
+ super(templateType, primaryItem, subtitleItem, subtitleSupplementalItem,
+ supplementalLineItem, supplementalAlarmItem, layoutWeight);
+
mCombinedCardDataList = combinedCardDataList;
}
@@ -161,14 +147,9 @@
if (mCombinedCardDataList == null) {
throw new IllegalStateException("Please assign a value to all @NonNull args.");
}
- return new CombinedCardsTemplateData(getTemplateType(), getTitleText(),
- getTitleIcon(), getSubtitleText(), getSubtitleIcon(),
- getPrimaryTapAction(), getPrimaryLoggingInfo(),
- getSupplementalSubtitleText(), getSupplementalSubtitleIcon(),
- getSupplementalSubtitleTapAction(), getSupplementalSubtitleLoggingInfo(),
- getSupplementalText(), getSupplementalIcon(),
- getSupplementalTapAction(), getSupplementalLoggingInfo(),
- getSupplementalAlarmText(), getLayoutWeight(),
+ return new CombinedCardsTemplateData(getTemplateType(), getPrimaryItem(),
+ getSubtitleItem(), getSubtitleSupplemtnalItem(),
+ getSupplementalLineItem(), getSupplementalAlarmItem(), getLayoutWeight(),
mCombinedCardDataList);
}
}
diff --git a/core/java/android/app/smartspace/uitemplatedata/HeadToHeadTemplateData.java b/core/java/android/app/smartspace/uitemplatedata/HeadToHeadTemplateData.java
index 19177df..29df018 100644
--- a/core/java/android/app/smartspace/uitemplatedata/HeadToHeadTemplateData.java
+++ b/core/java/android/app/smartspace/uitemplatedata/HeadToHeadTemplateData.java
@@ -66,21 +66,11 @@
}
private HeadToHeadTemplateData(@SmartspaceTarget.UiTemplateType int templateType,
- @Nullable Text titleText,
- @Nullable Icon titleIcon,
- @Nullable Text subtitleText,
- @Nullable Icon subtitleIcon,
- @Nullable TapAction primaryTapAction,
- @Nullable SubItemLoggingInfo primaryLoggingInfo,
- @Nullable Text supplementalSubtitleText,
- @Nullable Icon supplementalSubtitleIcon,
- @Nullable TapAction supplementalSubtitleTapAction,
- @Nullable SubItemLoggingInfo supplementalSubtitleLoggingInfo,
- @Nullable Text supplementalText,
- @Nullable Icon supplementalIcon,
- @Nullable TapAction supplementalTapAction,
- @Nullable SubItemLoggingInfo supplementalLoggingInfo,
- @Nullable Text supplementalAlarmText,
+ @Nullable SubItemInfo primaryItem,
+ @Nullable SubItemInfo subtitleItem,
+ @Nullable SubItemInfo subtitleSupplementalItem,
+ @Nullable SubItemInfo supplementalLineItem,
+ @Nullable SubItemInfo supplementalAlarmItem,
int layoutWeight,
@Nullable Text headToHeadTitle,
@Nullable Icon headToHeadFirstCompetitorIcon,
@@ -88,13 +78,8 @@
@Nullable Text headToHeadFirstCompetitorText,
@Nullable Text headToHeadSecondCompetitorText,
@Nullable TapAction headToHeadAction) {
- super(templateType, titleText, titleIcon, subtitleText, subtitleIcon,
- primaryTapAction, primaryLoggingInfo,
- supplementalSubtitleText, supplementalSubtitleIcon,
- supplementalSubtitleTapAction, supplementalSubtitleLoggingInfo,
- supplementalText, supplementalIcon,
- supplementalTapAction, supplementalLoggingInfo,
- supplementalAlarmText, layoutWeight);
+ super(templateType, primaryItem, subtitleItem, subtitleSupplementalItem,
+ supplementalLineItem, supplementalAlarmItem, layoutWeight);
mHeadToHeadTitle = headToHeadTitle;
mHeadToHeadFirstCompetitorIcon = headToHeadFirstCompetitorIcon;
@@ -296,14 +281,9 @@
*/
@NonNull
public HeadToHeadTemplateData build() {
- return new HeadToHeadTemplateData(getTemplateType(), getTitleText(),
- getTitleIcon(), getSubtitleText(), getSubtitleIcon(),
- getPrimaryTapAction(), getPrimaryLoggingInfo(),
- getSupplementalSubtitleText(), getSupplementalSubtitleIcon(),
- getSupplementalSubtitleTapAction(), getSupplementalSubtitleLoggingInfo(),
- getSupplementalText(), getSupplementalIcon(),
- getSupplementalTapAction(), getSupplementalLoggingInfo(),
- getSupplementalAlarmText(), getLayoutWeight(),
+ return new HeadToHeadTemplateData(getTemplateType(), getPrimaryItem(),
+ getSubtitleItem(), getSubtitleSupplemtnalItem(),
+ getSupplementalLineItem(), getSupplementalAlarmItem(), getLayoutWeight(),
mHeadToHeadTitle,
mHeadToHeadFirstCompetitorIcon,
mHeadToHeadSecondCompetitorIcon, mHeadToHeadFirstCompetitorText,
diff --git a/core/java/android/app/smartspace/uitemplatedata/SubCardTemplateData.java b/core/java/android/app/smartspace/uitemplatedata/SubCardTemplateData.java
index 48af9c1..b87e5b3 100644
--- a/core/java/android/app/smartspace/uitemplatedata/SubCardTemplateData.java
+++ b/core/java/android/app/smartspace/uitemplatedata/SubCardTemplateData.java
@@ -59,32 +59,17 @@
}
private SubCardTemplateData(int templateType,
- @Nullable Text titleText,
- @Nullable Icon titleIcon,
- @Nullable Text subtitleText,
- @Nullable Icon subtitleIcon,
- @Nullable TapAction primaryTapAction,
- @Nullable SubItemLoggingInfo primaryLoggingInfo,
- @Nullable Text supplementalSubtitleText,
- @Nullable Icon supplementalSubtitleIcon,
- @Nullable TapAction supplementalSubtitleTapAction,
- @Nullable SubItemLoggingInfo supplementalSubtitleLoggingInfo,
- @Nullable Text supplementalText,
- @Nullable Icon supplementalIcon,
- @Nullable TapAction supplementalTapAction,
- @Nullable SubItemLoggingInfo supplementalLoggingInfo,
- @Nullable Text supplementalAlarmText,
+ @Nullable SubItemInfo primaryItem,
+ @Nullable SubItemInfo subtitleItem,
+ @Nullable SubItemInfo subtitleSupplementalItem,
+ @Nullable SubItemInfo supplementalLineItem,
+ @Nullable SubItemInfo supplementalAlarmItem,
int layoutWeight,
@NonNull Icon subCardIcon,
@Nullable Text subCardText,
@Nullable TapAction subCardAction) {
- super(templateType, titleText, titleIcon, subtitleText, subtitleIcon,
- primaryTapAction, primaryLoggingInfo,
- supplementalSubtitleText, supplementalSubtitleIcon,
- supplementalSubtitleTapAction, supplementalSubtitleLoggingInfo,
- supplementalText, supplementalIcon,
- supplementalTapAction, supplementalLoggingInfo,
- supplementalAlarmText, layoutWeight);
+ super(templateType, primaryItem, subtitleItem, subtitleSupplementalItem,
+ supplementalLineItem, supplementalAlarmItem, layoutWeight);
mSubCardIcon = subCardIcon;
mSubCardText = subCardText;
@@ -207,14 +192,9 @@
*/
@NonNull
public SubCardTemplateData build() {
- return new SubCardTemplateData(getTemplateType(), getTitleText(),
- getTitleIcon(), getSubtitleText(), getSubtitleIcon(),
- getPrimaryTapAction(), getPrimaryLoggingInfo(),
- getSupplementalSubtitleText(), getSupplementalSubtitleIcon(),
- getSupplementalSubtitleTapAction(), getSupplementalSubtitleLoggingInfo(),
- getSupplementalText(), getSupplementalIcon(),
- getSupplementalTapAction(), getSupplementalLoggingInfo(),
- getSupplementalAlarmText(), getLayoutWeight(),
+ return new SubCardTemplateData(getTemplateType(), getPrimaryItem(),
+ getSubtitleItem(), getSubtitleSupplemtnalItem(),
+ getSupplementalLineItem(), getSupplementalAlarmItem(), getLayoutWeight(),
mSubCardIcon,
mSubCardText,
mSubCardAction);
diff --git a/core/java/android/app/smartspace/uitemplatedata/SubImageTemplateData.java b/core/java/android/app/smartspace/uitemplatedata/SubImageTemplateData.java
index 38692cd..430d79c 100644
--- a/core/java/android/app/smartspace/uitemplatedata/SubImageTemplateData.java
+++ b/core/java/android/app/smartspace/uitemplatedata/SubImageTemplateData.java
@@ -60,32 +60,17 @@
}
private SubImageTemplateData(@SmartspaceTarget.UiTemplateType int templateType,
- @Nullable Text titleText,
- @Nullable Icon titleIcon,
- @Nullable Text subtitleText,
- @Nullable Icon subtitleIcon,
- @Nullable TapAction primaryTapAction,
- @Nullable SubItemLoggingInfo primaryLoggingInfo,
- @Nullable Text supplementalSubtitleText,
- @Nullable Icon supplementalSubtitleIcon,
- @Nullable TapAction supplementalSubtitleTapAction,
- @Nullable SubItemLoggingInfo supplementalSubtitleLoggingInfo,
- @Nullable Text supplementalText,
- @Nullable Icon supplementalIcon,
- @Nullable TapAction supplementalTapAction,
- @Nullable SubItemLoggingInfo supplementalLoggingInfo,
- @Nullable Text supplementalAlarmText,
+ @Nullable SubItemInfo primaryItem,
+ @Nullable SubItemInfo subtitleItem,
+ @Nullable SubItemInfo subtitleSupplementalItem,
+ @Nullable SubItemInfo supplementalLineItem,
+ @Nullable SubItemInfo supplementalAlarmItem,
int layoutWeight,
@NonNull List<Text> subImageTexts,
@NonNull List<Icon> subImages,
@Nullable TapAction subImageAction) {
- super(templateType, titleText, titleIcon, subtitleText, subtitleIcon,
- primaryTapAction, primaryLoggingInfo,
- supplementalSubtitleText, supplementalSubtitleIcon,
- supplementalSubtitleTapAction, supplementalSubtitleLoggingInfo,
- supplementalText, supplementalIcon,
- supplementalTapAction, supplementalLoggingInfo,
- supplementalAlarmText, layoutWeight);
+ super(templateType, primaryItem, subtitleItem, subtitleSupplementalItem,
+ supplementalLineItem, supplementalAlarmItem, layoutWeight);
mSubImageTexts = subImageTexts;
mSubImages = subImages;
@@ -204,14 +189,9 @@
*/
@NonNull
public SubImageTemplateData build() {
- return new SubImageTemplateData(getTemplateType(), getTitleText(),
- getTitleIcon(), getSubtitleText(), getSubtitleIcon(),
- getPrimaryTapAction(), getPrimaryLoggingInfo(),
- getSupplementalSubtitleText(), getSupplementalSubtitleIcon(),
- getSupplementalSubtitleTapAction(), getSupplementalSubtitleLoggingInfo(),
- getSupplementalText(), getSupplementalIcon(),
- getSupplementalTapAction(), getSupplementalLoggingInfo(),
- getSupplementalAlarmText(), getLayoutWeight(),
+ return new SubImageTemplateData(getTemplateType(), getPrimaryItem(),
+ getSubtitleItem(), getSubtitleSupplemtnalItem(),
+ getSupplementalLineItem(), getSupplementalAlarmItem(), getLayoutWeight(),
mSubImageTexts,
mSubImages,
mSubImageAction);
diff --git a/core/java/android/app/smartspace/uitemplatedata/SubListTemplateData.java b/core/java/android/app/smartspace/uitemplatedata/SubListTemplateData.java
index b1535f1..ae43fc4 100644
--- a/core/java/android/app/smartspace/uitemplatedata/SubListTemplateData.java
+++ b/core/java/android/app/smartspace/uitemplatedata/SubListTemplateData.java
@@ -59,32 +59,17 @@
}
private SubListTemplateData(@SmartspaceTarget.UiTemplateType int templateType,
- @Nullable Text titleText,
- @Nullable Icon titleIcon,
- @Nullable Text subtitleText,
- @Nullable Icon subtitleIcon,
- @Nullable TapAction primaryTapAction,
- @Nullable SubItemLoggingInfo primaryLoggingInfo,
- @Nullable Text supplementalSubtitleText,
- @Nullable Icon supplementalSubtitleIcon,
- @Nullable TapAction supplementalSubtitleTapAction,
- @Nullable SubItemLoggingInfo supplementalSubtitleLoggingInfo,
- @Nullable Text supplementalText,
- @Nullable Icon supplementalIcon,
- @Nullable TapAction supplementalTapAction,
- @Nullable SubItemLoggingInfo supplementalLoggingInfo,
- @Nullable Text supplementalAlarmText,
+ @Nullable SubItemInfo primaryItem,
+ @Nullable SubItemInfo subtitleItem,
+ @Nullable SubItemInfo subtitleSupplementalItem,
+ @Nullable SubItemInfo supplementalLineItem,
+ @Nullable SubItemInfo supplementalAlarmItem,
int layoutWeight,
@Nullable Icon subListIcon,
@NonNull List<Text> subListTexts,
@Nullable TapAction subListAction) {
- super(templateType, titleText, titleIcon, subtitleText, subtitleIcon,
- primaryTapAction, primaryLoggingInfo,
- supplementalSubtitleText, supplementalSubtitleIcon,
- supplementalSubtitleTapAction, supplementalSubtitleLoggingInfo,
- supplementalText, supplementalIcon,
- supplementalTapAction, supplementalLoggingInfo,
- supplementalAlarmText, layoutWeight);
+ super(templateType, primaryItem, subtitleItem, subtitleSupplementalItem,
+ supplementalLineItem, supplementalAlarmItem, layoutWeight);
mSubListIcon = subListIcon;
mSubListTexts = subListTexts;
@@ -207,14 +192,9 @@
*/
@NonNull
public SubListTemplateData build() {
- return new SubListTemplateData(getTemplateType(), getTitleText(),
- getTitleIcon(), getSubtitleText(), getSubtitleIcon(),
- getPrimaryTapAction(), getPrimaryLoggingInfo(),
- getSupplementalSubtitleText(), getSupplementalSubtitleIcon(),
- getSupplementalSubtitleTapAction(), getSupplementalSubtitleLoggingInfo(),
- getSupplementalText(), getSupplementalIcon(),
- getSupplementalTapAction(), getSupplementalLoggingInfo(),
- getSupplementalAlarmText(), getLayoutWeight(),
+ return new SubListTemplateData(getTemplateType(), getPrimaryItem(),
+ getSubtitleItem(), getSubtitleSupplemtnalItem(),
+ getSupplementalLineItem(), getSupplementalAlarmItem(), getLayoutWeight(),
mSubListIcon,
mSubListTexts,
mSubListAction);
diff --git a/core/java/android/app/smartspace/uitemplatedata/Text.java b/core/java/android/app/smartspace/uitemplatedata/Text.java
index e1afce7..cb2f432 100644
--- a/core/java/android/app/smartspace/uitemplatedata/Text.java
+++ b/core/java/android/app/smartspace/uitemplatedata/Text.java
@@ -109,6 +109,15 @@
out.writeInt(mMaxLines);
}
+ @Override
+ public String toString() {
+ return "Text{"
+ + "mText=" + mText
+ + ", mTruncateAtType=" + mTruncateAtType
+ + ", mMaxLines=" + mMaxLines
+ + '}';
+ }
+
/**
* A builder for {@link Text} object.
*
diff --git a/core/java/android/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java
index 99ce147..02d140f 100644
--- a/core/java/android/companion/virtual/VirtualDeviceManager.java
+++ b/core/java/android/companion/virtual/VirtualDeviceManager.java
@@ -48,7 +48,6 @@
import android.util.ArrayMap;
import android.view.Surface;
-import java.util.Objects;
import java.util.concurrent.Executor;
/**
@@ -223,7 +222,8 @@
* {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY
* VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY}.
* @param executor The executor on which {@code callback} will be invoked. This is ignored
- * if {@code callback} is {@code null}.
+ * if {@code callback} is {@code null}. If {@code callback} is specified, this executor must
+ * not be null.
* @param callback Callback to call when the state of the {@link VirtualDisplay} changes
* @return The newly created virtual display, or {@code null} if the application could
* not create the virtual display.
@@ -237,7 +237,7 @@
@IntRange(from = 1) int densityDpi,
@Nullable Surface surface,
@VirtualDisplayFlag int flags,
- @NonNull @CallbackExecutor Executor executor,
+ @Nullable @CallbackExecutor Executor executor,
@Nullable VirtualDisplay.Callback callback) {
// TODO(b/205343547): Handle display groups properly instead of creating a new display
// group for every new virtual display created using this API.
@@ -253,7 +253,7 @@
.setFlags(getVirtualDisplayFlags(flags))
.build(),
callback,
- Objects.requireNonNull(executor));
+ executor);
}
/**
diff --git a/core/java/android/companion/virtual/VirtualDeviceParams.java b/core/java/android/companion/virtual/VirtualDeviceParams.java
index 45d0ad5..41b1a1f 100644
--- a/core/java/android/companion/virtual/VirtualDeviceParams.java
+++ b/core/java/android/companion/virtual/VirtualDeviceParams.java
@@ -20,9 +20,7 @@
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 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 @@
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 @@
*
* @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 @@
*
* @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 @@
dest.writeArraySet(mUsersWithMatchingAccounts);
dest.writeArraySet(mAllowedActivities);
dest.writeArraySet(mBlockedActivities);
+ dest.writeInt(mDefaultActivityPolicy);
}
@Override
@@ -164,12 +196,15 @@
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 @@
+ " mUsersWithMatchingAccounts=" + mUsersWithMatchingAccounts
+ " mAllowedActivities=" + mAllowedActivities
+ " mBlockedActivities=" + mBlockedActivities
+ + " mDefaultActivityPolicy=" + mDefaultActivityPolicy
+ ")";
}
@@ -202,8 +238,11 @@
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 @@
}
/**
- * 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 @@
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/Context.java b/core/java/android/content/Context.java
index 8f82a0a..2bda020 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3571,11 +3571,11 @@
* <li>{@link #BIND_INCLUDE_CAPABILITIES}
* </ul>
*
- * @return {@code true} if the system is in the process of bringing up a
- * service that your client has permission to bind to; {@code false}
- * if the system couldn't find the service or if your client doesn't
- * have permission to bind to it. You should call {@link #unbindService}
- * to release the connection even if this method returned {@code false}.
+ * @return {@code true} if the system is in the process of bringing up a
+ * service that your client has permission to bind to; {@code false}
+ * if the system couldn't find the service or if your client doesn't
+ * have permission to bind to it. Regardless of the return value, you
+ * should later call {@link #unbindService} to release the connection.
*
* @throws SecurityException If the caller does not have permission to
* access the service or the service cannot be found. Call
@@ -3589,10 +3589,16 @@
@NonNull ServiceConnection conn, @BindServiceFlags int flags);
/**
- * Same as {@link #bindService(Intent, ServiceConnection, int)} with executor to control
- * ServiceConnection callbacks.
+ * Same as {@link #bindService(Intent, ServiceConnection, int)
+ * bindService(Intent, ServiceConnection, int)} with executor to control ServiceConnection
+ * callbacks.
+ *
* @param executor Callbacks on ServiceConnection will be called on executor. Must use same
* instance for the same instance of ServiceConnection.
+ *
+ * @return The result of the binding as described in
+ * {@link #bindService(Intent, ServiceConnection, int)
+ * bindService(Intent, ServiceConnection, int)}.
*/
public boolean bindService(@RequiresPermission @NonNull Intent service,
@BindServiceFlags int flags, @NonNull @CallbackExecutor Executor executor,
@@ -3618,12 +3624,13 @@
* @param instanceName Unique identifier for the service instance. Each unique
* name here will result in a different service instance being created. Identifiers
* must only contain ASCII letters, digits, underscores, and periods.
- * @return Returns success of binding as per {@link #bindService}.
* @param executor Callbacks on ServiceConnection will be called on executor.
* Must use same instance for the same instance of ServiceConnection.
* @param conn Receives information as the service is started and stopped.
* This must be a valid ServiceConnection object; it must not be null.
*
+ * @return Returns success of binding as per {@link #bindService}.
+ *
* @throws SecurityException If the caller does not have permission to access the service
* @throws IllegalArgumentException If the instanceName is invalid.
*
@@ -3638,8 +3645,7 @@
}
/**
- * Binds to a service in the given {@code user} in the same manner as
- * {@link #bindService(Intent, ServiceConnection, int)}.
+ * Binds to a service in the given {@code user} in the same manner as {@link #bindService}.
*
* <p>Requires that one of the following conditions are met:
* <ul>
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 0aa25ef..478befd 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2054,7 +2054,7 @@
"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 @@
* <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/CameraStreamStats.java b/core/java/android/hardware/CameraStreamStats.java
index 85890c1..823d454 100644
--- a/core/java/android/hardware/CameraStreamStats.java
+++ b/core/java/android/hardware/CameraStreamStats.java
@@ -47,7 +47,7 @@
private int mHistogramType;
private float[] mHistogramBins;
private long[] mHistogramCounts;
- private int mDynamicRangeProfile;
+ private long mDynamicRangeProfile;
private int mStreamUseCase;
private static final String TAG = "CameraStreamStats";
@@ -70,7 +70,7 @@
public CameraStreamStats(int width, int height, int format,
int dataSpace, long usage, long requestCount, long errorCount,
- int startLatencyMs, int maxHalBuffers, int maxAppBuffers, int dynamicRangeProfile,
+ int startLatencyMs, int maxHalBuffers, int maxAppBuffers, long dynamicRangeProfile,
int streamUseCase) {
mWidth = width;
mHeight = height;
@@ -130,7 +130,7 @@
dest.writeInt(mHistogramType);
dest.writeFloatArray(mHistogramBins);
dest.writeLongArray(mHistogramCounts);
- dest.writeInt(mDynamicRangeProfile);
+ dest.writeLong(mDynamicRangeProfile);
dest.writeInt(mStreamUseCase);
}
@@ -148,7 +148,7 @@
mHistogramType = in.readInt();
mHistogramBins = in.createFloatArray();
mHistogramCounts = in.createLongArray();
- mDynamicRangeProfile = in.readInt();
+ mDynamicRangeProfile = in.readLong();
mStreamUseCase = in.readInt();
}
@@ -204,7 +204,7 @@
return mHistogramCounts;
}
- public int getDynamicRangeProfile() {
+ public long getDynamicRangeProfile() {
return mDynamicRangeProfile;
}
diff --git a/core/java/android/hardware/SensorPrivacyManager.java b/core/java/android/hardware/SensorPrivacyManager.java
index a3cc01c..0460e58 100644
--- a/core/java/android/hardware/SensorPrivacyManager.java
+++ b/core/java/android/hardware/SensorPrivacyManager.java
@@ -136,9 +136,9 @@
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 @@
DIALOG,
SHELL,
OTHER,
- SAFETY_HUB
+ SAFETY_CENTER
})
@Retention(RetentionPolicy.SOURCE)
public @interface Source {}
@@ -652,7 +652,7 @@
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/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 524fe79..7bebe1f 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -2448,8 +2448,8 @@
* @see #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_MAX
* @hide
*/
- public static final Key<int[]> REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP =
- new Key<int[]>("android.request.availableDynamicRangeProfilesMap", int[].class);
+ public static final Key<long[]> REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP =
+ new Key<long[]>("android.request.availableDynamicRangeProfilesMap", long[].class);
/**
* <p>Recommended 10-bit dynamic range profile.</p>
@@ -2464,8 +2464,8 @@
*/
@PublicKey
@NonNull
- public static final Key<Integer> REQUEST_RECOMMENDED_TEN_BIT_DYNAMIC_RANGE_PROFILE =
- new Key<Integer>("android.request.recommendedTenBitDynamicRangeProfile", int.class);
+ public static final Key<Long> REQUEST_RECOMMENDED_TEN_BIT_DYNAMIC_RANGE_PROFILE =
+ new Key<Long>("android.request.recommendedTenBitDynamicRangeProfile", long.class);
/**
* <p>The list of image formats that are supported by this
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 8f42b1f..73735ed 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -990,7 +990,7 @@
* <p>Reprocessing with 10-bit output targets on 10-bit capable
* {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT} devices is
* not supported. Trying to initialize a repreocessable capture session with one ore more
- * output configurations set {@link OutputConfiguration#setDynamicRangeProfile(int)} to use
+ * output configurations set {@link OutputConfiguration#setDynamicRangeProfile} to use
* a 10-bit dynamic range profile {@link android.hardware.camera2.params.DynamicRangeProfiles}
* will trigger {@link IllegalArgumentException}.</p>
*
@@ -1179,7 +1179,7 @@
* @see #createCaptureSessionByOutputConfigurations
* @see #createReprocessableCaptureSession
* @see #createConstrainedHighSpeedCaptureSession
- * @see OutputConfiguration#setDynamicRangeProfile(int)
+ * @see OutputConfiguration#setDynamicRangeProfile
* @see android.hardware.camera2.params.DynamicRangeProfiles
*/
public void createCaptureSession(
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 4fb496d..468e604 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -1058,7 +1058,7 @@
}
private DynamicRangeProfiles getDynamicRangeProfiles() {
- int[] profileArray = getBase(
+ long[] profileArray = getBase(
CameraCharacteristics.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP);
if (profileArray == null) {
diff --git a/core/java/android/hardware/camera2/params/DynamicRangeProfiles.java b/core/java/android/hardware/camera2/params/DynamicRangeProfiles.java
index 5c1a4aa..cbd84e7 100644
--- a/core/java/android/hardware/camera2/params/DynamicRangeProfiles.java
+++ b/core/java/android/hardware/camera2/params/DynamicRangeProfiles.java
@@ -16,7 +16,7 @@
package android.hardware.camera2.params;
-import android.annotation.IntDef;
+import android.annotation.LongDef;
import android.annotation.NonNull;
import android.hardware.camera2.CameraMetadata;
@@ -27,7 +27,6 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.Objects;
import java.util.Set;
/**
@@ -44,20 +43,20 @@
*
* <p>Some devices may not be able to support 8-bit and/or 10-bit output with different dynamic
* range profiles within the same capture request. Such device specific constraints can be queried
- * by calling {@link #getProfileCaptureRequestConstraints(int)}. Do note that unsupported
+ * by calling {@link #getProfileCaptureRequestConstraints}. Do note that unsupported
* combinations will result in {@link IllegalArgumentException} when trying to submit a capture
* request. Capture requests that only reference outputs configured using the same dynamic range
* profile value will never fail due to such constraints.</p>
*
- * @see OutputConfiguration#setDynamicRangeProfile(int)
+ * @see OutputConfiguration#setDynamicRangeProfile
*/
public final class DynamicRangeProfiles {
/**
* This the default 8-bit standard profile that will be used in case where camera clients do not
* explicitly configure a supported dynamic range profile by calling
- * {@link OutputConfiguration#setDynamicRangeProfile(int)}.
+ * {@link OutputConfiguration#setDynamicRangeProfile}.
*/
- public static final int STANDARD =
+ public static final long STANDARD =
CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD;
/**
@@ -65,7 +64,7 @@
*
* <p>All 10-bit output capable devices are required to support this profile.</p>
*/
- public static final int HLG10 =
+ public static final long HLG10 =
CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HLG10;
/**
@@ -74,7 +73,7 @@
* <p>This profile utilizes internal static metadata to increase the quality
* of the capture.</p>
*/
- public static final int HDR10 =
+ public static final long HDR10 =
CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10;
/**
@@ -83,7 +82,7 @@
* <p>In contrast to HDR10, this profile uses internal per-frame metadata
* to further enhance the quality of the capture.</p>
*/
- public static final int HDR10_PLUS =
+ public static final long HDR10_PLUS =
CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10_PLUS;
/**
@@ -91,13 +90,13 @@
* accurate capture. This would typically differ from what a specific device
* might want to tune for a consumer optimized Dolby Vision general capture.</p>
*/
- public static final int DOLBY_VISION_10B_HDR_REF =
+ public static final long DOLBY_VISION_10B_HDR_REF =
CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF;
/**
* <p>This is the power optimized mode for 10-bit Dolby Vision HDR Reference Mode.</p>
*/
- public static final int DOLBY_VISION_10B_HDR_REF_PO =
+ public static final long DOLBY_VISION_10B_HDR_REF_PO =
CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF_PO;
/**
@@ -107,52 +106,52 @@
* that each specific device would have a different look for their default
* Dolby Vision capture.</p>
*/
- public static final int DOLBY_VISION_10B_HDR_OEM =
+ public static final long DOLBY_VISION_10B_HDR_OEM =
CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM;
/**
* <p>This is the power optimized mode for 10-bit Dolby Vision HDR device specific capture
* Mode.</p>
*/
- public static final int DOLBY_VISION_10B_HDR_OEM_PO =
+ public static final long DOLBY_VISION_10B_HDR_OEM_PO =
CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM_PO;
/**
* <p>This is the 8-bit version of the Dolby Vision reference capture mode optimized
* for scene accuracy.</p>
*/
- public static final int DOLBY_VISION_8B_HDR_REF =
+ public static final long DOLBY_VISION_8B_HDR_REF =
CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF;
/**
* <p>This is the power optimized mode for 8-bit Dolby Vision HDR Reference Mode.</p>
*/
- public static final int DOLBY_VISION_8B_HDR_REF_PO =
+ public static final long DOLBY_VISION_8B_HDR_REF_PO =
CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF_PO;
/**
* <p>This is the 8-bit version of device specific tuned and optimized Dolby Vision
* capture mode.</p>
*/
- public static final int DOLBY_VISION_8B_HDR_OEM =
+ public static final long DOLBY_VISION_8B_HDR_OEM =
CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM;
/**
* <p>This is the power optimized mode for 8-bit Dolby Vision HDR device specific
* capture Mode.</p>
*/
- public static final int DOLBY_VISION_8B_HDR_OEM_PO =
+ public static final long DOLBY_VISION_8B_HDR_OEM_PO =
CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM_PO;
/*
* @hide
*/
- public static final int PUBLIC_MAX =
+ public static final long PUBLIC_MAX =
CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_MAX;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = {"PROFILE_"}, value =
+ @LongDef(prefix = {"PROFILE_"}, value =
{STANDARD,
HLG10,
HDR10,
@@ -168,7 +167,8 @@
public @interface Profile {
}
- private final HashMap<Integer, Set<Integer>> mProfileMap = new HashMap<>();
+ private final HashMap<Long, Set<Long>> mProfileMap = new HashMap<>();
+ private final HashMap<Long, Boolean> mLookahedLatencyMap = new HashMap<>();
/**
* Create a new immutable DynamicRangeProfiles instance.
@@ -193,23 +193,23 @@
* if {@code elements} is {@code null}
*
*/
- public DynamicRangeProfiles(@NonNull final int[] elements) {
- if ((elements.length % 2) != 0) {
+ public DynamicRangeProfiles(@NonNull final long[] elements) {
+ if ((elements.length % 3) != 0) {
throw new IllegalArgumentException("Dynamic range profile map length " +
elements.length + " is not even!");
}
- for (int i = 0; i < elements.length; i += 2) {
+ for (int i = 0; i < elements.length; i += 3) {
checkProfileValue(elements[i]);
// STANDARD is not expected to be included
if (elements[i] == STANDARD) {
throw new IllegalArgumentException("Dynamic range profile map must not include a"
+ " STANDARD profile entry!");
}
- HashSet<Integer> profiles = new HashSet<>();
+ HashSet<Long> profiles = new HashSet<>();
if (elements[i+1] != 0) {
- for (int profile = STANDARD; profile < PUBLIC_MAX; profile <<= 1) {
+ for (long profile = STANDARD; profile < PUBLIC_MAX; profile <<= 1) {
if ((elements[i+1] & profile) != 0) {
profiles.add(profile);
}
@@ -217,12 +217,13 @@
}
mProfileMap.put(elements[i], profiles);
+ mLookahedLatencyMap.put(elements[i], elements[i+2] != 0L);
}
// Build the STANDARD constraints depending on the advertised 10-bit limitations
- HashSet<Integer> standardConstraints = new HashSet<>();
+ HashSet<Long> standardConstraints = new HashSet<>();
standardConstraints.add(STANDARD);
- for(Integer profile : mProfileMap.keySet()) {
+ for(Long profile : mProfileMap.keySet()) {
if (mProfileMap.get(profile).isEmpty() || mProfileMap.get(profile).contains(STANDARD)) {
standardConstraints.add(profile);
}
@@ -235,24 +236,15 @@
/**
* @hide
*/
- public static void checkProfileValue(int profile) {
- switch (profile) {
- case STANDARD:
- case HLG10:
- case HDR10:
- case HDR10_PLUS:
- case DOLBY_VISION_10B_HDR_REF:
- case DOLBY_VISION_10B_HDR_REF_PO:
- case DOLBY_VISION_10B_HDR_OEM:
- case DOLBY_VISION_10B_HDR_OEM_PO:
- case DOLBY_VISION_8B_HDR_REF:
- case DOLBY_VISION_8B_HDR_REF_PO:
- case DOLBY_VISION_8B_HDR_OEM:
- case DOLBY_VISION_8B_HDR_OEM_PO:
- //No-op
- break;
- default:
- throw new IllegalArgumentException("Unknown profile " + profile);
+ public static void checkProfileValue(long profile) {
+ if (profile == STANDARD || profile == HLG10 || profile == HDR10 || profile == HDR10_PLUS
+ || profile == DOLBY_VISION_10B_HDR_REF || profile == DOLBY_VISION_10B_HDR_REF_PO
+ || profile == DOLBY_VISION_10B_HDR_OEM || profile == DOLBY_VISION_10B_HDR_OEM_PO
+ || profile == DOLBY_VISION_8B_HDR_REF || profile == DOLBY_VISION_8B_HDR_REF_PO
+ || profile == DOLBY_VISION_8B_HDR_OEM
+ || profile == DOLBY_VISION_8B_HDR_OEM_PO) {//No-op
+ } else {
+ throw new IllegalArgumentException("Unknown profile " + profile);
}
}
@@ -261,7 +253,7 @@
*
* @return non-modifiable set of dynamic range profiles
*/
- public @NonNull Set<Integer> getSupportedProfiles() {
+ public @NonNull Set<Long> getSupportedProfiles() {
return Collections.unmodifiableSet(mProfileMap.keySet());
}
@@ -272,7 +264,7 @@
*
* <p>For example if assume that a particular 10-bit output capable device
* returns ({@link #STANDARD}, {@link #HLG10}, {@link #HDR10}) as result from calling
- * {@link #getSupportedProfiles()} and {@link #getProfileCaptureRequestConstraints(int)}
+ * {@link #getSupportedProfiles()} and {@link #getProfileCaptureRequestConstraints}
* returns ({@link #STANDARD}, {@link #HLG10}) when given an argument of {@link #STANDARD}.
* This means that the corresponding camera device will only accept and process capture requests
* that reference outputs configured using {@link #HDR10} dynamic profile or alternatively
@@ -288,14 +280,40 @@
* within the list returned by
* getSupportedProfiles()
*
- * @see OutputConfiguration#setDynamicRangeProfile(int)
+ * @see OutputConfiguration#setDynamicRangeProfile
*/
- public @NonNull Set<Integer> getProfileCaptureRequestConstraints(@Profile int profile) {
- Set<Integer> ret = mProfileMap.get(profile);
+ public @NonNull Set<Long> getProfileCaptureRequestConstraints(@Profile long profile) {
+ Set<Long> ret = mProfileMap.get(profile);
if (ret == null) {
throw new IllegalArgumentException("Unsupported profile!");
}
return Collections.unmodifiableSet(ret);
}
+
+ /**
+ * Check whether a given dynamic range profile is suitable for latency sensitive use cases.
+ *
+ * <p>Due to internal lookahead logic, camera outputs configured with some dynamic range
+ * profiles may experience additional latency greater than 3 buffers. Using camera outputs
+ * with such profiles for latency sensitive use cases such as camera preview is not
+ * recommended. Profiles that have such extra streaming delay are typically utilized for
+ * scenarios such as offscreen video recording.</p>
+ *
+ * @return true if the given profile is not suitable for latency sensitive use cases, false
+ * otherwise
+ * @throws IllegalArgumentException - If the profile argument is not
+ * within the list returned by
+ * getSupportedProfiles()
+ *
+ * @see OutputConfiguration#setDynamicRangeProfile
+ */
+ public boolean isExtraLatencyPresent(@Profile long profile) {
+ Boolean ret = mLookahedLatencyMap.get(profile);
+ if (ret == null) {
+ throw new IllegalArgumentException("Unsupported profile!");
+ }
+
+ return ret;
+ }
}
diff --git a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
index 8c0dcfc..465abfb 100644
--- a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
+++ b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
@@ -246,7 +246,7 @@
* @return true if stream is able to output 10-bit pixels
*
* @see android.hardware.camera2.CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT
- * @see OutputConfiguration#setDynamicRangeProfile(int)
+ * @see OutputConfiguration#setDynamicRangeProfile
*/
public boolean is10BitCapable() {
return mIs10BitCapable;
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index 8093764..2350b7c 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -421,7 +421,7 @@
* {@link android.media.MediaCodec} etc.)
* or {@link ImageFormat#YCBCR_P010}.</p>
*/
- public void setDynamicRangeProfile(@Profile int profile) {
+ public void setDynamicRangeProfile(@Profile long profile) {
mDynamicRangeProfile = profile;
}
@@ -430,7 +430,7 @@
*
* @return the currently set dynamic range profile
*/
- public @Profile int getDynamicRangeProfile() {
+ public @Profile long getDynamicRangeProfile() {
return mDynamicRangeProfile;
}
@@ -1070,7 +1070,7 @@
int streamUseCase = source.readInt();
checkArgumentInRange(rotation, ROTATION_0, ROTATION_270, "Rotation constant");
- int dynamicRangeProfile = source.readInt();
+ long dynamicRangeProfile = source.readLong();
DynamicRangeProfiles.checkProfileValue(dynamicRangeProfile);
int timestampBase = source.readInt();
@@ -1217,7 +1217,7 @@
dest.writeInt(mIsMultiResolution ? 1 : 0);
// writeList doesn't seem to work well with Integer list.
dest.writeIntArray(convertIntegerToIntList(mSensorPixelModesUsed));
- dest.writeInt(mDynamicRangeProfile);
+ dest.writeLong(mDynamicRangeProfile);
dest.writeInt(mStreamUseCase);
dest.writeInt(mTimestampBase);
dest.writeInt(mMirrorMode);
@@ -1335,7 +1335,7 @@
// The sensor pixel modes that this OutputConfiguration will use
private ArrayList<Integer> mSensorPixelModesUsed;
// Dynamic range profile
- private int mDynamicRangeProfile;
+ private long mDynamicRangeProfile;
// Stream use case
private int mStreamUseCase;
// Timestamp base
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index c053c92..c341731 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -957,7 +957,7 @@
public VirtualDisplay createVirtualDisplay(@Nullable IVirtualDevice virtualDevice,
@NonNull VirtualDisplayConfig virtualDisplayConfig,
@Nullable VirtualDisplay.Callback callback,
- @NonNull Executor executor) {
+ @Nullable Executor executor) {
return mGlobal.createVirtualDisplay(mContext, null /* projection */, virtualDevice,
virtualDisplayConfig, callback, executor, null);
}
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 889100d..a62bbf6 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -1054,6 +1054,14 @@
@Nullable private final VirtualDisplay.Callback mCallback;
@Nullable private final Executor mExecutor;
+ /**
+ * Creates a virtual display callback.
+ *
+ * @param callback The callback to call for virtual display events, or {@code null} if the
+ * caller does not wish to receive callback events.
+ * @param executor The executor to call the {@code callback} on. Must not be {@code null} if
+ * the callback is not {@code null}.
+ */
VirtualDisplayCallback(VirtualDisplay.Callback callback, Executor executor) {
mCallback = callback;
mExecutor = mCallback != null ? Objects.requireNonNull(executor) : null;
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 2fd79cf..c38a847 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -1079,16 +1079,24 @@
}
/**
- * Gets the key code produced by the specified location on a US keyboard layout.
- * Key code as defined in {@link android.view.KeyEvent}.
- * This API is only functional for devices with {@link InputDevice#SOURCE_KEYBOARD} available
- * which can alter their key mapping using country specific keyboard layouts.
+ * Gets the {@link android.view.KeyEvent key code} produced by the given location on a reference
+ * QWERTY keyboard layout.
+ * <p>
+ * This API is useful for querying the physical location of keys that change the character
+ * produced based on the current locale and keyboard layout.
+ * <p>
+ * @see InputDevice#getKeyCodeForKeyLocation(int) for examples.
*
- * @param deviceId The input device id.
- * @param locationKeyCode The location of a key on a US keyboard layout.
- * @return The key code produced when pressing the key at the specified location, given the
- * active keyboard layout. Returns {@link KeyEvent#KEYCODE_UNKNOWN} if the requested
- * mapping could not be determined, or if an error occurred.
+ * @param locationKeyCode The location of a key specified as a key code on the QWERTY layout.
+ * This provides a consistent way of referring to the physical location of a key independently
+ * of the current keyboard layout. Also see the
+ * <a href="https://www.w3.org/TR/2017/CR-uievents-code-20170601/#key-alphanumeric-writing-system">
+ * hypothetical keyboard</a> provided by the W3C, which may be helpful for identifying the
+ * physical location of a key.
+ * @return The key code produced by the key at the specified location, given the current
+ * keyboard layout. Returns {@link KeyEvent#KEYCODE_UNKNOWN} if the device does not specify
+ * {@link InputDevice#SOURCE_KEYBOARD} or the requested mapping cannot be determined.
+ *
* @hide
*/
public int getKeyCodeForKeyLocation(int deviceId, int locationKeyCode) {
diff --git a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
index bf4b514..eed92c1 100644
--- a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
+++ b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
@@ -37,6 +37,8 @@
import android.os.RemoteException;
import android.util.Log;
+import java.io.IOException;
+
/**
* The SoundTriggerModule provides APIs to control sound models and sound detection
* on a given sound trigger hardware module.
@@ -137,13 +139,39 @@
if (model instanceof SoundTrigger.GenericSoundModel) {
SoundModel aidlModel = ConversionUtil.api2aidlGenericSoundModel(
(SoundTrigger.GenericSoundModel) model);
- soundModelHandle[0] = mService.loadModel(aidlModel);
+ try {
+ soundModelHandle[0] = mService.loadModel(aidlModel);
+ } finally {
+ // TODO(b/219825762): We should be able to use the entire object in a
+ // try-with-resources
+ // clause, instead of having to explicitly close internal fields.
+ if (aidlModel.data != null) {
+ try {
+ aidlModel.data.close();
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to close file", e);
+ }
+ }
+ }
return SoundTrigger.STATUS_OK;
}
if (model instanceof SoundTrigger.KeyphraseSoundModel) {
PhraseSoundModel aidlModel = ConversionUtil.api2aidlPhraseSoundModel(
(SoundTrigger.KeyphraseSoundModel) model);
- soundModelHandle[0] = mService.loadPhraseModel(aidlModel);
+ try {
+ soundModelHandle[0] = mService.loadPhraseModel(aidlModel);
+ } finally {
+ // TODO(b/219825762): We should be able to use the entire object in a
+ // try-with-resources
+ // clause, instead of having to explicitly close internal fields.
+ if (aidlModel.common.data != null) {
+ try {
+ aidlModel.common.data.close();
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to close file", e);
+ }
+ }
+ }
return SoundTrigger.STATUS_OK;
}
return SoundTrigger.STATUS_BAD_VALUE;
diff --git a/core/java/android/os/BadTypeParcelableException.java b/core/java/android/os/BadTypeParcelableException.java
new file mode 100644
index 0000000..2ca3bd2
--- /dev/null
+++ b/core/java/android/os/BadTypeParcelableException.java
@@ -0,0 +1,30 @@
+/*
+ * 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.os;
+
+/** Used by Parcel to signal that the type on the payload was not expected by the caller. */
+class BadTypeParcelableException extends BadParcelableException {
+ BadTypeParcelableException(String msg) {
+ super(msg);
+ }
+ BadTypeParcelableException(Exception cause) {
+ super(cause);
+ }
+ BadTypeParcelableException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+}
diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java
index 244335d..45812e5 100644
--- a/core/java/android/os/BaseBundle.java
+++ b/core/java/android/os/BaseBundle.java
@@ -16,6 +16,8 @@
package android.os;
+import static java.util.Objects.requireNonNull;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
@@ -31,7 +33,7 @@
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Set;
-import java.util.function.Function;
+import java.util.function.BiFunction;
/**
* A mapping from String keys to values of various types. In most cases, you
@@ -254,8 +256,8 @@
}
try {
return getValueAt(0, String.class);
- } catch (ClassCastException | BadParcelableException e) {
- typeWarning("getPairValue()", /* value */ null, "String", e);
+ } catch (ClassCastException | BadTypeParcelableException e) {
+ typeWarning("getPairValue()", "String", e);
return null;
}
}
@@ -320,28 +322,46 @@
* This call should always be made after {@link #unparcel()} or inside a lock after making sure
* {@code mMap} is not null.
*
+ * @deprecated Use {@link #getValue(String, Class, Class[])}. This method should only be used in
+ * other deprecated APIs.
+ *
* @hide
*/
+ @Deprecated
+ @Nullable
final Object getValue(String key) {
return getValue(key, /* clazz */ null);
}
+ /** Same as {@link #getValue(String, Class, Class[])} with no item types. */
+ @Nullable
+ final <T> T getValue(String key, @Nullable Class<T> clazz) {
+ // Avoids allocating Class[0] array
+ return getValue(key, clazz, (Class<?>[]) null);
+ }
+
/**
- * Returns the value for key {@code key} for expected return type {@param clazz} (or {@code
+ * Returns the value for key {@code key} for expected return type {@code clazz} (or pass {@code
* null} for no type check).
*
+ * For {@code itemTypes}, see {@link Parcel#readValue(int, ClassLoader, Class, Class[])}.
+ *
* This call should always be made after {@link #unparcel()} or inside a lock after making sure
* {@code mMap} is not null.
*
* @hide
*/
- final <T> T getValue(String key, @Nullable Class<T> clazz) {
+ @Nullable
+ final <T> T getValue(String key, @Nullable Class<T> clazz, @Nullable Class<?>... itemTypes) {
int i = mMap.indexOfKey(key);
- return (i >= 0) ? getValueAt(i, clazz) : null;
+ return (i >= 0) ? getValueAt(i, clazz, itemTypes) : null;
}
/**
- * Returns the value for a certain position in the array map.
+ * Returns the value for a certain position in the array map for expected return type {@code
+ * clazz} (or pass {@code null} for no type check).
+ *
+ * For {@code itemTypes}, see {@link Parcel#readValue(int, ClassLoader, Class, Class[])}.
*
* This call should always be made after {@link #unparcel()} or inside a lock after making sure
* {@code mMap} is not null.
@@ -349,11 +369,12 @@
* @hide
*/
@SuppressWarnings("unchecked")
- final <T> T getValueAt(int i, @Nullable Class<T> clazz) {
+ @Nullable
+ final <T> T getValueAt(int i, @Nullable Class<T> clazz, @Nullable Class<?>... itemTypes) {
Object object = mMap.valueAt(i);
- if (object instanceof Function<?, ?>) {
+ if (object instanceof BiFunction<?, ?, ?>) {
try {
- object = ((Function<Class<?>, ?>) object).apply(clazz);
+ object = ((BiFunction<Class<?>, Class<?>[], ?>) object).apply(clazz, itemTypes);
} catch (BadParcelableException e) {
if (sShouldDefuse) {
Log.w(TAG, "Failed to parse item " + mMap.keyAt(i) + ", returning null.", e);
@@ -615,7 +636,11 @@
*
* @param key a String key
* @return an Object, or null
+ *
+ * @deprecated Use the type-safe specific APIs depending on the type of the item to be
+ * retrieved, eg. {@link #getString(String)}.
*/
+ @Deprecated
@Nullable
public Object get(String key) {
unparcel();
@@ -623,6 +648,32 @@
}
/**
+ * Returns the object of type {@code clazz} for the given {@code key}, or {@code null} if:
+ * <ul>
+ * <li>No mapping of the desired type exists for the given key.
+ * <li>A {@code null} value is explicitly associated with the key.
+ * <li>The object is not of type {@code clazz}.
+ * </ul>
+ *
+ * <p>Use the more specific APIs where possible, especially in the case of containers such as
+ * lists, since those APIs allow you to specify the type of the items.
+ *
+ * @param key String key
+ * @param clazz The type of the object expected
+ * @return an Object, or null
+ */
+ @Nullable
+ <T> T get(@Nullable String key, @NonNull Class<T> clazz) {
+ unparcel();
+ try {
+ return getValue(key, requireNonNull(clazz));
+ } catch (ClassCastException | BadTypeParcelableException e) {
+ typeWarning(key, clazz.getCanonicalName(), e);
+ return null;
+ }
+ }
+
+ /**
* Removes any entry with the given key from the mapping of this Bundle.
*
* @param key a String key
@@ -1006,7 +1057,7 @@
sb.append(" but value was a ");
sb.append(value.getClass().getName());
} else {
- sb.append(" but value was of a different type ");
+ sb.append(" but value was of a different type");
}
sb.append(". The default value ");
sb.append(defaultValue);
@@ -1019,6 +1070,10 @@
typeWarning(key, value, className, "<null>", e);
}
+ void typeWarning(String key, String className, RuntimeException e) {
+ typeWarning(key, /* value */ null, className, "<null>", e);
+ }
+
/**
* Returns the value associated with the given key, or defaultValue if
* no mapping of the desired type exists for the given key.
@@ -1358,7 +1413,11 @@
*
* @param key a String, or null
* @return a Serializable value, or null
+ *
+ * @deprecated Use {@link #getSerializable(String, Class)}. This method should only be used in
+ * other deprecated APIs.
*/
+ @Deprecated
@Nullable
Serializable getSerializable(@Nullable String key) {
unparcel();
@@ -1375,6 +1434,36 @@
}
/**
+ * Returns the value associated with the given key, or {@code null} if:
+ * <ul>
+ * <li>No mapping of the desired type exists for the given key.
+ * <li>A {@code null} value is explicitly associated with the key.
+ * <li>The object is not of type {@code clazz}.
+ * </ul>
+ *
+ * @param key a String, or null
+ * @param clazz The expected class of the returned type
+ * @return a Serializable value, or null
+ */
+ @Nullable
+ <T extends Serializable> T getSerializable(@Nullable String key, @NonNull Class<T> clazz) {
+ return get(key, clazz);
+ }
+
+
+ @SuppressWarnings("unchecked")
+ @Nullable
+ <T> ArrayList<T> getArrayList(@Nullable String key, @NonNull Class<T> clazz) {
+ unparcel();
+ try {
+ return getValue(key, ArrayList.class, requireNonNull(clazz));
+ } catch (ClassCastException | BadTypeParcelableException e) {
+ typeWarning(key, "ArrayList<" + clazz.getCanonicalName() + ">", e);
+ return null;
+ }
+ }
+
+ /**
* Returns the value associated with the given key, or null if
* no mapping of the desired type exists for the given key or a null
* value is explicitly associated with the key.
@@ -1384,17 +1473,7 @@
*/
@Nullable
ArrayList<Integer> getIntegerArrayList(@Nullable String key) {
- unparcel();
- Object o = getValue(key);
- if (o == null) {
- return null;
- }
- try {
- return (ArrayList<Integer>) o;
- } catch (ClassCastException e) {
- typeWarning(key, o, "ArrayList<Integer>", e);
- return null;
- }
+ return getArrayList(key, Integer.class);
}
/**
@@ -1407,17 +1486,7 @@
*/
@Nullable
ArrayList<String> getStringArrayList(@Nullable String key) {
- unparcel();
- Object o = getValue(key);
- if (o == null) {
- return null;
- }
- try {
- return (ArrayList<String>) o;
- } catch (ClassCastException e) {
- typeWarning(key, o, "ArrayList<String>", e);
- return null;
- }
+ return getArrayList(key, String.class);
}
/**
@@ -1430,17 +1499,7 @@
*/
@Nullable
ArrayList<CharSequence> getCharSequenceArrayList(@Nullable String key) {
- unparcel();
- Object o = getValue(key);
- if (o == null) {
- return null;
- }
- try {
- return (ArrayList<CharSequence>) o;
- } catch (ClassCastException e) {
- typeWarning(key, o, "ArrayList<CharSequence>", e);
- return null;
- }
+ return getArrayList(key, CharSequence.class);
}
/**
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index 2b13f20..edbbb59 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -20,6 +20,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
import android.compat.annotation.UnsupportedAppUsage;
import android.util.ArrayMap;
import android.util.Size;
@@ -876,7 +877,7 @@
@Nullable
public Bundle getBundle(@Nullable String key) {
unparcel();
- Object o = getValue(key);
+ Object o = mMap.get(key);
if (o == null) {
return null;
}
@@ -899,7 +900,11 @@
*
* @param key a String, or {@code null}
* @return a Parcelable value, or {@code null}
+ *
+ * @deprecated Use the type-safer {@link #getParcelable(String, Class)} starting from Android
+ * {@link Build.VERSION_CODES#TIRAMISU}.
*/
+ @Deprecated
@Nullable
public <T extends Parcelable> T getParcelable(@Nullable String key) {
unparcel();
@@ -916,30 +921,28 @@
}
/**
- * Returns the value associated with the given key, or {@code null} if
- * no mapping of the desired type exists for the given key or a {@code null}
- * value is explicitly associated with the key.
+ * Returns the value associated with the given key or {@code null} if:
+ * <ul>
+ * <li>No mapping of the desired type exists for the given key.
+ * <li>A {@code null} value is explicitly associated with the key.
+ * <li>The object is not of type {@code clazz}.
+ * </ul>
*
* <p><b>Note: </b> if the expected value is not a class provided by the Android platform,
* you must call {@link #setClassLoader(ClassLoader)} with the proper {@link ClassLoader} first.
* Otherwise, this method might throw an exception or return {@code null}.
*
* @param key a String, or {@code null}
- * @param clazz The type of the object expected or {@code null} for performing no checks.
+ * @param clazz The type of the object expected
* @return a Parcelable value, or {@code null}
- *
- * @hide
*/
@SuppressWarnings("unchecked")
@Nullable
public <T> T getParcelable(@Nullable String key, @NonNull Class<T> clazz) {
- unparcel();
- try {
- return getValue(key, requireNonNull(clazz));
- } catch (ClassCastException | BadParcelableException e) {
- typeWarning(key, /* value */ null, "Parcelable", e);
- return null;
- }
+ // The reason for not using <T extends Parcelable> is because the caller could provide a
+ // super class to restrict the children that doesn't implement Parcelable itself while the
+ // children do, more details at b/210800751 (same reasoning applies here).
+ return get(key, clazz);
}
/**
@@ -953,7 +956,11 @@
*
* @param key a String, or {@code null}
* @return a Parcelable[] value, or {@code null}
+ *
+ * @deprecated Use the type-safer {@link #getParcelableArray(String, Class)} starting from
+ * Android {@link Build.VERSION_CODES#TIRAMISU}.
*/
+ @Deprecated
@Nullable
public Parcelable[] getParcelableArray(@Nullable String key) {
unparcel();
@@ -970,6 +977,39 @@
}
/**
+ * Returns the value associated with the given key, or {@code null} if:
+ * <ul>
+ * <li>No mapping of the desired type exists for the given key.
+ * <li>A {@code null} value is explicitly associated with the key.
+ * <li>The object is not of type {@code clazz}.
+ * </ul>
+ *
+ * <p><b>Note: </b> if the expected value is not a class provided by the Android platform,
+ * you must call {@link #setClassLoader(ClassLoader)} with the proper {@link ClassLoader} first.
+ * Otherwise, this method might throw an exception or return {@code null}.
+ *
+ * @param key a String, or {@code null}
+ * @param clazz The type of the items inside the array
+ * @return a Parcelable[] value, or {@code null}
+ */
+ @SuppressLint({"ArrayReturn", "NullableCollection"})
+ @SuppressWarnings("unchecked")
+ @Nullable
+ public <T> T[] getParcelableArray(@Nullable String key, @NonNull Class<T> clazz) {
+ // The reason for not using <T extends Parcelable> is because the caller could provide a
+ // super class to restrict the children that doesn't implement Parcelable itself while the
+ // children do, more details at b/210800751 (same reasoning applies here).
+ unparcel();
+ try {
+ // In Java 12, we can pass clazz.arrayType() instead of Parcelable[] and later casting.
+ return (T[]) getValue(key, Parcelable[].class, requireNonNull(clazz));
+ } catch (ClassCastException | BadTypeParcelableException e) {
+ typeWarning(key, clazz.getCanonicalName() + "[]", e);
+ return null;
+ }
+ }
+
+ /**
* Returns the value associated with the given key, or {@code null} if
* no mapping of the desired type exists for the given key or a {@code null}
* value is explicitly associated with the key.
@@ -980,7 +1020,11 @@
*
* @param key a String, or {@code null}
* @return an ArrayList<T> value, or {@code null}
+ *
+ * @deprecated Use the type-safer {@link #getParcelable(String, Class)} starting from Android
+ * {@link Build.VERSION_CODES#TIRAMISU}.
*/
+ @Deprecated
@Nullable
public <T extends Parcelable> ArrayList<T> getParcelableArrayList(@Nullable String key) {
unparcel();
@@ -997,14 +1041,43 @@
}
/**
+ * Returns the value associated with the given key, or {@code null} if:
+ * <ul>
+ * <li>No mapping of the desired type exists for the given key.
+ * <li>A {@code null} value is explicitly associated with the key.
+ * <li>The object is not of type {@code clazz}.
+ * </ul>
+ *
+ * <p><b>Note: </b> if the expected value is not a class provided by the Android platform,
+ * you must call {@link #setClassLoader(ClassLoader)} with the proper {@link ClassLoader} first.
+ * Otherwise, this method might throw an exception or return {@code null}.
+ *
+ * @param key a String, or {@code null}
+ * @param clazz The type of the items inside the array list
+ * @return an ArrayList<T> value, or {@code null}
+ */
+ @SuppressLint("NullableCollection")
+ @SuppressWarnings("unchecked")
+ @Nullable
+ public <T> ArrayList<T> getParcelableArrayList(@Nullable String key, @NonNull Class<T> clazz) {
+ // The reason for not using <T extends Parcelable> is because the caller could provide a
+ // super class to restrict the children that doesn't implement Parcelable itself while the
+ // children do, more details at b/210800751 (same reasoning applies here).
+ return getArrayList(key, clazz);
+ }
+
+ /**
* Returns the value associated with the given key, or null if
* no mapping of the desired type exists for the given key or a null
* value is explicitly associated with the key.
*
* @param key a String, or null
- *
* @return a SparseArray of T values, or null
+ *
+ * @deprecated Use the type-safer {@link #getSparseParcelableArray(String, Class)} starting from
+ * Android {@link Build.VERSION_CODES#TIRAMISU}.
*/
+ @Deprecated
@Nullable
public <T extends Parcelable> SparseArray<T> getSparseParcelableArray(@Nullable String key) {
unparcel();
@@ -1021,13 +1094,44 @@
}
/**
+ * Returns the value associated with the given key, or {@code null} if:
+ * <ul>
+ * <li>No mapping of the desired type exists for the given key.
+ * <li>A {@code null} value is explicitly associated with the key.
+ * <li>The object is not of type {@code clazz}.
+ * </ul>
+ *
+ * @param key a String, or null
+ * @return a SparseArray of T values, or null
+ */
+ @SuppressWarnings("unchecked")
+ @Nullable
+ public <T> SparseArray<T> getSparseParcelableArray(@Nullable String key,
+ @NonNull Class<T> clazz) {
+ // The reason for not using <T extends Parcelable> is because the caller could provide a
+ // super class to restrict the children that doesn't implement Parcelable itself while the
+ // children do, more details at b/210800751 (same reasoning applies here).
+ unparcel();
+ try {
+ return (SparseArray<T>) getValue(key, SparseArray.class, requireNonNull(clazz));
+ } catch (ClassCastException | BadTypeParcelableException e) {
+ typeWarning(key, "SparseArray<" + clazz.getCanonicalName() + ">", e);
+ return null;
+ }
+ }
+
+ /**
* Returns the value associated with the given key, or null if
* no mapping of the desired type exists for the given key or a null
* value is explicitly associated with the key.
*
* @param key a String, or null
* @return a Serializable value, or null
+ *
+ * @deprecated Use the type-safer {@link #getSerializable(String, Class)} starting from Android
+ * {@link Build.VERSION_CODES#TIRAMISU}.
*/
+ @Deprecated
@Override
@Nullable
public Serializable getSerializable(@Nullable String key) {
@@ -1035,6 +1139,24 @@
}
/**
+ * Returns the value associated with the given key, or {@code null} if:
+ * <ul>
+ * <li>No mapping of the desired type exists for the given key.
+ * <li>A {@code null} value is explicitly associated with the key.
+ * <li>The object is not of type {@code clazz}.
+ * </ul>
+ *
+ * @param key a String, or null
+ * @param clazz The expected class of the returned type
+ * @return a Serializable value, or null
+ */
+ @Nullable
+ public <T extends Serializable> T getSerializable(@Nullable String key,
+ @NonNull Class<T> clazz) {
+ return super.getSerializable(key, requireNonNull(clazz));
+ }
+
+ /**
* Returns the value associated with the given key, or null if
* no mapping of the desired type exists for the given key or a null
* value is explicitly associated with the key.
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index ae92353..09cfb6e 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -16,6 +16,8 @@
package android.os;
+import static com.android.internal.util.Preconditions.checkArgument;
+
import static java.util.Objects.requireNonNull;
import android.annotation.IntDef;
@@ -65,6 +67,7 @@
import java.util.Map;
import java.util.Objects;
import java.util.Set;
+import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.function.Supplier;
@@ -287,26 +290,26 @@
private static final int VAL_NULL = -1;
private static final int VAL_STRING = 0;
private static final int VAL_INTEGER = 1;
- private static final int VAL_MAP = 2;
+ private static final int VAL_MAP = 2; // length-prefixed
private static final int VAL_BUNDLE = 3;
- private static final int VAL_PARCELABLE = 4;
+ private static final int VAL_PARCELABLE = 4; // length-prefixed
private static final int VAL_SHORT = 5;
private static final int VAL_LONG = 6;
private static final int VAL_FLOAT = 7;
private static final int VAL_DOUBLE = 8;
private static final int VAL_BOOLEAN = 9;
private static final int VAL_CHARSEQUENCE = 10;
- private static final int VAL_LIST = 11;
- private static final int VAL_SPARSEARRAY = 12;
+ private static final int VAL_LIST = 11; // length-prefixed
+ private static final int VAL_SPARSEARRAY = 12; // length-prefixed
private static final int VAL_BYTEARRAY = 13;
private static final int VAL_STRINGARRAY = 14;
private static final int VAL_IBINDER = 15;
- private static final int VAL_PARCELABLEARRAY = 16;
- private static final int VAL_OBJECTARRAY = 17;
+ private static final int VAL_PARCELABLEARRAY = 16; // length-prefixed
+ private static final int VAL_OBJECTARRAY = 17; // length-prefixed
private static final int VAL_INTARRAY = 18;
private static final int VAL_LONGARRAY = 19;
private static final int VAL_BYTE = 20;
- private static final int VAL_SERIALIZABLE = 21;
+ private static final int VAL_SERIALIZABLE = 21; // length-prefixed
private static final int VAL_SPARSEBOOLEANARRAY = 22;
private static final int VAL_BOOLEANARRAY = 23;
private static final int VAL_CHARSEQUENCEARRAY = 24;
@@ -3179,8 +3182,7 @@
*/
@Deprecated
public final void readMap(@NonNull Map outVal, @Nullable ClassLoader loader) {
- int n = readInt();
- readMapInternal(outVal, n, loader, /* clazzKey */ null, /* clazzValue */ null);
+ readMapInternal(outVal, loader, /* clazzKey */ null, /* clazzValue */ null);
}
/**
@@ -3195,8 +3197,7 @@
@NonNull Class<V> clazzValue) {
Objects.requireNonNull(clazzKey);
Objects.requireNonNull(clazzValue);
- int n = readInt();
- readMapInternal(outVal, n, loader, clazzKey, clazzValue);
+ readMapInternal(outVal, loader, clazzKey, clazzValue);
}
/**
@@ -3245,13 +3246,7 @@
@Deprecated
@Nullable
public HashMap readHashMap(@Nullable ClassLoader loader) {
- int n = readInt();
- if (n < 0) {
- return null;
- }
- HashMap m = new HashMap(n);
- readMapInternal(m, n, loader, /* clazzKey */ null, /* clazzValue */ null);
- return m;
+ return readHashMapInternal(loader, /* clazzKey */ null, /* clazzValue */ null);
}
/**
@@ -3267,13 +3262,7 @@
@NonNull Class<? extends K> clazzKey, @NonNull Class<? extends V> clazzValue) {
Objects.requireNonNull(clazzKey);
Objects.requireNonNull(clazzValue);
- int n = readInt();
- if (n < 0) {
- return null;
- }
- HashMap<K, V> map = new HashMap<>(n);
- readMapInternal(map, n, loader, clazzKey, clazzValue);
- return map;
+ return readHashMapInternal(loader, clazzKey, clazzValue);
}
/**
@@ -4296,16 +4285,17 @@
/**
- * @param clazz The type of the object expected or {@code null} for performing no checks.
+ * @see #readValue(int, ClassLoader, Class, Class[])
*/
@Nullable
- private <T> T readValue(@Nullable ClassLoader loader, @Nullable Class<T> clazz) {
+ private <T> T readValue(@Nullable ClassLoader loader, @Nullable Class<T> clazz,
+ @Nullable Class<?>... itemTypes) {
int type = readInt();
final T object;
if (isLengthPrefixed(type)) {
int length = readInt();
int start = dataPosition();
- object = readValue(type, loader, clazz);
+ object = readValue(type, loader, clazz, itemTypes);
int actual = dataPosition() - start;
if (actual != length) {
Slog.wtfStack(TAG,
@@ -4313,25 +4303,26 @@
+ " consumed " + actual + " bytes, but " + length + " expected.");
}
} else {
- object = readValue(type, loader, clazz);
+ object = readValue(type, loader, clazz, itemTypes);
}
return object;
}
/**
- * This will return a {@link Function} for length-prefixed types that deserializes the object
- * when {@link Function#apply} is called with the expected class of the return object (or {@code
- * null} for no type check), for other types it will return the object itself.
+ * This will return a {@link BiFunction} for length-prefixed types that deserializes the object
+ * when {@link BiFunction#apply} is called (the arguments correspond to the ones of {@link
+ * #readValue(int, ClassLoader, Class, Class[])} after the class loader), for other types it
+ * will return the object itself.
*
- * <p>After calling {@link Function#apply(Object)} the parcel cursor will not change. Note that
- * you shouldn't recycle the parcel, not at least until all objects have been retrieved. No
+ * <p>After calling {@link BiFunction#apply} the parcel cursor will not change. Note that you
+ * shouldn't recycle the parcel, not at least until all objects have been retrieved. No
* synchronization attempts are made.
*
* </p>The function returned implements {@link #equals(Object)} and {@link #hashCode()}. Two
* function objects are equal if either of the following is true:
* <ul>
- * <li>{@link Function#apply} has been called on both and both objects returned are equal.
- * <li>{@link Function#apply} hasn't been called on either one and everything below is true:
+ * <li>{@link BiFunction#apply} has been called on both and both objects returned are equal.
+ * <li>{@link BiFunction#apply} hasn't been called on either one and everything below is true:
* <ul>
* <li>The {@code loader} parameters used to retrieve each are equal.
* <li>They both have the same type.
@@ -4358,7 +4349,7 @@
}
- private static final class LazyValue implements Function<Class<?>, Object> {
+ private static final class LazyValue implements BiFunction<Class<?>, Class<?>[], Object> {
/**
* | 4B | 4B |
* mSource = Parcel{... | type | length | object | ...}
@@ -4390,7 +4381,7 @@
}
@Override
- public Object apply(@Nullable Class<?> clazz) {
+ public Object apply(@Nullable Class<?> clazz, @Nullable Class<?>[] itemTypes) {
Parcel source = mSource;
if (source != null) {
synchronized (source) {
@@ -4399,7 +4390,7 @@
int restore = source.dataPosition();
try {
source.setDataPosition(mPosition);
- mObject = source.readValue(mLoader, clazz);
+ mObject = source.readValue(mLoader, clazz, itemTypes);
} finally {
source.setDataPosition(restore);
}
@@ -4479,14 +4470,25 @@
}
}
+ /** Same as {@link #readValue(ClassLoader, Class, Class[])} without any item types. */
+ private <T> T readValue(int type, @Nullable ClassLoader loader, @Nullable Class<T> clazz) {
+ // Avoids allocating Class[0] array
+ return readValue(type, loader, clazz, (Class<?>[]) null);
+ }
+
/**
* Reads a value from the parcel of type {@code type}. Does NOT read the int representing the
* type first.
+ *
* @param clazz The type of the object expected or {@code null} for performing no checks.
+ * @param itemTypes If the value is a container, these represent the item types (eg. for a list
+ * it's the item type, for a map, it's the key type, followed by the value
+ * type).
*/
@SuppressWarnings("unchecked")
@Nullable
- private <T> T readValue(int type, @Nullable ClassLoader loader, @Nullable Class<T> clazz) {
+ private <T> T readValue(int type, @Nullable ClassLoader loader, @Nullable Class<T> clazz,
+ @Nullable Class<?>... itemTypes) {
final Object object;
switch (type) {
case VAL_NULL:
@@ -4502,7 +4504,11 @@
break;
case VAL_MAP:
- object = readHashMap(loader);
+ checkTypeToUnparcel(clazz, HashMap.class);
+ Class<?> keyType = ArrayUtils.getOrNull(itemTypes, 0);
+ Class<?> valueType = ArrayUtils.getOrNull(itemTypes, 1);
+ checkArgument((keyType == null) == (valueType == null));
+ object = readHashMapInternal(loader, keyType, valueType);
break;
case VAL_PARCELABLE:
@@ -4533,10 +4539,12 @@
object = readCharSequence();
break;
- case VAL_LIST:
- object = readArrayList(loader);
+ case VAL_LIST: {
+ checkTypeToUnparcel(clazz, ArrayList.class);
+ Class<?> itemType = ArrayUtils.getOrNull(itemTypes, 0);
+ object = readArrayListInternal(loader, itemType);
break;
-
+ }
case VAL_BOOLEANARRAY:
object = createBooleanArray();
break;
@@ -4557,10 +4565,12 @@
object = readStrongBinder();
break;
- case VAL_OBJECTARRAY:
- object = readArray(loader);
+ case VAL_OBJECTARRAY: {
+ Class<?> itemType = ArrayUtils.getOrNull(itemTypes, 0);
+ checkArrayTypeToUnparcel(clazz, (itemType != null) ? itemType : Object.class);
+ object = readArrayInternal(loader, itemType);
break;
-
+ }
case VAL_INTARRAY:
object = createIntArray();
break;
@@ -4577,14 +4587,18 @@
object = readSerializableInternal(loader, clazz);
break;
- case VAL_PARCELABLEARRAY:
- object = readParcelableArray(loader);
+ case VAL_PARCELABLEARRAY: {
+ Class<?> itemType = ArrayUtils.getOrNull(itemTypes, 0);
+ checkArrayTypeToUnparcel(clazz, (itemType != null) ? itemType : Parcelable.class);
+ object = readParcelableArrayInternal(loader, itemType);
break;
-
- case VAL_SPARSEARRAY:
- object = readSparseArray(loader);
+ }
+ case VAL_SPARSEARRAY: {
+ checkTypeToUnparcel(clazz, SparseArray.class);
+ Class<?> itemType = ArrayUtils.getOrNull(itemTypes, 0);
+ object = readSparseArrayInternal(loader, itemType);
break;
-
+ }
case VAL_SPARSEBOOLEANARRAY:
object = readSparseBooleanArray();
break;
@@ -4632,7 +4646,7 @@
+ " at offset " + off);
}
if (object != null && clazz != null && !clazz.isInstance(object)) {
- throw new BadParcelableException("Unparcelled object " + object
+ throw new BadTypeParcelableException("Unparcelled object " + object
+ " is not an instance of required class " + clazz.getName()
+ " provided in the parameter");
}
@@ -4659,6 +4673,38 @@
}
/**
+ * Checks that an array of type T[], where T is {@code componentTypeToUnparcel}, is a subtype of
+ * {@code requiredArrayType}.
+ */
+ private void checkArrayTypeToUnparcel(@Nullable Class<?> requiredArrayType,
+ Class<?> componentTypeToUnparcel) {
+ if (requiredArrayType != null) {
+ // In Java 12, we could use componentTypeToUnparcel.arrayType() for the check
+ Class<?> requiredComponentType = requiredArrayType.getComponentType();
+ if (requiredComponentType == null) {
+ throw new BadTypeParcelableException(
+ "About to unparcel an array but type "
+ + requiredArrayType.getCanonicalName()
+ + " required by caller is not an array.");
+ }
+ checkTypeToUnparcel(requiredComponentType, componentTypeToUnparcel);
+ }
+ }
+
+ /**
+ * Checks that {@code typeToUnparcel} is a subtype of {@code requiredType}, if {@code
+ * requiredType} is not {@code null}.
+ */
+ private void checkTypeToUnparcel(@Nullable Class<?> requiredType, Class<?> typeToUnparcel) {
+ if (requiredType != null && !requiredType.isAssignableFrom(typeToUnparcel)) {
+ throw new BadTypeParcelableException(
+ "About to unparcel a " + typeToUnparcel.getCanonicalName()
+ + ", which is not a subtype of type " + requiredType.getCanonicalName()
+ + " required by caller.");
+ }
+ }
+
+ /**
* Read and return a new Parcelable from the parcel. The given class loader
* will be used to load any enclosed Parcelables. If it is null, the default
* class loader will be used.
@@ -4788,7 +4834,7 @@
if (clazz != null) {
Class<?> parcelableClass = creator.getClass().getEnclosingClass();
if (!clazz.isAssignableFrom(parcelableClass)) {
- throw new BadParcelableException("Parcelable creator " + name + " is not "
+ throw new BadTypeParcelableException("Parcelable creator " + name + " is not "
+ "a subclass of required class " + clazz.getName()
+ " provided in the parameter");
}
@@ -4811,7 +4857,7 @@
}
if (clazz != null) {
if (!clazz.isAssignableFrom(parcelableClass)) {
- throw new BadParcelableException("Parcelable creator " + name + " is not "
+ throw new BadTypeParcelableException("Parcelable creator " + name + " is not "
+ "a subclass of required class " + clazz.getName()
+ " provided in the parameter");
}
@@ -4872,15 +4918,7 @@
@Deprecated
@Nullable
public Parcelable[] readParcelableArray(@Nullable ClassLoader loader) {
- int N = readInt();
- if (N < 0) {
- return null;
- }
- Parcelable[] p = new Parcelable[N];
- for (int i = 0; i < N; i++) {
- p[i] = readParcelable(loader);
- }
- return p;
+ return readParcelableArrayInternal(loader, /* clazz */ null);
}
/**
@@ -4892,14 +4930,20 @@
* trying to instantiate an element.
*/
@SuppressLint({"ArrayReturn", "NullableCollection"})
- @SuppressWarnings("unchecked")
@Nullable
public <T> T[] readParcelableArray(@Nullable ClassLoader loader, @NonNull Class<T> clazz) {
+ return readParcelableArrayInternal(loader, requireNonNull(clazz));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Nullable
+ private <T> T[] readParcelableArrayInternal(@Nullable ClassLoader loader,
+ @Nullable Class<T> clazz) {
int n = readInt();
if (n < 0) {
return null;
}
- T[] p = (T[]) Array.newInstance(clazz, n);
+ T[] p = (T[]) ((clazz == null) ? new Parcelable[n] : Array.newInstance(clazz, n));
for (int i = 0; i < n; i++) {
p[i] = readParcelableInternal(loader, clazz);
}
@@ -4962,7 +5006,7 @@
// the class the same way as ObjectInputStream, using the provided classloader.
Class<?> cl = Class.forName(name, false, loader);
if (!clazz.isAssignableFrom(cl)) {
- throw new BadParcelableException("Serializable object "
+ throw new BadTypeParcelableException("Serializable object "
+ cl.getName() + " is not a subclass of required class "
+ clazz.getName() + " provided in the parameter");
}
@@ -4987,7 +5031,7 @@
// the deserialized object, as we cannot resolve the class the same way as
// ObjectInputStream.
if (!clazz.isAssignableFrom(object.getClass())) {
- throw new BadParcelableException("Serializable object "
+ throw new BadTypeParcelableException("Serializable object "
+ object.getClass().getName() + " is not a subclass of required class "
+ clazz.getName() + " provided in the parameter");
}
@@ -5097,7 +5141,26 @@
readMapInternal(outVal, n, loader, /* clazzKey */null, /* clazzValue */null);
}
- /* package */ <K, V> void readMapInternal(@NonNull Map<? super K, ? super V> outVal, int n,
+ @Nullable
+ private <K, V> HashMap<K, V> readHashMapInternal(@Nullable ClassLoader loader,
+ @NonNull Class<? extends K> clazzKey, @NonNull Class<? extends V> clazzValue) {
+ int n = readInt();
+ if (n < 0) {
+ return null;
+ }
+ HashMap<K, V> map = new HashMap<>(n);
+ readMapInternal(map, n, loader, clazzKey, clazzValue);
+ return map;
+ }
+
+ private <K, V> void readMapInternal(@NonNull Map<? super K, ? super V> outVal,
+ @Nullable ClassLoader loader, @Nullable Class<K> clazzKey,
+ @Nullable Class<V> clazzValue) {
+ int n = readInt();
+ readMapInternal(outVal, n, loader, clazzKey, clazzValue);
+ }
+
+ private <K, V> void readMapInternal(@NonNull Map<? super K, ? super V> outVal, int n,
@Nullable ClassLoader loader, @Nullable Class<K> clazzKey,
@Nullable Class<V> clazzValue) {
while (n > 0) {
@@ -5108,7 +5171,7 @@
}
}
- /* package */ void readArrayMapInternal(@NonNull ArrayMap<? super String, Object> outVal,
+ private void readArrayMapInternal(@NonNull ArrayMap<? super String, Object> outVal,
int size, @Nullable ClassLoader loader) {
readArrayMap(outVal, size, /* sorted */ true, /* lazy */ false, loader);
}
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 315eef7..e3be4d3 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -183,25 +183,29 @@
/**
* Wake lock flag: Turn the screen on when the wake lock is acquired.
* <p>
- * Normally wake locks don't actually wake the device, they just cause
- * the screen to remain on once it's already on. Think of the video player
- * application as the normal behavior. Notifications that pop up and want
- * the device to be on are the exception; use this flag to be like them.
+ * Normally wake locks don't actually wake the device, they just cause the screen to remain on
+ * once it's already on. This flag will cause the device to wake up when the wake lock is
+ * acquired.
* </p><p>
* Android TV playback devices attempt to turn on the HDMI-connected TV via HDMI-CEC on any
* wake-up, including wake-ups triggered by wake locks.
* </p><p>
* Cannot be used with {@link #PARTIAL_WAKE_LOCK}.
* </p>
+ *
+ * @deprecated Most applications should use {@link android.R.attr#turnScreenOn} or
+ * {@link android.app.Activity#setTurnScreenOn(boolean)} instead, as this prevents the previous
+ * foreground app from being resumed first when the screen turns on. Note that this flag may
+ * require a permission in the future.
*/
+ @Deprecated
public static final int ACQUIRE_CAUSES_WAKEUP = 0x10000000;
/**
* Wake lock flag: When this wake lock is released, poke the user activity timer
* so the screen stays on for a little longer.
* <p>
- * Will not turn the screen on if it is not already on.
- * See {@link #ACQUIRE_CAUSES_WAKEUP} if you want that.
+ * This will not turn the screen on if it is not already on.
* </p><p>
* Cannot be used with {@link #PARTIAL_WAKE_LOCK}.
* </p>
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 944b717..a3b836a 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -674,10 +674,12 @@
}
try {
if (!rs.allocateSpaceForUpdate(packageFile)) {
+ rs.clearBcb();
throw new IOException("Failed to allocate space for update "
+ packageFile.getAbsolutePath());
}
} catch (RemoteException e) {
+ rs.clearBcb();
e.rethrowAsRuntimeException();
}
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index cc98339..48e2827 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -3022,9 +3022,17 @@
}
}
- /** @hide */
- @TestApi
+ /**
+ * Returns the authority of the current cloud media provider that was set by the
+ * {@link android.service.storage.ExternalStorageService} holding the
+ * {@link android.Manifest.permission#WRITE_MEDIA_STORAGE} permission via
+ * {@link #setCloudMediaProvider(String)}.
+ *
+ * @hide
+ */
@Nullable
+ @TestApi
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public String getCloudMediaProvider() {
try {
return mStorageManager.getCloudMediaProvider();
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 87f4489..afd1283 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -407,6 +407,13 @@
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
@@ -586,7 +593,7 @@
@NonNull
private static final List<String> PUBLIC_NAMESPACES =
Arrays.asList(NAMESPACE_TEXTCLASSIFIER, NAMESPACE_RUNTIME, NAMESPACE_STATSD_JAVA,
- NAMESPACE_STATSD_JAVA_BOOT, NAMESPACE_SELECTION_TOOLBAR);
+ NAMESPACE_STATSD_JAVA_BOOT, NAMESPACE_SELECTION_TOOLBAR, NAMESPACE_AUTOFILL);
/**
* Privacy related properties definitions.
*
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 23e02e9..8feff16 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -24,7 +24,6 @@
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
-import android.annotation.StringDef;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.TestApi;
@@ -2128,7 +2127,7 @@
/**
* Intent extra: The id of a setting restricted by supervisors.
* <p>
- * Type: String with a value from the SupervisorVerificationSetting annotation below.
+ * Type: Integer with a value from the SupervisorVerificationSetting annotation below.
* <ul>
* <li>{@link #SUPERVISOR_VERIFICATION_SETTING_UNKNOWN}
* <li>{@link #SUPERVISOR_VERIFICATION_SETTING_BIOMETRICS}
@@ -2141,20 +2140,19 @@
/**
* Unknown setting.
*/
- public static final String SUPERVISOR_VERIFICATION_SETTING_UNKNOWN = "";
+ public static final int SUPERVISOR_VERIFICATION_SETTING_UNKNOWN = 0;
/**
* Biometric settings for supervisors.
*/
- public static final String SUPERVISOR_VERIFICATION_SETTING_BIOMETRICS =
- "supervisor_restricted_biometrics_controller";
+ public static final int SUPERVISOR_VERIFICATION_SETTING_BIOMETRICS = 1;
/**
* Keys for {@link #EXTRA_SUPERVISOR_RESTRICTED_SETTING_KEY}.
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
- @StringDef(prefix = { "SUPERVISOR_VERIFICATION_SETTING_" }, value = {
+ @IntDef(prefix = { "SUPERVISOR_VERIFICATION_SETTING_" }, value = {
SUPERVISOR_VERIFICATION_SETTING_UNKNOWN,
SUPERVISOR_VERIFICATION_SETTING_BIOMETRICS,
})
@@ -9950,6 +9948,14 @@
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
@@ -9965,6 +9971,13 @@
"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/DreamOverlayService.java b/core/java/android/service/dreams/DreamOverlayService.java
index 163d6ed..bfc3b8b 100644
--- a/core/java/android/service/dreams/DreamOverlayService.java
+++ b/core/java/android/service/dreams/DreamOverlayService.java
@@ -36,6 +36,9 @@
private static final String TAG = "DreamOverlayService";
private static final boolean DEBUG = false;
private boolean mShowComplications;
+ private boolean mIsPreviewMode;
+ @Nullable
+ private CharSequence mDreamLabel;
private IDreamOverlay mDreamOverlay = new IDreamOverlay.Stub() {
@Override
@@ -56,6 +59,8 @@
public final IBinder onBind(@NonNull Intent intent) {
mShowComplications = intent.getBooleanExtra(DreamService.EXTRA_SHOW_COMPLICATIONS,
DreamService.DEFAULT_SHOW_COMPLICATIONS);
+ mIsPreviewMode = intent.getBooleanExtra(DreamService.EXTRA_IS_PREVIEW, false);
+ mDreamLabel = intent.getCharSequenceExtra(DreamService.EXTRA_DREAM_LABEL);
return mDreamOverlay.asBinder();
}
@@ -84,4 +89,19 @@
public final boolean shouldShowComplications() {
return mShowComplications;
}
+
+ /**
+ * Returns whether the dream is running in preview mode.
+ */
+ public final boolean isPreviewMode() {
+ return mIsPreviewMode;
+ }
+
+ /**
+ * Returns the user-facing label of the currently running dream.
+ */
+ @Nullable
+ public final CharSequence getDreamLabel() {
+ return mDreamLabel;
+ }
}
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 3459172..db622d3 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -216,6 +216,18 @@
"android.service.dreams.SHOW_COMPLICATIONS";
/**
+ * Extra containing a boolean for whether we are showing this dream in preview mode.
+ * @hide
+ */
+ public static final String EXTRA_IS_PREVIEW = "android.service.dreams.IS_PREVIEW";
+
+ /**
+ * The user-facing label of the current dream service.
+ * @hide
+ */
+ public static final String EXTRA_DREAM_LABEL = "android.service.dreams.DREAM_LABEL";
+
+ /**
* The default value for whether to show complications on the overlay.
* @hide
*/
@@ -258,15 +270,19 @@
}
public void bind(Context context, @Nullable ComponentName overlayService,
- ComponentName dreamService) {
+ ComponentName dreamService, boolean isPreviewMode) {
if (overlayService == null) {
return;
}
+ final ServiceInfo serviceInfo = fetchServiceInfo(context, dreamService);
+
final Intent overlayIntent = new Intent();
overlayIntent.setComponent(overlayService);
overlayIntent.putExtra(EXTRA_SHOW_COMPLICATIONS,
- fetchShouldShowComplications(context, dreamService));
+ fetchShouldShowComplications(context, serviceInfo));
+ overlayIntent.putExtra(EXTRA_DREAM_LABEL, fetchDreamLabel(context, serviceInfo));
+ overlayIntent.putExtra(EXTRA_IS_PREVIEW, isPreviewMode);
context.bindService(overlayIntent,
this, Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE);
@@ -988,8 +1004,11 @@
// Connect to the overlay service if present.
if (!mWindowless) {
- mOverlayConnection.bind(this, intent.getParcelableExtra(EXTRA_DREAM_OVERLAY_COMPONENT),
- new ComponentName(this, getClass()));
+ mOverlayConnection.bind(
+ /* context= */ this,
+ intent.getParcelableExtra(EXTRA_DREAM_OVERLAY_COMPONENT),
+ new ComponentName(this, getClass()),
+ intent.getBooleanExtra(EXTRA_IS_PREVIEW, /* defaultValue= */ false));
}
return mDreamServiceWrapper;
@@ -1111,7 +1130,10 @@
* @hide
*/
@Nullable
- public static DreamMetadata getDreamMetadata(Context context, ServiceInfo serviceInfo) {
+ public static DreamMetadata getDreamMetadata(Context context,
+ @Nullable ServiceInfo serviceInfo) {
+ if (serviceInfo == null) return null;
+
final PackageManager pm = context.getPackageManager();
final TypedArray rawMetadata = readMetadata(pm, serviceInfo);
@@ -1350,22 +1372,33 @@
* {@link DreamService#DEFAULT_SHOW_COMPLICATIONS}.
*/
private static boolean fetchShouldShowComplications(Context context,
- ComponentName componentName) {
+ @Nullable ServiceInfo serviceInfo) {
+ final DreamMetadata metadata = getDreamMetadata(context, serviceInfo);
+ if (metadata != null) {
+ return metadata.showComplications;
+ }
+ return DEFAULT_SHOW_COMPLICATIONS;
+ }
+
+ @Nullable
+ private static CharSequence fetchDreamLabel(Context context,
+ @Nullable ServiceInfo serviceInfo) {
+ if (serviceInfo == null) return null;
+ final PackageManager pm = context.getPackageManager();
+ return serviceInfo.loadLabel(pm);
+ }
+
+ @Nullable
+ private static ServiceInfo fetchServiceInfo(Context context, ComponentName componentName) {
final PackageManager pm = context.getPackageManager();
try {
- final ServiceInfo si = pm.getServiceInfo(componentName,
+ return pm.getServiceInfo(componentName,
PackageManager.ComponentInfoFlags.of(PackageManager.GET_META_DATA));
- final DreamMetadata metadata = getDreamMetadata(context, si);
-
- if (metadata != null) {
- return metadata.showComplications;
- }
} catch (PackageManager.NameNotFoundException e) {
if (DEBUG) Log.w(TAG, "cannot find component " + componentName.flattenToShortString());
}
-
- return DEFAULT_SHOW_COMPLICATIONS;
+ return null;
}
@Override
diff --git a/core/java/android/service/selectiontoolbar/FloatingToolbarRoot.java b/core/java/android/service/selectiontoolbar/FloatingToolbarRoot.java
index 8fe6f71..adc9251 100644
--- a/core/java/android/service/selectiontoolbar/FloatingToolbarRoot.java
+++ b/core/java/android/service/selectiontoolbar/FloatingToolbarRoot.java
@@ -40,7 +40,7 @@
private final IBinder mTargetInputToken;
private final SelectionToolbarRenderService.TransferTouchListener mTransferTouchListener;
- private Rect mContentRect;
+ private final Rect mContentRect = new Rect();
private int mLastDownX = -1;
private int mLastDownY = -1;
@@ -57,7 +57,7 @@
* Sets the Rect that shows the selection toolbar content.
*/
public void setContentRect(Rect contentRect) {
- mContentRect = contentRect;
+ mContentRect.set(contentRect);
}
@Override
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index 542de3f..c1fcd66 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -239,8 +239,10 @@
* @param events Events
* @param notifyNow Whether to notify instantly
*/
- public void listenFromListener(int subId, @NonNull String pkg, @NonNull String featureId,
- @NonNull PhoneStateListener listener, @NonNull int events, boolean notifyNow) {
+ public void listenFromListener(int subId, @NonNull boolean renounceFineLocationAccess,
+ @NonNull boolean renounceCoarseLocationAccess, @NonNull String pkg,
+ @NonNull String featureId, @NonNull PhoneStateListener listener,
+ @NonNull int events, boolean notifyNow) {
if (listener == null) {
throw new IllegalStateException("telephony service is null.");
}
@@ -257,8 +259,8 @@
} else if (listener.mSubId != null) {
subId = listener.mSubId;
}
- sRegistry.listenWithEventList(false, false, subId, pkg, featureId,
- listener.callback, eventsList, notifyNow);
+ sRegistry.listenWithEventList(renounceFineLocationAccess, renounceCoarseLocationAccess,
+ subId, pkg, featureId, listener.callback, eventsList, notifyNow);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/util/DumpableContainer.java b/core/java/android/util/DumpableContainer.java
index e7b2acd..fef5acd 100644
--- a/core/java/android/util/DumpableContainer.java
+++ b/core/java/android/util/DumpableContainer.java
@@ -18,8 +18,7 @@
import android.annotation.NonNull;
/**
- * Objects that contains a list of {@link Dumpable}, which will be dumped when the object itself
- * is dumped.
+ * Represents a container that manages {@link Dumpable dumpables}.
*/
public interface DumpableContainer {
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index ce21086..53b842a 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -18,6 +18,7 @@
import com.android.internal.os.IResultReceiver;
import com.android.internal.policy.IKeyguardDismissCallback;
+import com.android.internal.policy.IKeyguardLockedStateListener;
import com.android.internal.policy.IShortcutService;
import android.app.IAssistDataReceiver;
@@ -199,6 +200,9 @@
boolean isKeyguardSecure(int userId);
void dismissKeyguard(IKeyguardDismissCallback callback, CharSequence message);
+ void addKeyguardLockedStateListener(in IKeyguardLockedStateListener listener);
+ void removeKeyguardLockedStateListener(in IKeyguardLockedStateListener listener);
+
// Requires INTERACT_ACROSS_USERS_FULL permission
void setSwitchingUser(boolean switching);
diff --git a/core/java/android/view/ImeFocusController.java b/core/java/android/view/ImeFocusController.java
index 3fc9f6b..b48b525 100644
--- a/core/java/android/view/ImeFocusController.java
+++ b/core/java/android/view/ImeFocusController.java
@@ -54,13 +54,11 @@
@NonNull
private InputMethodManagerDelegate getImmDelegate() {
- InputMethodManagerDelegate delegate = mDelegate;
- if (delegate != null) {
- return delegate;
+ if (mDelegate == null) {
+ mDelegate = mViewRootImpl.mContext.getSystemService(
+ InputMethodManager.class).getDelegate();
}
- delegate = mViewRootImpl.mContext.getSystemService(InputMethodManager.class).getDelegate();
- mDelegate = delegate;
- return delegate;
+ return mDelegate;
}
/** Called when the view root is moved to a different display. */
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index 188d745..7d56039 100644
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -737,15 +737,47 @@
}
/**
- * Gets the key code produced by the specified location on a US keyboard layout.
- * Key code as defined in {@link android.view.KeyEvent}.
- * This API is only functional for devices with {@link InputDevice#SOURCE_KEYBOARD} available
- * which can alter their key mapping using country specific keyboard layouts.
+ * Gets the {@link android.view.KeyEvent key code} produced by the given location on a reference
+ * QWERTY keyboard layout.
+ * <p>
+ * This API is useful for querying the physical location of keys that change the character
+ * produced based on the current locale and keyboard layout.
+ * <p>
+ * The following table provides a non-exhaustive list of examples:
+ * <table border="2" width="85%" align="center" cellpadding="5">
+ * <thead>
+ * <tr><th>Active Keyboard Layout</th> <th>Input Parameter</th>
+ * <th>Return Value</th></tr>
+ * </thead>
*
- * @param locationKeyCode The location of a key on a US keyboard layout.
- * @return The key code produced when pressing the key at the specified location, given the
- * active keyboard layout. Returns {@link KeyEvent#KEYCODE_UNKNOWN} if the requested
- * mapping could not be determined, or if an error occurred.
+ * <tbody>
+ * <tr>
+ * <td>French AZERTY</td>
+ * <td><code>{@link KeyEvent#KEYCODE_Q}</code></td>
+ * <td><code>{@link KeyEvent#KEYCODE_A}</code></td>
+ * </tr>
+ * <tr>
+ * <td>German QWERTZ</td>
+ * <td><code>{@link KeyEvent#KEYCODE_Y}</code></td>
+ * <td><code>{@link KeyEvent#KEYCODE_Z}</code></td>
+ * </tr>
+ * <tr>
+ * <td>US QWERTY</td>
+ * <td><code>{@link KeyEvent#KEYCODE_B}</code></td>
+ * <td><code>{@link KeyEvent#KEYCODE_B}</code></td>
+ * </tr>
+ * </tbody>
+ * </table>
+ *
+ * @param locationKeyCode The location of a key specified as a key code on the QWERTY layout.
+ * This provides a consistent way of referring to the physical location of a key independently
+ * of the current keyboard layout. Also see the
+ * <a href="https://www.w3.org/TR/2017/CR-uievents-code-20170601/#key-alphanumeric-writing-system">
+ * hypothetical keyboard</a> provided by the W3C, which may be helpful for identifying the
+ * physical location of a key.
+ * @return The key code produced by the key at the specified location, given the current
+ * keyboard layout. Returns {@link KeyEvent#KEYCODE_UNKNOWN} if the device does not specify
+ * {@link InputDevice#SOURCE_KEYBOARD} or the requested mapping cannot be determined.
*/
public int getKeyCodeForKeyLocation(int locationKeyCode) {
return InputManager.getInstance().getKeyCodeForKeyLocation(mId, locationKeyCode);
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 98cef958..64f5668 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -248,6 +248,7 @@
private static native void nativeSetFixedTransformHint(long transactionObj, long nativeObject,
int transformHint);
+ private static native void nativeRemoveCurrentInputFocus(long nativeObject, int displayId);
private static native void nativeSetFocusedWindow(long transactionObj, IBinder toToken,
String windowName, IBinder focusedToken, String focusedWindowName, int displayId);
private static native void nativeSetFrameTimelineVsync(long transactionObj,
@@ -264,6 +265,8 @@
private static native void nativeAddTransactionCommittedListener(long nativeObject,
TransactionCommittedListener listener);
private static native void nativeSanitize(long transactionObject);
+ private static native void nativeSetDestinationFrame(long transactionObj, long nativeObject,
+ int l, int t, int r, int b);
/**
* Transforms that can be applied to buffers as they are displayed to a window.
@@ -3094,6 +3097,10 @@
* @param destFrame The destination rectangle in parent space. Or null for the source frame.
* @param orientation The buffer rotation
* @return This transaction object.
+ * @deprecated Use {@link #setCrop(SurfaceControl, Rect)},
+ * {@link #setBufferTransform(SurfaceControl, int)},
+ * {@link #setPosition(SurfaceControl, float, float)} and
+ * {@link #setScale(SurfaceControl, float, float)} instead.
*/
@NonNull
public Transaction setGeometry(@NonNull SurfaceControl sc, @Nullable Rect sourceCrop,
@@ -3653,6 +3660,17 @@
}
/**
+ * Removes the input focus from the current window which is having the input focus. Should
+ * only be called when the current focused app is not responding and the current focused
+ * window is not beloged to the current focused app.
+ * @hide
+ */
+ public Transaction removeCurrentInputFocus(int displayId) {
+ nativeRemoveCurrentInputFocus(mNativeObject, displayId);
+ return this;
+ }
+
+ /**
* Adds or removes the flag SKIP_SCREENSHOT of the surface. Setting the flag is equivalent
* to creating the Surface with the {@link #SKIP_SCREENSHOT} flag.
*
@@ -3834,6 +3852,26 @@
}
/**
+ * @hide
+ */
+ public Transaction setDesintationFrame(SurfaceControl sc, @NonNull Rect destinationFrame) {
+ checkPreconditions(sc);
+ nativeSetDestinationFrame(mNativeObject, sc.mNativeObject,
+ destinationFrame.left, destinationFrame.top, destinationFrame.right,
+ destinationFrame.bottom);
+ return this;
+ }
+
+ /**
+ * @hide
+ */
+ public Transaction setDesintationFrame(SurfaceControl sc, int width, int height) {
+ checkPreconditions(sc);
+ nativeSetDestinationFrame(mNativeObject, sc.mNativeObject, 0, 0, width, height);
+ return this;
+ }
+
+ /**
* Merge the other transaction into this transaction, clearing the
* other transaction as if it had been applied.
*
diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java
index 2edfda5..a13579d 100644
--- a/core/java/android/view/SurfaceControlViewHost.java
+++ b/core/java/android/view/SurfaceControlViewHost.java
@@ -328,7 +328,8 @@
*/
public @Nullable SurfacePackage getSurfacePackage() {
if (mSurfaceControl != null && mAccessibilityEmbeddedConnection != null) {
- return new SurfacePackage(mSurfaceControl, mAccessibilityEmbeddedConnection,
+ return new SurfacePackage(new SurfaceControl(mSurfaceControl, "getSurfacePackage"),
+ mAccessibilityEmbeddedConnection,
mWm.getFocusGrantToken(), mRemoteInterface);
} else {
return null;
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 1a458ce..55300b3 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -133,9 +133,8 @@
private boolean mDisableBackgroundLayer = false;
/**
- * We use this lock to protect access to mSurfaceControl and
- * SurfaceViewPositionUpdateListener#mPositionChangedTransaction. Both are accessed on the UI
- * thread and the render thread.
+ * We use this lock to protect access to mSurfaceControl. Both are accessed on the UI
+ * thread and the render thread via RenderNode.PositionUpdateListener#positionLost.
*/
final Object mSurfaceControlLock = new Object();
final Rect mTmpRect = new Rect();
@@ -224,12 +223,6 @@
private final SurfaceControl.Transaction mFrameCallbackTransaction =
new SurfaceControl.Transaction();
- /**
- * A temporary transaction holder that should only be used when applying right away. There
- * should be no assumption about thread safety for this transaction.
- */
- private final SurfaceControl.Transaction mTmpTransaction = new SurfaceControl.Transaction();
-
private int mParentSurfaceSequenceId;
private RemoteAccessibilityController mRemoteAccessibilityController =
@@ -760,7 +753,7 @@
mBlastBufferQueue = null;
}
- Transaction transaction = new Transaction();
+ final Transaction transaction = new Transaction();
if (mSurfaceControl != null) {
transaction.remove(mSurfaceControl);
mSurfaceControl = null;
@@ -790,22 +783,18 @@
// synchronously otherwise we may see flickers.
// When the listener is updated, we will get at least a single position update call so we can
// guarantee any changes we post will be applied.
- private void replacePositionUpdateListener(int surfaceWidth, int surfaceHeight,
- Transaction geometryTransaction) {
+ private void replacePositionUpdateListener(int surfaceWidth, int surfaceHeight) {
if (mPositionListener != null) {
mRenderNode.removePositionUpdateListener(mPositionListener);
- synchronized (mSurfaceControlLock) {
- geometryTransaction = mPositionListener.getTransaction().merge(geometryTransaction);
- }
}
mPositionListener = new SurfaceViewPositionUpdateListener(surfaceWidth, surfaceHeight,
- geometryTransaction);
+ mSurfaceControl);
mRenderNode.addPositionUpdateListener(mPositionListener);
}
private boolean performSurfaceTransaction(ViewRootImpl viewRoot, Translator translator,
boolean creating, boolean sizeChanged, boolean hintChanged,
- Transaction geometryTransaction) {
+ Transaction surfaceUpdateTransaction) {
boolean realSizeChanged = false;
mSurfaceLock.lock();
@@ -820,56 +809,60 @@
// SurfaceChangedCallback to update the relative z. This is needed so that
// we do not change the relative z before the server is ready to swap the
// parent surface.
- if (creating || (mParentSurfaceSequenceId == viewRoot.getSurfaceSequenceId())) {
- updateRelativeZ(mTmpTransaction);
+ if (creating) {
+ updateRelativeZ(surfaceUpdateTransaction);
+ if (mSurfacePackage != null) {
+ reparentSurfacePackage(surfaceUpdateTransaction, mSurfacePackage);
+ }
}
mParentSurfaceSequenceId = viewRoot.getSurfaceSequenceId();
if (mViewVisibility) {
- geometryTransaction.show(mSurfaceControl);
+ surfaceUpdateTransaction.show(mSurfaceControl);
} else {
- geometryTransaction.hide(mSurfaceControl);
+ surfaceUpdateTransaction.hide(mSurfaceControl);
}
- if (mSurfacePackage != null) {
- reparentSurfacePackage(mTmpTransaction, mSurfacePackage);
- }
- updateBackgroundVisibility(mTmpTransaction);
- updateBackgroundColor(mTmpTransaction);
+
+ updateBackgroundVisibility(surfaceUpdateTransaction);
+ updateBackgroundColor(surfaceUpdateTransaction);
if (mUseAlpha) {
float alpha = getFixedAlpha();
- mTmpTransaction.setAlpha(mSurfaceControl, alpha);
+ surfaceUpdateTransaction.setAlpha(mSurfaceControl, alpha);
mSurfaceAlpha = alpha;
}
- geometryTransaction.setCornerRadius(mSurfaceControl, mCornerRadius);
+ surfaceUpdateTransaction.setCornerRadius(mSurfaceControl, mCornerRadius);
if ((sizeChanged || hintChanged) && !creating) {
- setBufferSize(geometryTransaction);
+ setBufferSize(surfaceUpdateTransaction);
}
if (sizeChanged || creating || !isHardwareAccelerated()) {
- onSetSurfacePositionAndScaleRT(geometryTransaction, mSurfaceControl,
- mScreenRect.left, /*positionLeft*/
- mScreenRect.top /*positionTop*/ ,
- mScreenRect.width() / (float) mSurfaceWidth /*postScaleX*/,
- mScreenRect.height() / (float) mSurfaceHeight /*postScaleY*/);
// Set a window crop when creating the surface or changing its size to
// crop the buffer to the surface size since the buffer producer may
// use SCALING_MODE_SCALE and submit a larger size than the surface
// size.
if (mClipSurfaceToBounds && mClipBounds != null) {
- geometryTransaction.setWindowCrop(mSurfaceControl, mClipBounds);
+ surfaceUpdateTransaction.setWindowCrop(mSurfaceControl, mClipBounds);
} else {
- geometryTransaction.setWindowCrop(mSurfaceControl, mSurfaceWidth,
+ surfaceUpdateTransaction.setWindowCrop(mSurfaceControl, mSurfaceWidth,
mSurfaceHeight);
}
+ surfaceUpdateTransaction.setDesintationFrame(mBlastSurfaceControl, mSurfaceWidth,
+ mSurfaceHeight);
+
if (isHardwareAccelerated()) {
// This will consume the passed in transaction and the transaction will be
// applied on a render worker thread.
- replacePositionUpdateListener(mSurfaceWidth, mSurfaceHeight,
- geometryTransaction);
+ replacePositionUpdateListener(mSurfaceWidth, mSurfaceHeight);
+ } else {
+ onSetSurfacePositionAndScale(surfaceUpdateTransaction, mSurfaceControl,
+ mScreenRect.left /*positionLeft*/,
+ mScreenRect.top /*positionTop*/,
+ mScreenRect.width() / (float) mSurfaceWidth /*postScaleX*/,
+ mScreenRect.height() / (float) mSurfaceHeight /*postScaleY*/);
}
if (DEBUG_POSITION) {
Log.d(TAG, String.format(
@@ -881,8 +874,7 @@
mScreenRect.bottom, mSurfaceWidth, mSurfaceHeight));
}
}
- mTmpTransaction.merge(geometryTransaction);
- mTmpTransaction.apply();
+ applyTransactionOnVriDraw(surfaceUpdateTransaction);
updateEmbeddedAccessibilityMatrix();
mSurfaceFrame.left = 0;
@@ -990,17 +982,17 @@
mScreenRect.offset(surfaceInsets.left, surfaceInsets.top);
// Collect all geometry changes and apply these changes on the RenderThread worker
// via the RenderNode.PositionUpdateListener.
- final Transaction geometryTransaction = new Transaction();
+ final Transaction surfaceUpdateTransaction = new Transaction();
if (creating) {
updateOpaqueFlag();
final String name = "SurfaceView[" + viewRoot.getTitle().toString() + "]";
- createBlastSurfaceControls(viewRoot, name, geometryTransaction);
+ createBlastSurfaceControls(viewRoot, name, surfaceUpdateTransaction);
} else if (mSurfaceControl == null) {
return;
}
final boolean realSizeChanged = performSurfaceTransaction(viewRoot,
- translator, creating, sizeChanged, hintChanged, geometryTransaction);
+ translator, creating, sizeChanged, hintChanged, surfaceUpdateTransaction);
final boolean redrawNeeded = sizeChanged || creating || hintChanged
|| (mVisible && !mDrawFinished);
@@ -1107,7 +1099,7 @@
mBlastSurfaceControl.setTransformHint(mTransformHint);
if (mBlastBufferQueue != null) {
mBlastBufferQueue.update(mBlastSurfaceControl, mSurfaceWidth, mSurfaceHeight,
- mFormat, transaction);
+ mFormat);
}
}
@@ -1136,7 +1128,7 @@
*
*/
private void createBlastSurfaceControls(ViewRootImpl viewRoot, String name,
- Transaction geometryTransaction) {
+ Transaction surfaceUpdateTransaction) {
if (mSurfaceControl == null) {
mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession)
.setName(name)
@@ -1159,11 +1151,10 @@
.build();
} else {
// update blast layer
- mTmpTransaction
+ surfaceUpdateTransaction
.setOpaque(mBlastSurfaceControl, (mSurfaceFlags & SurfaceControl.OPAQUE) != 0)
.setSecure(mBlastSurfaceControl, (mSurfaceFlags & SurfaceControl.SECURE) != 0)
- .show(mBlastSurfaceControl)
- .apply();
+ .show(mBlastSurfaceControl);
}
if (mBackgroundControl == null) {
@@ -1184,9 +1175,8 @@
}
mTransformHint = viewRoot.getBufferTransformHint();
mBlastSurfaceControl.setTransformHint(mTransformHint);
- mBlastBufferQueue = new BLASTBufferQueue(name);
- mBlastBufferQueue.update(mBlastSurfaceControl, mSurfaceWidth, mSurfaceHeight, mFormat,
- geometryTransaction);
+ mBlastBufferQueue = new BLASTBufferQueue(name, false /* updateDestinationFrame */);
+ mBlastBufferQueue.update(mBlastSurfaceControl, mSurfaceWidth, mSurfaceHeight, mFormat);
}
private void onDrawFinished(Transaction t) {
@@ -1211,7 +1201,7 @@
*
* @hide
*/
- protected void onSetSurfacePositionAndScaleRT(@NonNull Transaction transaction,
+ protected void onSetSurfacePositionAndScale(@NonNull Transaction transaction,
@NonNull SurfaceControl surface, int positionLeft, int positionTop,
float postScaleX, float postScaleY) {
transaction.setPosition(surface, positionLeft, positionTop);
@@ -1224,12 +1214,14 @@
if (mSurfaceControl == null) {
return;
}
- onSetSurfacePositionAndScaleRT(mTmpTransaction, mSurfaceControl,
+ final Transaction transaction = new Transaction();
+ onSetSurfacePositionAndScale(transaction, mSurfaceControl,
mScreenRect.left, /*positionLeft*/
mScreenRect.top/*positionTop*/ ,
mScreenRect.width() / (float) mSurfaceWidth /*postScaleX*/,
mScreenRect.height() / (float) mSurfaceHeight /*postScaleY*/);
- mTmpTransaction.apply();
+ applyTransactionOnVriDraw(transaction);
+ invalidate();
}
/**
@@ -1251,66 +1243,57 @@
}
}
- private Rect mRTLastReportedPosition = new Rect();
- private Point mRTLastReportedSurfaceSize = new Point();
+ private final Rect mRTLastReportedPosition = new Rect();
+ private final Point mRTLastReportedSurfaceSize = new Point();
private class SurfaceViewPositionUpdateListener implements RenderNode.PositionUpdateListener {
- int mRtSurfaceWidth = -1;
- int mRtSurfaceHeight = -1;
+ private final int mRtSurfaceWidth;
+ private final int mRtSurfaceHeight;
private final SurfaceControl.Transaction mPositionChangedTransaction =
new SurfaceControl.Transaction();
- boolean mPendingTransaction = false;
+ private final SurfaceControl mRtSurfaceControl = new SurfaceControl();
SurfaceViewPositionUpdateListener(int surfaceWidth, int surfaceHeight,
- @Nullable Transaction t) {
+ SurfaceControl surfaceControl) {
mRtSurfaceWidth = surfaceWidth;
mRtSurfaceHeight = surfaceHeight;
- if (t != null) {
- mPositionChangedTransaction.merge(t);
- mPendingTransaction = true;
- }
+ mRtSurfaceControl.copyFrom(surfaceControl, "SurfaceViewPositionUpdateListener");
}
@Override
public void positionChanged(long frameNumber, int left, int top, int right, int bottom) {
- synchronized(mSurfaceControlLock) {
- if (mSurfaceControl == null) {
- return;
+ if (mRTLastReportedPosition.left == left
+ && mRTLastReportedPosition.top == top
+ && mRTLastReportedPosition.right == right
+ && mRTLastReportedPosition.bottom == bottom
+ && mRTLastReportedSurfaceSize.x == mRtSurfaceWidth
+ && mRTLastReportedSurfaceSize.y == mRtSurfaceHeight) {
+ return;
+ }
+ try {
+ if (DEBUG_POSITION) {
+ Log.d(TAG, String.format(
+ "%d updateSurfacePosition RenderWorker, frameNr = %d, "
+ + "position = [%d, %d, %d, %d] surfaceSize = %dx%d",
+ System.identityHashCode(SurfaceView.this), frameNumber,
+ left, top, right, bottom, mRtSurfaceWidth, mRtSurfaceHeight));
}
- if (mRTLastReportedPosition.left == left
- && mRTLastReportedPosition.top == top
- && mRTLastReportedPosition.right == right
- && mRTLastReportedPosition.bottom == bottom
- && mRTLastReportedSurfaceSize.x == mRtSurfaceWidth
- && mRTLastReportedSurfaceSize.y == mRtSurfaceHeight
- && !mPendingTransaction) {
- return;
+ mRTLastReportedPosition.set(left, top, right, bottom);
+ mRTLastReportedSurfaceSize.set(mRtSurfaceWidth, mRtSurfaceHeight);
+ onSetSurfacePositionAndScale(mPositionChangedTransaction, mRtSurfaceControl,
+ mRTLastReportedPosition.left /*positionLeft*/,
+ mRTLastReportedPosition.top /*positionTop*/,
+ mRTLastReportedPosition.width()
+ / (float) mRtSurfaceWidth /*postScaleX*/,
+ mRTLastReportedPosition.height()
+ / (float) mRtSurfaceHeight /*postScaleY*/);
+ if (mViewVisibility) {
+ // b/131239825
+ mPositionChangedTransaction.show(mRtSurfaceControl);
}
- try {
- if (DEBUG_POSITION) {
- Log.d(TAG, String.format(
- "%d updateSurfacePosition RenderWorker, frameNr = %d, "
- + "position = [%d, %d, %d, %d] surfaceSize = %dx%d",
- System.identityHashCode(SurfaceView.this), frameNumber,
- left, top, right, bottom, mRtSurfaceWidth, mRtSurfaceHeight));
- }
- mRTLastReportedPosition.set(left, top, right, bottom);
- mRTLastReportedSurfaceSize.set(mRtSurfaceWidth, mRtSurfaceHeight);
- onSetSurfacePositionAndScaleRT(mPositionChangedTransaction, mSurfaceControl,
- mRTLastReportedPosition.left /*positionLeft*/,
- mRTLastReportedPosition.top /*positionTop*/,
- mRTLastReportedPosition.width()
- / (float) mRtSurfaceWidth /*postScaleX*/,
- mRTLastReportedPosition.height()
- / (float) mRtSurfaceHeight /*postScaleY*/);
- if (mViewVisibility) {
- mPositionChangedTransaction.show(mSurfaceControl);
- }
- applyOrMergeTransaction(mPositionChangedTransaction, frameNumber);
- mPendingTransaction = false;
- } catch (Exception ex) {
- Log.e(TAG, "Exception from repositionChild", ex);
- }
+ applyOrMergeTransaction(mPositionChangedTransaction, frameNumber);
+ } catch (Exception ex) {
+ Log.e(TAG, "Exception from repositionChild", ex);
}
}
@@ -1319,7 +1302,7 @@
float vecX, float vecY, float maxStretchX, float maxStretchY,
float childRelativeLeft, float childRelativeTop, float childRelativeRight,
float childRelativeBottom) {
- mRtTransaction.setStretchEffect(mSurfaceControl, width, height, vecX, vecY,
+ mRtTransaction.setStretchEffect(mRtSurfaceControl, width, height, vecX, vecY,
maxStretchX, maxStretchY, childRelativeLeft, childRelativeTop,
childRelativeRight, childRelativeBottom);
applyOrMergeTransaction(mRtTransaction, frameNumber);
@@ -1334,28 +1317,14 @@
mRTLastReportedPosition.setEmpty();
mRTLastReportedSurfaceSize.set(-1, -1);
- /**
- * positionLost can be called while UI thread is un-paused so we
- * need to hold the lock here.
- */
+ // positionLost can be called while UI thread is un-paused.
synchronized (mSurfaceControlLock) {
- if (mPendingTransaction) {
- Log.w(TAG, System.identityHashCode(SurfaceView.this)
- + "Pending transaction cleared.");
- mPositionChangedTransaction.clear();
- mPendingTransaction = false;
- }
- if (mSurfaceControl == null) {
- return;
- }
+ if (mSurfaceControl == null) return;
+ // b/131239825
mRtTransaction.hide(mSurfaceControl);
applyOrMergeTransaction(mRtTransaction, frameNumber);
}
}
-
- public Transaction getTransaction() {
- return mPositionChangedTransaction;
- }
}
private SurfaceViewPositionUpdateListener mPositionListener = null;
@@ -1402,8 +1371,10 @@
* @hide
*/
public void setResizeBackgroundColor(int bgColor) {
- setResizeBackgroundColor(mTmpTransaction, bgColor);
- mTmpTransaction.apply();
+ final SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
+ setResizeBackgroundColor(transaction, bgColor);
+ applyTransactionOnVriDraw(transaction);
+ invalidate();
}
/**
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 1566f9e..785735c 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -184,6 +184,7 @@
*/
public static final String DEBUG_FORCE_DARK = "debug.hwui.force_dark";
+ public static int EGL_CONTEXT_PRIORITY_REALTIME_NV = 0x3357;
public static int EGL_CONTEXT_PRIORITY_HIGH_IMG = 0x3101;
public static int EGL_CONTEXT_PRIORITY_MEDIUM_IMG = 0x3102;
public static int EGL_CONTEXT_PRIORITY_LOW_IMG = 0x3103;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 286b502..553c537 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -8226,9 +8226,25 @@
*/
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,12 +14184,15 @@
}
// 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 ((getVisibility() == VISIBLE)
+ if ((isAggregatedVisible())
|| (changeType == AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED)) {
final AccessibilityEvent event = AccessibilityEvent.obtain();
onInitializeAccessibilityEvent(event);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 8444032..feb17f5 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -217,6 +217,7 @@
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.ref.WeakReference;
+import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
@@ -2721,6 +2722,10 @@
// Execute enqueued actions on every traversal in case a detached view enqueued an action
getRunQueue().executeActions(mAttachInfo.mHandler);
+ if (mApplyInsetsRequested && !(mWillMove || mWillResize)) {
+ dispatchApplyInsets(host);
+ }
+
boolean layoutRequested = mLayoutRequested && (!mStopped || mReportNextDraw);
if (layoutRequested) {
@@ -2785,18 +2790,6 @@
}
}
- if (mApplyInsetsRequested && !(mWillMove || mWillResize)) {
- dispatchApplyInsets(host);
- if (mLayoutRequested) {
- // Short-circuit catching a new layout request here, so
- // we don't need to go through two layout passes when things
- // change due to fitting system windows, which can happen a lot.
- windowSizeMayChange |= measureHierarchy(host, lp,
- mView.getContext().getResources(),
- desiredWindowWidth, desiredWindowHeight);
- }
- }
-
if (layoutRequested) {
// Clear this now, so that if anything requests a layout in the
// rest of this function we will catch it and re-run a full
@@ -3693,7 +3686,7 @@
return current;
}
- final Queue<AccessibilityNodeInfo> fringe = new LinkedList<>();
+ final Queue<AccessibilityNodeInfo> fringe = new ArrayDeque<>();
fringe.offer(current);
while (!fringe.isEmpty()) {
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index cd8dd86..7e16531 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -592,6 +592,11 @@
/**
* 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/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index 07b7a18..6853278 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -46,11 +46,11 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
+import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
-import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.atomic.AtomicInteger;
@@ -1166,7 +1166,7 @@
+ connectionIdWaitingForPrefetchResultCopy + ";Result: " + infos,
Binder.getCallingUid(),
Arrays.asList(Thread.currentThread().getStackTrace()),
- new HashSet<String>(Arrays.asList("getStackTrace")),
+ new HashSet<>(Collections.singletonList("getStackTrace")),
FLAGS_ACCESSIBILITY_INTERACTION_CONNECTION_CALLBACK);
}
} else if (DEBUG) {
@@ -1348,7 +1348,7 @@
}
// Check for duplicates.
HashSet<AccessibilityNodeInfo> seen = new HashSet<>();
- Queue<AccessibilityNodeInfo> fringe = new LinkedList<>();
+ Queue<AccessibilityNodeInfo> fringe = new ArrayDeque<>();
fringe.add(root);
while (!fringe.isEmpty()) {
AccessibilityNodeInfo current = fringe.poll();
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index b7994db..a8cc114 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -58,6 +58,7 @@
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.provider.DeviceConfig;
import android.service.autofill.AutofillService;
import android.service.autofill.FillCallback;
import android.service.autofill.FillEventHistory;
@@ -491,6 +492,15 @@
public static final String DEVICE_CONFIG_AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES =
"compat_mode_allowed_packages";
+ /**
+ * Sets the fill dialog feature enabled or not.
+ *
+ * @hide
+ */
+ @TestApi
+ public static final String DEVICE_CONFIG_AUTOFILL_DIALOG_ENABLED =
+ "autofill_dialog_enabled";
+
/** @hide */
public static final int RESULT_OK = 0;
/** @hide */
@@ -539,7 +549,7 @@
*/
public static final int NO_SESSION = Integer.MAX_VALUE;
- private static final boolean HAS_FILL_DIALOG_UI_FEATURE = false;
+ private static final boolean HAS_FILL_DIALOG_UI_FEATURE_DEFAULT = false;
private final IAutoFillManager mService;
@@ -655,6 +665,8 @@
@Nullable private List<AutofillId> mFillDialogTriggerIds;
+ private final boolean mIsFillDialogEnabled;
+
/** @hide */
public interface AutofillClient {
/**
@@ -795,6 +807,14 @@
mIsFillRequested = false;
mRequireAutofill = false;
+ mIsFillDialogEnabled = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_AUTOFILL,
+ DEVICE_CONFIG_AUTOFILL_DIALOG_ENABLED,
+ HAS_FILL_DIALOG_UI_FEATURE_DEFAULT);
+ if (sDebug) {
+ Log.d(TAG, "Fill dialog is enabled:" + mIsFillDialogEnabled);
+ }
+
if (mOptions != null) {
sDebug = (mOptions.loggingLevel & FLAG_ADD_CLIENT_DEBUG) != 0;
sVerbose = (mOptions.loggingLevel & FLAG_ADD_CLIENT_VERBOSE) != 0;
@@ -1081,7 +1101,7 @@
}
private boolean hasFillDialogUiFeature() {
- return HAS_FILL_DIALOG_UI_FEATURE;
+ return mIsFillDialogEnabled;
}
/**
@@ -3012,6 +3032,7 @@
}
pw.print(pfx); pw.print("compat mode enabled: ");
synchronized (mLock) {
+ pw.print(pfx); pw.print("fill dialog enabled: "); pw.println(mIsFillDialogEnabled);
if (mCompatibilityBridge != null) {
final String pfx2 = pfx + " ";
pw.println("true");
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 2717463..017b8aa 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -46,6 +46,8 @@
import android.annotation.TestApi;
import android.annotation.UserIdInt;
import android.app.ActivityThread;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -356,6 +358,21 @@
/** @hide */
public static final int SHOW_IM_PICKER_MODE_EXCLUDE_AUXILIARY_SUBTYPES = 2;
+ /**
+ * Clear {@link #SHOW_FORCED} flag when the next IME focused application changed.
+ *
+ * <p>
+ * Note that when this flag enabled in server side, {@link #SHOW_FORCED} will no longer
+ * affect the next focused application to keep showing IME, in case of unexpected IME visible
+ * when the next focused app isn't be the IME requester. </p>
+ *
+ * @hide
+ */
+ @TestApi
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
+ public static final long CLEAR_SHOW_FORCED_FLAG_WHEN_LEAVING = 214016041L; // This is a bug id.
+
@UnsupportedAppUsage
final IInputMethodManager mService;
final Looper mMainLooper;
@@ -1646,7 +1663,14 @@
* Flag for {@link #showSoftInput} to indicate that the user has forced
* the input method open (such as by long-pressing menu) so it should
* not be closed until they explicitly do so.
+ *
+ * @deprecated Use {@link #showSoftInput} without this flag instead. Using this flag can lead
+ * to the soft input remaining visible even when the calling application is closed. The
+ * use of this flag can make the soft input remains visible globally. Starting in
+ * {@link Build.VERSION_CODES#TIRAMISU Android T}, this flag only has an effect while the
+ * caller is currently focused.
*/
+ @Deprecated
public static final int SHOW_FORCED = 0x0002;
/**
diff --git a/core/java/android/view/textservice/SpellCheckerSession.java b/core/java/android/view/textservice/SpellCheckerSession.java
index 6cfb938..5d9f4f6 100644
--- a/core/java/android/view/textservice/SpellCheckerSession.java
+++ b/core/java/android/view/textservice/SpellCheckerSession.java
@@ -39,7 +39,7 @@
import dalvik.system.CloseGuard;
-import java.util.LinkedList;
+import java.util.ArrayDeque;
import java.util.Locale;
import java.util.Queue;
import java.util.concurrent.Executor;
@@ -245,7 +245,7 @@
}
}
- private final Queue<SpellCheckerParams> mPendingTasks = new LinkedList<>();
+ private final Queue<SpellCheckerParams> mPendingTasks = new ArrayDeque<>();
@GuardedBy("SpellCheckerSessionListenerImpl.this")
private SpellCheckerSession mSpellCheckerSession;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 3dfb4a5..c207af5 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -12774,7 +12774,9 @@
/**
* Called when a context menu option for the text view is selected. Currently
* this will be one of {@link android.R.id#selectAll}, {@link android.R.id#cut},
- * {@link android.R.id#copy}, {@link android.R.id#paste} or {@link android.R.id#shareText}.
+ * {@link android.R.id#copy}, {@link android.R.id#paste},
+ * {@link android.R.id#pasteAsPlainText} (starting at API level 23) or
+ * {@link android.R.id#shareText}.
*
* @return true if the context menu item action was performed.
*/
@@ -12965,6 +12967,7 @@
* method. The default actions can also be removed from the menu using
* {@link android.view.Menu#removeItem(int)} and passing {@link android.R.id#selectAll},
* {@link android.R.id#cut}, {@link android.R.id#copy}, {@link android.R.id#paste},
+ * {@link android.R.id#pasteAsPlainText} (starting at API level 23),
* {@link android.R.id#replaceText} or {@link android.R.id#shareText} ids as parameters.
*
* <p>Returning false from
@@ -13003,7 +13006,8 @@
* {@link android.view.ActionMode.Callback#onPrepareActionMode(android.view.ActionMode,
* android.view.Menu)} method. The default actions can also be removed from the menu using
* {@link android.view.Menu#removeItem(int)} and passing {@link android.R.id#selectAll},
- * {@link android.R.id#paste} or {@link android.R.id#replaceText} ids as parameters.</p>
+ * {@link android.R.id#paste}, {@link android.R.id#pasteAsPlainText} (starting at API
+ * level 23) or {@link android.R.id#replaceText} ids as parameters.</p>
*
* <p>Returning false from
* {@link android.view.ActionMode.Callback#onCreateActionMode(android.view.ActionMode,
diff --git a/core/java/android/widget/inline/InlineContentView.java b/core/java/android/widget/inline/InlineContentView.java
index 9712311..e4f483a 100644
--- a/core/java/android/widget/inline/InlineContentView.java
+++ b/core/java/android/widget/inline/InlineContentView.java
@@ -230,8 +230,9 @@
int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
mSurfaceView = new SurfaceView(context, attrs, defStyleAttr, defStyleRes) {
+ // b/219807628
@Override
- protected void onSetSurfacePositionAndScaleRT(
+ protected void onSetSurfacePositionAndScale(
@NonNull SurfaceControl.Transaction transaction,
@NonNull SurfaceControl surface, int positionLeft, int positionTop,
float postScaleX, float postScaleY) {
@@ -248,7 +249,7 @@
postScaleX = InlineContentView.this.getScaleX();
postScaleY = InlineContentView.this.getScaleY();
- super.onSetSurfacePositionAndScaleRT(transaction, surface, positionLeft,
+ super.onSetSurfacePositionAndScale(transaction, surface, positionLeft,
positionTop, postScaleX, postScaleY);
}
};
diff --git a/core/java/android/window/ProxyOnBackInvokedDispatcher.java b/core/java/android/window/ProxyOnBackInvokedDispatcher.java
index 4de977a..cdbd078 100644
--- a/core/java/android/window/ProxyOnBackInvokedDispatcher.java
+++ b/core/java/android/window/ProxyOnBackInvokedDispatcher.java
@@ -81,6 +81,10 @@
}
synchronized (mLock) {
mCallbacks.removeIf((p) -> p.first.equals(callback));
+ if (mActualDispatcherOwner != null) {
+ mActualDispatcherOwner.getOnBackInvokedDispatcher().unregisterOnBackInvokedCallback(
+ callback);
+ }
}
}
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java
index 4745220e..346aa33 100644
--- a/core/java/android/window/WindowContainerTransaction.java
+++ b/core/java/android/window/WindowContainerTransaction.java
@@ -571,6 +571,24 @@
}
/**
+ * If `container` was brought to front as a transient-launch (eg. recents), this will reorder
+ * the container back to where it was prior to the transient-launch. This way if a transient
+ * launch is "aborted", the z-ordering of containers in WM should be restored to before the
+ * launch.
+ * @hide
+ */
+ @NonNull
+ public WindowContainerTransaction restoreTransientOrder(
+ @NonNull WindowContainerToken container) {
+ final HierarchyOp hierarchyOp =
+ new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_RESTORE_TRANSIENT_ORDER)
+ .setContainer(container.asBinder())
+ .build();
+ mHierarchyOps.add(hierarchyOp);
+ return this;
+ }
+
+ /**
* When this {@link WindowContainerTransaction} failed to finish on the server side, it will
* trigger callback with this {@param errorCallbackToken}.
* @param errorCallbackToken client provided token that will be passed back as parameter in
@@ -974,6 +992,7 @@
public static final int HIERARCHY_OP_TYPE_PENDING_INTENT = 12;
public static final int HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS = 13;
public static final int HIERARCHY_OP_TYPE_START_SHORTCUT = 14;
+ public static final int HIERARCHY_OP_TYPE_RESTORE_TRANSIENT_ORDER = 15;
// The following key(s) are for use with mLaunchOptions:
// When launching a task (eg. from recents), this is the taskId to be launched.
diff --git a/core/java/com/android/internal/app/MediaRouteChooserDialog.java b/core/java/com/android/internal/app/MediaRouteChooserDialog.java
index 7108d14..23d966fd 100644
--- a/core/java/com/android/internal/app/MediaRouteChooserDialog.java
+++ b/core/java/com/android/internal/app/MediaRouteChooserDialog.java
@@ -16,25 +16,26 @@
package com.android.internal.app;
-import com.android.internal.R;
-
-import android.app.Dialog;
+import android.app.AlertDialog;
import android.content.Context;
import android.media.MediaRouter;
import android.media.MediaRouter.RouteInfo;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.TypedValue;
+import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.view.Window;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
+import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
+import com.android.internal.R;
+
import java.util.Comparator;
/**
@@ -48,9 +49,10 @@
*
* TODO: Move this back into the API, as in the support library media router.
*/
-public class MediaRouteChooserDialog extends Dialog {
+public class MediaRouteChooserDialog extends AlertDialog {
private final MediaRouter mRouter;
private final MediaRouterCallback mCallback;
+ private final boolean mShowProgressBarWhenEmpty;
private int mRouteTypes;
private View.OnClickListener mExtendedSettingsClickListener;
@@ -60,10 +62,15 @@
private boolean mAttachedToWindow;
public MediaRouteChooserDialog(Context context, int theme) {
+ this(context, theme, true);
+ }
+
+ public MediaRouteChooserDialog(Context context, int theme, boolean showProgressBarWhenEmpty) {
super(context, theme);
mRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
mCallback = new MediaRouterCallback();
+ mShowProgressBarWhenEmpty = showProgressBarWhenEmpty;
}
/**
@@ -120,28 +127,38 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
+ // Note: setView must be called before super.onCreate().
+ setView(LayoutInflater.from(getContext()).inflate(R.layout.media_route_chooser_dialog,
+ null));
- getWindow().requestFeature(Window.FEATURE_LEFT_ICON);
-
- setContentView(R.layout.media_route_chooser_dialog);
setTitle(mRouteTypes == MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY
? R.string.media_route_chooser_title_for_remote_display
: R.string.media_route_chooser_title);
- // Must be called after setContentView.
- getWindow().setFeatureDrawableResource(Window.FEATURE_LEFT_ICON,
- isLightTheme(getContext()) ? R.drawable.ic_media_route_off_holo_light
- : R.drawable.ic_media_route_off_holo_dark);
+ setIcon(isLightTheme(getContext()) ? R.drawable.ic_media_route_off_holo_light
+ : R.drawable.ic_media_route_off_holo_dark);
+ super.onCreate(savedInstanceState);
+
+ View emptyView = findViewById(android.R.id.empty);
mAdapter = new RouteAdapter(getContext());
- mListView = (ListView)findViewById(R.id.media_route_list);
+ mListView = (ListView) findViewById(R.id.media_route_list);
mListView.setAdapter(mAdapter);
mListView.setOnItemClickListener(mAdapter);
- mListView.setEmptyView(findViewById(android.R.id.empty));
+ mListView.setEmptyView(emptyView);
- mExtendedSettingsButton = (Button)findViewById(R.id.media_route_extended_settings_button);
+ mExtendedSettingsButton = (Button) findViewById(R.id.media_route_extended_settings_button);
updateExtendedSettingsButton();
+
+ if (!mShowProgressBarWhenEmpty) {
+ findViewById(R.id.media_route_progress_bar).setVisibility(View.GONE);
+
+ // Center the empty view when the progress bar is not shown.
+ LinearLayout.LayoutParams params =
+ (LinearLayout.LayoutParams) emptyView.getLayoutParams();
+ params.gravity = Gravity.CENTER;
+ emptyView.setLayoutParams(params);
+ }
}
private void updateExtendedSettingsButton() {
diff --git a/core/java/com/android/internal/app/MediaRouteDialogPresenter.java b/core/java/com/android/internal/app/MediaRouteDialogPresenter.java
index bb2d7fa..5628b7e 100644
--- a/core/java/com/android/internal/app/MediaRouteDialogPresenter.java
+++ b/core/java/com/android/internal/app/MediaRouteDialogPresenter.java
@@ -66,24 +66,37 @@
}
}
+ /** Create a media route dialog as appropriate. */
public static Dialog createDialog(Context context,
int routeTypes, View.OnClickListener extendedSettingsClickListener) {
- final MediaRouter router = (MediaRouter)context.getSystemService(
- Context.MEDIA_ROUTER_SERVICE);
-
int theme = MediaRouteChooserDialog.isLightTheme(context)
? android.R.style.Theme_DeviceDefault_Light_Dialog
: android.R.style.Theme_DeviceDefault_Dialog;
+ return createDialog(context, routeTypes, extendedSettingsClickListener, theme);
+ }
+
+ /** Create a media route dialog as appropriate. */
+ public static Dialog createDialog(Context context,
+ int routeTypes, View.OnClickListener extendedSettingsClickListener, int theme) {
+ return createDialog(context, routeTypes, extendedSettingsClickListener, theme,
+ true /* showProgressBarWhenEmpty */);
+ }
+
+ /** Create a media route dialog as appropriate. */
+ public static Dialog createDialog(Context context, int routeTypes,
+ View.OnClickListener extendedSettingsClickListener, int theme,
+ boolean showProgressBarWhenEmpty) {
+ final MediaRouter router = context.getSystemService(MediaRouter.class);
MediaRouter.RouteInfo route = router.getSelectedRoute();
if (route.isDefault() || !route.matchesTypes(routeTypes)) {
- final MediaRouteChooserDialog d = new MediaRouteChooserDialog(context, theme);
+ final MediaRouteChooserDialog d = new MediaRouteChooserDialog(context, theme,
+ showProgressBarWhenEmpty);
d.setRouteTypes(routeTypes);
d.setExtendedSettingsClickListener(extendedSettingsClickListener);
return d;
} else {
- MediaRouteControllerDialog d = new MediaRouteControllerDialog(context, theme);
- return d;
+ return new MediaRouteControllerDialog(context, theme);
}
}
}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index cdb69e5..e336e96 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -33,7 +33,6 @@
import android.annotation.UiThread;
import android.app.Activity;
import android.app.ActivityManager;
-import android.app.ActivityTaskManager;
import android.app.ActivityThread;
import android.app.VoiceInteractor.PickOptionRequest;
import android.app.VoiceInteractor.PickOptionRequest.Option;
@@ -54,13 +53,11 @@
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.content.res.Configuration;
-import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Insets;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
-import android.os.IBinder;
import android.os.PatternMatcher;
import android.os.RemoteException;
import android.os.StrictMode;
@@ -1464,36 +1461,9 @@
public boolean startAsCallerImpl(Intent intent, Bundle options, boolean ignoreTargetSecurity,
int userId) {
- // Pass intent to delegate chooser activity with permission token.
- // TODO: This should move to a trampoline Activity in the system when the ChooserActivity
- // moves into systemui
- try {
- // TODO: Once this is a small springboard activity, it can move off the UI process
- // and we can move the request method to ActivityManagerInternal.
- final Intent chooserIntent = new Intent();
- final ComponentName delegateActivity = ComponentName.unflattenFromString(
- Resources.getSystem().getString(R.string.config_chooserActivity));
- IBinder permissionToken = ActivityTaskManager.getService()
- .requestStartActivityPermissionToken(delegateActivity);
- chooserIntent.setClassName(delegateActivity.getPackageName(),
- delegateActivity.getClassName());
- chooserIntent.putExtra(ActivityTaskManager.EXTRA_PERMISSION_TOKEN, permissionToken);
-
- // TODO: These extras will change as chooser activity moves into systemui
- chooserIntent.putExtra(Intent.EXTRA_INTENT, intent);
- chooserIntent.putExtra(ActivityTaskManager.EXTRA_OPTIONS, options);
- chooserIntent.putExtra(ActivityTaskManager.EXTRA_IGNORE_TARGET_SECURITY,
- ignoreTargetSecurity);
- chooserIntent.putExtra(Intent.EXTRA_USER_ID, userId);
- chooserIntent.addFlags(Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
-
- // Don't close until the delegate finishes, or the token will be invalidated.
- mAwaitingDelegateResponse = true;
-
- startActivityForResult(chooserIntent, REQUEST_CODE_RETURN_FROM_DELEGATE_CHOOSER);
- } catch (RemoteException e) {
- Log.e(TAG, e.toString());
- }
+ // Note: this method will be overridden in the delegate implementation to use the passed-in
+ // permission token.
+ startActivityAsCaller(intent, options, null, false, userId);
return true;
}
diff --git a/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java b/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java
index 301de2d..dc53e77 100644
--- a/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java
+++ b/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java
@@ -30,11 +30,9 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.os.UserHandle;
-import android.provider.DeviceConfig;
import com.android.internal.app.ResolverActivity;
import com.android.internal.app.ResolverListAdapter.ResolveInfoPresentationGetter;
-import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import java.util.ArrayList;
import java.util.Arrays;
@@ -45,11 +43,6 @@
* resolve it to an activity.
*/
public class DisplayResolveInfo implements TargetInfo, Parcelable {
- private final boolean mEnableChooserDelegate =
- DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
- SystemUiDeviceConfigFlags.USE_DELEGATE_CHOOSER,
- false);
-
private final ResolveInfo mResolveInfo;
private CharSequence mDisplayLabel;
private Drawable mDisplayIcon;
@@ -180,12 +173,9 @@
@Override
public boolean startAsCaller(ResolverActivity activity, Bundle options, int userId) {
- if (mEnableChooserDelegate) {
- return activity.startAsCallerImpl(mResolvedIntent, options, false, userId);
- } else {
- activity.startActivityAsCaller(mResolvedIntent, options, null, false, userId);
- return true;
- }
+ // TODO: if the start-as-caller API no longer requires a permission token, this can go back
+ // to inlining the real activity-start call, and we can remove startAsCallerImpl.
+ return activity.startAsCallerImpl(mResolvedIntent, options, false, userId);
}
@Override
diff --git a/core/java/com/android/internal/os/SystemServerClassLoaderFactory.java b/core/java/com/android/internal/os/SystemServerClassLoaderFactory.java
index 615e4b79..a03bac4 100644
--- a/core/java/com/android/internal/os/SystemServerClassLoaderFactory.java
+++ b/core/java/com/android/internal/os/SystemServerClassLoaderFactory.java
@@ -29,22 +29,66 @@
private static final ArrayMap<String, PathClassLoader> sLoadedPaths = new ArrayMap<>();
/**
- * Creates and caches a ClassLoader for the jar at the given path, or returns a cached
- * ClassLoader if it exists.
+ * Creates and caches a ClassLoader for the jar at the given path.
+ *
+ * This method should only be called by ZygoteInit to prefetch jars. For other users, use
+ * {@link getOrCreateClassLoader} instead.
*
* The parent class loader should always be the system server class loader. Changing it has
* implications that require discussion with the mainline team.
*
* @hide for internal use only
*/
- public static PathClassLoader getOrCreateClassLoader(String path, ClassLoader parent) {
- PathClassLoader pathClassLoader = sLoadedPaths.get(path);
- if (pathClassLoader == null) {
- pathClassLoader = (PathClassLoader) ClassLoaderFactory.createClassLoader(
- path, /*librarySearchPath=*/null, /*libraryPermittedPath=*/null, parent,
- Build.VERSION.SDK_INT, /*isNamespaceShared=*/true , /*classLoaderName=*/null);
- sLoadedPaths.put(path, pathClassLoader);
+ /* package */ static PathClassLoader createClassLoader(String path, ClassLoader parent) {
+ if (sLoadedPaths.containsKey(path)) {
+ throw new IllegalStateException("A ClassLoader for " + path + " already exists");
}
+ PathClassLoader pathClassLoader = (PathClassLoader) ClassLoaderFactory.createClassLoader(
+ path, /*librarySearchPath=*/null, /*libraryPermittedPath=*/null, parent,
+ Build.VERSION.SDK_INT, /*isNamespaceShared=*/true , /*classLoaderName=*/null);
+ sLoadedPaths.put(path, pathClassLoader);
return pathClassLoader;
}
+
+ /**
+ * Returns a cached ClassLoader to be used at runtime for the jar at the given path. Or, creates
+ * one if it is not prefetched and is allowed to be created at runtime.
+ *
+ * The parent class loader should always be the system server class loader. Changing it has
+ * implications that require discussion with the mainline team.
+ *
+ * @hide for internal use only
+ */
+ public static PathClassLoader getOrCreateClassLoader(
+ String path, ClassLoader parent, boolean isTestOnly) {
+ PathClassLoader pathClassLoader = sLoadedPaths.get(path);
+ if (pathClassLoader != null) {
+ return pathClassLoader;
+ }
+ if (!allowClassLoaderCreation(path, isTestOnly)) {
+ throw new RuntimeException("Creating a ClassLoader from " + path + " is not allowed. "
+ + "Please make sure that the jar is listed in "
+ + "`PRODUCT_APEX_STANDALONE_SYSTEM_SERVER_JARS` in the Makefile and added as a "
+ + "`standalone_contents` of a `systemserverclasspath_fragment` in "
+ + "`Android.bp`.");
+ }
+ return createClassLoader(path, parent);
+ }
+
+ /**
+ * Returns whether a class loader for the jar is allowed to be created at runtime.
+ */
+ private static boolean allowClassLoaderCreation(String path, boolean isTestOnly) {
+ // Currently, we only enforce prefetching for APEX jars.
+ if (!path.startsWith("/apex/")) {
+ return true;
+ }
+ // APEXes for testing only are okay to ignore.
+ if (isTestOnly) {
+ return true;
+ }
+ return false;
+ }
+
+
}
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 3d24aa2d..ca1ae19 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -586,7 +586,7 @@
}
for (String jar : envStr.split(":")) {
try {
- SystemServerClassLoaderFactory.getOrCreateClassLoader(
+ SystemServerClassLoaderFactory.createClassLoader(
jar, getOrCreateSystemServerClassLoader());
} catch (Error e) {
// We don't want the process to crash for this error because prefetching is just an
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/LauncherEventUtil.java b/core/java/com/android/internal/policy/IKeyguardLockedStateListener.aidl
similarity index 65%
rename from packages/SystemUI/shared/src/com/android/systemui/shared/system/LauncherEventUtil.java
rename to core/java/com/android/internal/policy/IKeyguardLockedStateListener.aidl
index a51d668..ee50219 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/LauncherEventUtil.java
+++ b/core/java/com/android/internal/policy/IKeyguardLockedStateListener.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -11,14 +11,11 @@
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
*/
-package com.android.systemui.shared.system;
+package com.android.internal.policy;
-public class LauncherEventUtil {
-
- // Constants for the Action
- public static final int VISIBLE = 0;
- public static final int DISMISS = 1;
-}
+oneway interface IKeyguardLockedStateListener {
+ void onKeyguardLockedStateChanged(boolean isKeyguardLocked);
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 9e70392..dcc1a76 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -175,20 +175,20 @@
void cancelRequestAddTile(in String packageName);
/**
- * Overrides the navigation bar mode.
+ * Sets the navigation bar mode.
*
- * @param navBarModeOverride the mode of the navigation bar override to be set.
+ * @param navBarMode the mode of the navigation bar to be set.
*
* @hide
*/
- void setNavBarModeOverride(int navBarModeOverride);
+ void setNavBarMode(int navBarMode);
/**
- * Gets the navigation bar mode override.
+ * Gets the navigation bar mode.
*
* @hide
*/
- int getNavBarModeOverride();
+ int getNavBarMode();
/**
* Register a listener for certain sessions. Each session may be guarded by its own permission.
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index 9bdcddf..1fd0410 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -888,6 +888,15 @@
}
}
+ /**
+ * Returns the {@code i}-th item in {@code items}, if it exists and {@code items} is not {@code
+ * null}, otherwise returns {@code null}.
+ */
+ @Nullable
+ public static <T> T getOrNull(@Nullable T[] items, int i) {
+ return (items != null && items.length > i) ? items[i] : null;
+ }
+
public static @Nullable <T> T firstOrNull(T[] items) {
return items.length > 0 ? items[0] : null;
}
diff --git a/core/jni/android_graphics_BLASTBufferQueue.cpp b/core/jni/android_graphics_BLASTBufferQueue.cpp
index 4f13a9c..3be0eb8 100644
--- a/core/jni/android_graphics_BLASTBufferQueue.cpp
+++ b/core/jni/android_graphics_BLASTBufferQueue.cpp
@@ -35,9 +35,10 @@
jmethodID ctor;
} gTransactionClassInfo;
-static jlong nativeCreate(JNIEnv* env, jclass clazz, jstring jName) {
+static jlong nativeCreate(JNIEnv* env, jclass clazz, jstring jName,
+ jboolean updateDestinationFrame) {
ScopedUtfChars name(env, jName);
- sp<BLASTBufferQueue> queue = new BLASTBufferQueue(name.c_str());
+ sp<BLASTBufferQueue> queue = new BLASTBufferQueue(name.c_str(), updateDestinationFrame);
queue->incStrong((void*)nativeCreate);
return reinterpret_cast<jlong>(queue.get());
}
@@ -62,11 +63,9 @@
}
static void nativeUpdate(JNIEnv* env, jclass clazz, jlong ptr, jlong surfaceControl, jlong width,
- jlong height, jint format, jlong transactionPtr) {
+ jlong height, jint format) {
sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
- auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionPtr);
- queue->update(reinterpret_cast<SurfaceControl*>(surfaceControl), width, height, format,
- transaction);
+ queue->update(reinterpret_cast<SurfaceControl*>(surfaceControl), width, height, format);
}
static void nativeMergeWithNextTransaction(JNIEnv*, jclass clazz, jlong ptr, jlong transactionPtr,
@@ -102,11 +101,11 @@
static const JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
// clang-format off
- {"nativeCreate", "(Ljava/lang/String;)J", (void*)nativeCreate},
+ {"nativeCreate", "(Ljava/lang/String;Z)J", (void*)nativeCreate},
{"nativeGetSurface", "(JZ)Landroid/view/Surface;", (void*)nativeGetSurface},
{"nativeDestroy", "(J)V", (void*)nativeDestroy},
{"nativeSetSyncTransaction", "(JJZ)V", (void*)nativeSetSyncTransaction},
- {"nativeUpdate", "(JJJJIJ)V", (void*)nativeUpdate},
+ {"nativeUpdate", "(JJJJI)V", (void*)nativeUpdate},
{"nativeMergeWithNextTransaction", "(JJJ)V", (void*)nativeMergeWithNextTransaction},
{"nativeGetLastAcquiredFrameNum", "(J)J", (void*)nativeGetLastAcquiredFrameNum},
{"nativeApplyPendingTransactions", "(JJ)V", (void*)nativeApplyPendingTransactions},
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index fb5b5ff..68025a8 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) {
@@ -961,6 +962,14 @@
transaction->sanitize();
}
+static void nativeSetDestinationFrame(JNIEnv* env, jclass clazz, jlong transactionObj,
+ jlong nativeObject, jint l, jint t, jint r, jint b) {
+ auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+ SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl*>(nativeObject);
+ Rect crop(l, t, r, b);
+ transaction->setDestinationFrame(ctrl, crop);
+}
+
static jlongArray nativeGetPhysicalDisplayIds(JNIEnv* env, jclass clazz) {
const auto displayIds = SurfaceComposerClient::getPhysicalDisplayIds();
jlongArray array = env->NewLongArray(displayIds.size());
@@ -1833,6 +1842,15 @@
return reinterpret_cast<jlong>(surfaceControl->getHandle().get());
}
+static void nativeRemoveCurrentInputFocus(JNIEnv* env, jclass clazz, jlong transactionObj,
+ jint displayId) {
+ auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+ FocusRequest request;
+ request.timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
+ request.displayId = displayId;
+ transaction->setFocusedWindow(request);
+}
+
static void nativeSetFocusedWindow(JNIEnv* env, jclass clazz, jlong transactionObj,
jobject toTokenObj, jstring windowNameJstr,
jobject focusedTokenObj, jstring focusedWindowNameJstr,
@@ -2167,6 +2185,8 @@
(void*)nativeSetFixedTransformHint},
{"nativeSetFocusedWindow", "(JLandroid/os/IBinder;Ljava/lang/String;Landroid/os/IBinder;Ljava/lang/String;I)V",
(void*)nativeSetFocusedWindow},
+ {"nativeRemoveCurrentInputFocus", "(JI)V",
+ (void*)nativeRemoveCurrentInputFocus},
{"nativeSetFrameTimelineVsync", "(JJ)V",
(void*)nativeSetFrameTimelineVsync },
{"nativeAddJankDataListener", "(JJ)V",
@@ -2190,7 +2210,9 @@
{"nativeAddTransactionCommittedListener", "(JLandroid/view/SurfaceControl$TransactionCommittedListener;)V",
(void*) nativeAddTransactionCommittedListener },
{"nativeSanitize", "(J)V",
- (void*) nativeSanitize }
+ (void*) nativeSanitize },
+ {"nativeSetDestinationFrame", "(JJIIII)V",
+ (void*)nativeSetDestinationFrame },
// clang-format on
};
diff --git a/core/proto/android/hardware/sensorprivacy.proto b/core/proto/android/hardware/sensorprivacy.proto
index 97870a1..9359528 100644
--- a/core/proto/android/hardware/sensorprivacy.proto
+++ b/core/proto/android/hardware/sensorprivacy.proto
@@ -128,7 +128,7 @@
DIALOG = 3;
SHELL = 4;
OTHER = 5;
- SAFETY_HUB = 6;
+ SAFETY_CENTER = 6;
}
// Source for which sensor privacy was toggled.
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index c33b7c9..e8f7b93 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -382,6 +382,7 @@
optional bool in_size_compat_mode = 32;
optional float min_aspect_ratio = 33;
optional bool provides_max_bounds = 34;
+ optional bool enable_recents_screenshot = 35;
}
/* represents WindowToken */
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index d4c03e4..58a3bb4 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4119,6 +4119,13 @@
<permission android:name="android.permission.MANAGE_HOTWORD_DETECTION"
android:protectionLevel="internal|preinstalled" />
+ <!-- Allows an application to subscribe to keyguard locked (i.e., showing) state.
+ <p>Protection level: internal|role
+ <p>Intended for use by ROLE_ASSISTANT only.
+ -->
+ <permission android:name="android.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE"
+ android:protectionLevel="internal|role"/>
+
<!-- Must be required by a {@link android.service.autofill.AutofillService},
to ensure that only the system can bind to it.
<p>Protection level: signature
@@ -6912,6 +6919,10 @@
android:permission="android.permission.BIND_JOB_SERVICE">
</service>
+ <service android:name="com.android.server.appsearch.contactsindexer.ContactsIndexerMaintenanceService"
+ android:permission="android.permission.BIND_JOB_SERVICE">
+ </service>
+
<service android:name="com.android.server.pm.PackageManagerShellCommandDataLoader"
android:exported="false">
<intent-filter>
diff --git a/core/res/res/layout/media_route_chooser_dialog.xml b/core/res/res/layout/media_route_chooser_dialog.xml
index cd1c74f..bf73f4b 100644
--- a/core/res/res/layout/media_route_chooser_dialog.xml
+++ b/core/res/res/layout/media_route_chooser_dialog.xml
@@ -28,20 +28,21 @@
<!-- Content to show when list is empty. -->
<LinearLayout android:id="@android:id/empty"
- android:layout_width="match_parent"
- android:layout_height="64dp"
- android:orientation="horizontal"
- android:paddingLeft="16dp"
- android:paddingRight="16dp"
- android:visibility="gone">
- <ProgressBar android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center" />
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:visibility="gone">
+ <ProgressBar android:id="@+id/media_route_progress_bar"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center" />
<TextView android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:paddingStart="16dp"
- android:text="@string/media_route_chooser_searching" />
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:paddingStart="16dp"
+ android:text="@string/media_route_chooser_searching" />
</LinearLayout>
<!-- Settings button. -->
diff --git a/core/res/res/values-television/config.xml b/core/res/res/values-television/config.xml
index 0db08fb..88bf18c 100644
--- a/core/res/res/values-television/config.xml
+++ b/core/res/res/values-television/config.xml
@@ -24,19 +24,6 @@
<!-- Flags enabling default window features. See Window.java -->
<bool name="config_defaultWindowFeatureOptionsPanel">false</bool>
- <!-- The percentage of the screen width to use for the default width or height of
- picture-in-picture windows. Regardless of the percent set here, calculated size will never
- be smaller than @dimen/default_minimal_size_pip_resizable_task. -->
- <item name="config_pictureInPictureDefaultSizePercent" format="float" type="dimen">0.2</item>
-
- <!-- Default insets [LEFT/RIGHTxTOP/BOTTOM] from the screen edge for picture-in-picture windows.
- These values are in DPs and will be converted to pixel sizes internally. -->
- <string translatable="false" name="config_defaultPictureInPictureScreenEdgeInsets">24x24</string>
-
- <!-- The default gravity for the picture-in-picture window.
- Currently, this maps to Gravity.BOTTOM | Gravity.RIGHT -->
- <integer name="config_defaultPictureInPictureGravity">0x55</integer>
-
<!-- The maximum height of the expanded horizontal picture-in-picture window -->
<item name="config_pictureInPictureExpandedHorizontalHeight"
format="dimension" type="dimen">110dp</item>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 689d37c..da5f899 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3932,12 +3932,12 @@
<!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_INPUT_METHOD_EDITOR}. -->
<flag name="flagInputMethodEditor" value="0x0008000" />
</attr>
- <!-- Component name of an activity that allows the user to modify
- the settings for this service. This setting cannot be changed at runtime. -->
+ <!-- Fully qualified class name of an activity that allows the user to modify the settings
+ for this service. This setting cannot be changed at runtime. -->
<attr name="settingsActivity" />
- <!-- Component name of {@link android.service.quicksettings.TileService} is associated
- with this accessibility service for one to one mapping. It is used by system settings
- to remind users this accessibility service has a
+ <!-- Fully qualified class name of {@link android.service.quicksettings.TileService} is
+ associated with this accessibility service for one to one mapping. It is used by system
+ settings to remind users this accessibility service has a
{@link android.service.quicksettings.TileService}. -->
<attr name="tileService" format="string" />
<!-- Attribute whether the accessibility service wants to be able to retrieve the
@@ -4026,12 +4026,12 @@
<!-- Html description of the target of accessibility shortcut usage, availability, or
limitations (e.g. isn't supported by all apps). -->
<attr name="htmlDescription" format="reference"/>
- <!-- Component name of an activity that allows the user to modify the settings for this
- target of accessibility shortcut. -->
+ <!-- Fully qualified class name of an activity that allows the user to modify the settings
+ for this target of accessibility shortcut. -->
<attr name="settingsActivity" />
- <!-- Component name of {@link android.service.quicksettings.TileService} is associated
- with this accessibility shortcut target for one to one mapping. It is used by system
- settings to remind users this accessibility service has a
+ <!-- Fully qualified class name of {@link android.service.quicksettings.TileService} is
+ associated with this accessibility shortcut target for one to one mapping. It is used
+ by system settings to remind users this accessibility service has a
{@link android.service.quicksettings.TileService}. -->
<attr name="tileService" format="string" />
<!-- Detailed intro of the target of accessibility shortcut purpose or behavior. -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 05894d5..5ac30de 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3704,26 +3704,6 @@
snapped to any position between the first target and the last target. -->
<bool name="config_dockedStackDividerFreeSnapMode">false</bool>
- <!-- Default insets [LEFT/RIGHTxTOP/BOTTOM] from the screen edge for picture-in-picture windows.
- These values are in DPs and will be converted to pixel sizes internally. -->
- <string translatable="false" name="config_defaultPictureInPictureScreenEdgeInsets">16x16</string>
-
- <!-- The percentage of the screen width to use for the default width or height of
- picture-in-picture windows. Regardless of the percent set here, calculated size will never
- be smaller than @dimen/default_minimal_size_pip_resizable_task. -->
- <item name="config_pictureInPictureDefaultSizePercent" format="float" type="dimen">0.23</item>
-
- <!-- The default aspect ratio for picture-in-picture windows. -->
- <item name="config_pictureInPictureDefaultAspectRatio" format="float" type="dimen">1.777778</item>
-
- <!-- This is the limit for the max and min aspect ratio (1 / this value) at which the min size
- will be used instead of an adaptive size based loosely on area. -->
- <item name="config_pictureInPictureAspectRatioLimitForMinSize" format="float" type="dimen">1.777778</item>
-
- <!-- The default gravity for the picture-in-picture window.
- Currently, this maps to Gravity.BOTTOM | Gravity.RIGHT -->
- <integer name="config_defaultPictureInPictureGravity">0x55</integer>
-
<!-- The minimum aspect ratio (width/height) that is supported for picture-in-picture. Any
ratio smaller than this is considered too tall and thin to be usable. Currently, this
is the inverse of the max landscape aspect ratio (1:2.39), but this is an extremely
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 744c3dab..032d0b9 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -606,6 +606,9 @@
<!-- The padding ratio of the Accessibility icon foreground drawable -->
<item name="accessibility_icon_foreground_padding_ratio" type="dimen">21.88%</item>
+ <!-- The minimum window size of the accessibility window magnifier -->
+ <dimen name="accessibility_window_magnifier_min_size">122dp</dimen>
+
<!-- Margin around the various security views -->
<dimen name="keyguard_muliuser_selector_margin">8dp</dimen>
@@ -714,16 +717,6 @@
<!-- The default minimal size of a resizable task, in both dimensions. -->
<dimen name="default_minimal_size_resizable_task">220dp</dimen>
- <!-- The default minimal size of a PiP task, in both dimensions. -->
- <dimen name="default_minimal_size_pip_resizable_task">108dp</dimen>
-
- <!--
- The overridable minimal size of a PiP task, in both dimensions.
- Different from default_minimal_size_pip_resizable_task, this is to limit the dimension
- when the pinned stack size is overridden by app via minWidth/minHeight.
- -->
- <dimen name="overridable_minimal_size_pip_resizable_task">48dp</dimen>
-
<!-- Height of a task when in minimized mode from the top when launcher is resizable. -->
<dimen name="task_height_of_minimized_mode">80dp</dimen>
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index bccd2b6..29eb0c0 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/symbols.xml b/core/res/res/values/symbols.xml
index e7eeecc..e543034 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -408,11 +408,6 @@
<java-symbol type="array" name="config_localPrivateDisplayPorts" />
<java-symbol type="integer" name="config_defaultDisplayDefaultColorMode" />
<java-symbol type="bool" name="config_enableAppWidgetService" />
- <java-symbol type="string" name="config_defaultPictureInPictureScreenEdgeInsets" />
- <java-symbol type="dimen" name="config_pictureInPictureDefaultSizePercent" />
- <java-symbol type="dimen" name="config_pictureInPictureDefaultAspectRatio" />
- <java-symbol type="dimen" name="config_pictureInPictureAspectRatioLimitForMinSize" />
- <java-symbol type="integer" name="config_defaultPictureInPictureGravity" />
<java-symbol type="dimen" name="config_pictureInPictureMinAspectRatio" />
<java-symbol type="dimen" name="config_pictureInPictureMaxAspectRatio" />
<java-symbol type="integer" name="config_pictureInPictureMaxNumberOfActions" />
@@ -1295,6 +1290,8 @@
<java-symbol type="array" name="vendor_required_apps_managed_user" />
<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" />
@@ -1676,6 +1673,7 @@
<java-symbol type="id" name="media_route_volume_slider" />
<java-symbol type="id" name="media_route_control_frame" />
<java-symbol type="id" name="media_route_extended_settings_button" />
+ <java-symbol type="id" name="media_route_progress_bar" />
<java-symbol type="string" name="media_route_chooser_title" />
<java-symbol type="string" name="media_route_chooser_title_for_remote_display" />
<java-symbol type="string" name="media_route_controller_disconnect" />
@@ -2015,8 +2013,6 @@
<java-symbol type="id" name="replace_message" />
<java-symbol type="fraction" name="config_dimBehindFadeDuration" />
<java-symbol type="dimen" name="default_minimal_size_resizable_task" />
- <java-symbol type="dimen" name="default_minimal_size_pip_resizable_task" />
- <java-symbol type="dimen" name="overridable_minimal_size_pip_resizable_task" />
<java-symbol type="dimen" name="task_height_of_minimized_mode" />
<java-symbol type="fraction" name="config_screenAutoBrightnessDozeScaleFactor" />
<java-symbol type="bool" name="config_allowPriorityVibrationsInLowPowerMode" />
@@ -4398,6 +4394,7 @@
<java-symbol type="color" name="accessibility_focus_highlight_color" />
<!-- Width of the outline stroke used by the accessibility focus rectangle -->
<java-symbol type="dimen" name="accessibility_focus_highlight_stroke_width" />
+ <java-symbol type="dimen" name="accessibility_window_magnifier_min_size" />
<java-symbol type="bool" name="config_attachNavBarToAppDuringTransition" />
diff --git a/core/res/res/values/vendor_required_attestation_certificates.xml b/core/res/res/values/vendor_required_attestation_certificates.xml
new file mode 100644
index 0000000..ff7313e
--- /dev/null
+++ b/core/res/res/values/vendor_required_attestation_certificates.xml
@@ -0,0 +1,38 @@
+<?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.
+ */
+-->
+<resources>
+ <!-- The PEM-encoded certificates added here are used for verifying attestations.
+ The trustworthiness of the attestation depends on the root certificate of the chain.
+
+ Certificates that can be used can be retrieved from:
+ https://developer.android.com/training/articles/security-key-attestation#root_certificate.
+
+ If not already present in resource overlay, please add
+ vendor_required_attestation_certificates.xml (matching this file) in vendor overlay
+ with <item></item> of the PEM-encoded root certificates.
+ -->
+ <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/core/tests/coretests/src/android/accessibilityservice/AccessibilityShortcutInfoTest.java b/core/tests/coretests/src/android/accessibilityservice/AccessibilityShortcutInfoTest.java
index f605a00..eebc578 100644
--- a/core/tests/coretests/src/android/accessibilityservice/AccessibilityShortcutInfoTest.java
+++ b/core/tests/coretests/src/android/accessibilityservice/AccessibilityShortcutInfoTest.java
@@ -129,7 +129,7 @@
@Test
public void testTileService() {
assertThat("Tile service is not correct",
- mShortcutInfo.getTileServiceClassName(), is(TILE_SERVICE_NAME));
+ mShortcutInfo.getTileServiceName(), is(TILE_SERVICE_NAME));
}
diff --git a/core/tests/coretests/src/android/companion/virtual/audio/VirtualAudioSessionTest.java b/core/tests/coretests/src/android/companion/virtual/audio/VirtualAudioSessionTest.java
index d66cb71..0e09d56 100644
--- a/core/tests/coretests/src/android/companion/virtual/audio/VirtualAudioSessionTest.java
+++ b/core/tests/coretests/src/android/companion/virtual/audio/VirtualAudioSessionTest.java
@@ -22,6 +22,7 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
import static org.testng.Assert.assertThrows;
@@ -168,7 +169,7 @@
mVirtualAudioSession.onPlaybackConfigChanged(configs);
- verify(mCallback).onPlaybackConfigChanged(configs);
+ verify(mCallback, timeout(2000)).onPlaybackConfigChanged(configs);
}
@Test
@@ -177,6 +178,6 @@
mVirtualAudioSession.onRecordingConfigChanged(configs);
- verify(mCallback).onRecordingConfigChanged(configs);
+ verify(mCallback, timeout(2000)).onRecordingConfigChanged(configs);
}
}
diff --git a/core/tests/coretests/src/android/content/ManagedUserContentResolverTest.java b/core/tests/coretests/src/android/content/ManagedUserContentResolverTest.java
index 68d4cd4..1bc46a7 100644
--- a/core/tests/coretests/src/android/content/ManagedUserContentResolverTest.java
+++ b/core/tests/coretests/src/android/content/ManagedUserContentResolverTest.java
@@ -20,7 +20,6 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
-import android.platform.test.annotations.Presubmit;
import androidx.test.filters.LargeTest;
@@ -37,7 +36,6 @@
* Run: adb shell am instrument -e class android.content.ManagedUserContentResolverTest -w \
* com.android.frameworks.coretests/androidx.test.runner.AndroidJUnitRunner
*/
-@Presubmit
@LargeTest
public class ManagedUserContentResolverTest extends AbstractCrossUserContentResolverTest {
@Override
diff --git a/core/tests/coretests/src/android/content/SecondaryUserContentResolverTest.java b/core/tests/coretests/src/android/content/SecondaryUserContentResolverTest.java
index de4c572..dbe0278 100644
--- a/core/tests/coretests/src/android/content/SecondaryUserContentResolverTest.java
+++ b/core/tests/coretests/src/android/content/SecondaryUserContentResolverTest.java
@@ -18,7 +18,6 @@
import android.content.pm.UserInfo;
import android.os.RemoteException;
-import android.platform.test.annotations.Presubmit;
import androidx.test.filters.LargeTest;
@@ -35,7 +34,6 @@
* Run: adb shell am instrument -e class android.content.SecondaryUserContentResolverTest -w \
* com.android.frameworks.coretests/androidx.test.runner.AndroidJUnitRunner
*/
-@Presubmit
@LargeTest
public class SecondaryUserContentResolverTest extends AbstractCrossUserContentResolverTest {
@Override
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 1779655..ed89869 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -3793,6 +3793,12 @@
"group": "WM_DEBUG_REMOTE_ANIMATIONS",
"at": "com\/android\/server\/wm\/NonAppWindowAnimationAdapter.java"
},
+ "2001473656": {
+ "message": "App %s is focused, but the window is not ready. Start a transaction to remove focus from the window of non-focused apps.",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_FOCUS_LIGHT",
+ "at": "com\/android\/server\/wm\/InputMonitor.java"
+ },
"2018454757": {
"message": "WS.removeImmediately: %s Already removed...",
"level": "VERBOSE",
diff --git a/graphics/java/android/graphics/BLASTBufferQueue.java b/graphics/java/android/graphics/BLASTBufferQueue.java
index 2678c79d..369f20f 100644
--- a/graphics/java/android/graphics/BLASTBufferQueue.java
+++ b/graphics/java/android/graphics/BLASTBufferQueue.java
@@ -27,13 +27,13 @@
// Note: This field is accessed by native code.
public long mNativeObject; // BLASTBufferQueue*
- private static native long nativeCreate(String name);
+ private static native long nativeCreate(String name, boolean updateDestinationFrame);
private static native void nativeDestroy(long ptr);
private static native Surface nativeGetSurface(long ptr, boolean includeSurfaceControlHandle);
private static native void nativeSetSyncTransaction(long ptr, long transactionPtr,
boolean acquireSingleBuffer);
private static native void nativeUpdate(long ptr, long surfaceControl, long width, long height,
- int format, long transactionPtr);
+ int format);
private static native void nativeMergeWithNextTransaction(long ptr, long transactionPtr,
long frameNumber);
private static native long nativeGetLastAcquiredFrameNum(long ptr);
@@ -45,12 +45,12 @@
/** Create a new connection with the surface flinger. */
public BLASTBufferQueue(String name, SurfaceControl sc, int width, int height,
@PixelFormat.Format int format) {
- this(name);
+ this(name, false /* updateDestinationFrame */);
update(sc, width, height, format);
}
- public BLASTBufferQueue(String name) {
- mNativeObject = nativeCreate(name);
+ public BLASTBufferQueue(String name, boolean updateDestinationFrame) {
+ mNativeObject = nativeCreate(name, updateDestinationFrame);
}
public void destroy() {
@@ -101,15 +101,9 @@
* @param width The new width for the buffer.
* @param height The new height for the buffer.
* @param format The new format for the buffer.
- * @param t Adds destination frame changes to the passed in transaction.
*/
- public void update(SurfaceControl sc, int width, int height, @PixelFormat.Format int format,
- SurfaceControl.Transaction t) {
- nativeUpdate(mNativeObject, sc.mNativeObject, width, height, format, t.mNativeObject);
- }
-
public void update(SurfaceControl sc, int width, int height, @PixelFormat.Format int format) {
- nativeUpdate(mNativeObject, sc.mNativeObject, width, height, format, 0);
+ nativeUpdate(mNativeObject, sc.mNativeObject, width, height, format);
}
@Override
diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java
index 2f978fc..582488f 100644
--- a/graphics/java/android/graphics/ColorSpace.java
+++ b/graphics/java/android/graphics/ColorSpace.java
@@ -22,6 +22,10 @@
import android.annotation.Nullable;
import android.annotation.Size;
import android.annotation.SuppressAutoDoc;
+import android.annotation.SuppressLint;
+import android.hardware.DataSpace;
+import android.hardware.DataSpace.NamedDataSpace;
+import android.util.SparseIntArray;
import libcore.util.NativeAllocationRegistry;
@@ -207,6 +211,7 @@
// See static initialization block next to #get(Named)
private static final ColorSpace[] sNamedColorSpaces = new ColorSpace[Named.values().length];
+ private static final SparseIntArray sDataToColorSpaces = new SparseIntArray();
@NonNull private final String mName;
@NonNull private final Model mModel;
@@ -1389,6 +1394,47 @@
}
/**
+ * Create a {@link ColorSpace} object using a {@link android.hardware.DataSpace DataSpace}
+ * value.
+ *
+ * <p>This function maps from a dataspace to a {@link Named} ColorSpace.
+ * If no {@link Named} ColorSpace object matching the {@code dataSpace} value can be created,
+ * {@code null} will return.</p>
+ *
+ * @param dataSpace The dataspace value
+ * @return the ColorSpace object or {@code null} if no matching colorspace can be found.
+ */
+ @SuppressLint("MethodNameUnits")
+ @Nullable
+ public static ColorSpace getFromDataSpace(@NamedDataSpace int dataSpace) {
+ int index = sDataToColorSpaces.get(dataSpace, -1);
+ if (index != -1) {
+ return ColorSpace.get(index);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Retrieve the {@link android.hardware.DataSpace DataSpace} value from a {@link ColorSpace}
+ * object.
+ *
+ * <p>If this {@link ColorSpace} object has no matching {@code dataSpace} value,
+ * {@link android.hardware.DataSpace#DATASPACE_UNKNOWN DATASPACE_UNKNOWN} will return.</p>
+ *
+ * @return the dataspace value.
+ */
+ @SuppressLint("MethodNameUnits")
+ public @NamedDataSpace int getDataSpace() {
+ int index = sDataToColorSpaces.indexOfValue(getId());
+ if (index != -1) {
+ return sDataToColorSpaces.keyAt(index);
+ } else {
+ return DataSpace.DATASPACE_UNKNOWN;
+ }
+ }
+
+ /**
* <p>Returns an instance of {@link ColorSpace} identified by the specified
* name. The list of names provided in the {@link Named} enum gives access
* to a variety of common RGB color spaces.</p>
@@ -1445,6 +1491,7 @@
SRGB_TRANSFER_PARAMETERS,
Named.SRGB.ordinal()
);
+ sDataToColorSpaces.put(DataSpace.DATASPACE_SRGB, Named.SRGB.ordinal());
sNamedColorSpaces[Named.LINEAR_SRGB.ordinal()] = new ColorSpace.Rgb(
"sRGB IEC61966-2.1 (Linear)",
SRGB_PRIMARIES,
@@ -1453,6 +1500,7 @@
0.0f, 1.0f,
Named.LINEAR_SRGB.ordinal()
);
+ sDataToColorSpaces.put(DataSpace.DATASPACE_SRGB_LINEAR, Named.LINEAR_SRGB.ordinal());
sNamedColorSpaces[Named.EXTENDED_SRGB.ordinal()] = new ColorSpace.Rgb(
"scRGB-nl IEC 61966-2-2:2003",
SRGB_PRIMARIES,
@@ -1464,6 +1512,7 @@
SRGB_TRANSFER_PARAMETERS,
Named.EXTENDED_SRGB.ordinal()
);
+ sDataToColorSpaces.put(DataSpace.DATASPACE_SCRGB, Named.EXTENDED_SRGB.ordinal());
sNamedColorSpaces[Named.LINEAR_EXTENDED_SRGB.ordinal()] = new ColorSpace.Rgb(
"scRGB IEC 61966-2-2:2003",
SRGB_PRIMARIES,
@@ -1472,6 +1521,8 @@
-0.5f, 7.499f,
Named.LINEAR_EXTENDED_SRGB.ordinal()
);
+ sDataToColorSpaces.put(
+ DataSpace.DATASPACE_SCRGB_LINEAR, Named.LINEAR_EXTENDED_SRGB.ordinal());
sNamedColorSpaces[Named.BT709.ordinal()] = new ColorSpace.Rgb(
"Rec. ITU-R BT.709-5",
new float[] { 0.640f, 0.330f, 0.300f, 0.600f, 0.150f, 0.060f },
@@ -1480,6 +1531,7 @@
new Rgb.TransferParameters(1 / 1.099, 0.099 / 1.099, 1 / 4.5, 0.081, 1 / 0.45),
Named.BT709.ordinal()
);
+ sDataToColorSpaces.put(DataSpace.DATASPACE_BT709, Named.BT709.ordinal());
sNamedColorSpaces[Named.BT2020.ordinal()] = new ColorSpace.Rgb(
"Rec. ITU-R BT.2020-1",
new float[] { 0.708f, 0.292f, 0.170f, 0.797f, 0.131f, 0.046f },
@@ -1488,6 +1540,7 @@
new Rgb.TransferParameters(1 / 1.0993, 0.0993 / 1.0993, 1 / 4.5, 0.08145, 1 / 0.45),
Named.BT2020.ordinal()
);
+ sDataToColorSpaces.put(DataSpace.DATASPACE_BT2020, Named.BT2020.ordinal());
sNamedColorSpaces[Named.DCI_P3.ordinal()] = new ColorSpace.Rgb(
"SMPTE RP 431-2-2007 DCI (P3)",
new float[] { 0.680f, 0.320f, 0.265f, 0.690f, 0.150f, 0.060f },
@@ -1496,6 +1549,7 @@
0.0f, 1.0f,
Named.DCI_P3.ordinal()
);
+ sDataToColorSpaces.put(DataSpace.DATASPACE_DCI_P3, Named.DCI_P3.ordinal());
sNamedColorSpaces[Named.DISPLAY_P3.ordinal()] = new ColorSpace.Rgb(
"Display P3",
new float[] { 0.680f, 0.320f, 0.265f, 0.690f, 0.150f, 0.060f },
@@ -1504,6 +1558,7 @@
SRGB_TRANSFER_PARAMETERS,
Named.DISPLAY_P3.ordinal()
);
+ sDataToColorSpaces.put(DataSpace.DATASPACE_DISPLAY_P3, Named.DISPLAY_P3.ordinal());
sNamedColorSpaces[Named.NTSC_1953.ordinal()] = new ColorSpace.Rgb(
"NTSC (1953)",
NTSC_1953_PRIMARIES,
@@ -1528,6 +1583,7 @@
0.0f, 1.0f,
Named.ADOBE_RGB.ordinal()
);
+ sDataToColorSpaces.put(DataSpace.DATASPACE_ADOBE_RGB, Named.ADOBE_RGB.ordinal());
sNamedColorSpaces[Named.PRO_PHOTO_RGB.ordinal()] = new ColorSpace.Rgb(
"ROMM RGB ISO 22028-2:2013",
new float[] { 0.7347f, 0.2653f, 0.1596f, 0.8404f, 0.0366f, 0.0001f },
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 02cdeef..4b367e0 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -1117,6 +1117,7 @@
intent, keyChainServiceConnection, Context.BIND_AUTO_CREATE, user);
}
if (!bindSucceed) {
+ context.unbindService(keyChainServiceConnection);
throw new AssertionError("could not bind to KeyChainService");
}
countDownLatch.await();
diff --git a/libs/WindowManager/Shell/res/values-television/config.xml b/libs/WindowManager/Shell/res/values-television/config.xml
new file mode 100644
index 0000000..552048e
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-television/config.xml
@@ -0,0 +1,36 @@
+<?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.
+ -->
+
+<!-- These resources are around just to allow their values to be customized
+ for TV products. Do not translate. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- The percentage of the screen width to use for the default width or height of
+ picture-in-picture windows. Regardless of the percent set here, calculated size will never
+ be smaller than @dimen/default_minimal_size_pip_resizable_task. -->
+ <item name="config_pictureInPictureDefaultSizePercent" format="float" type="dimen">0.2</item>
+
+ <!-- Default insets [LEFT/RIGHTxTOP/BOTTOM] from the screen edge for picture-in-picture windows.
+ These values are in DPs and will be converted to pixel sizes internally. -->
+ <string translatable="false" name="config_defaultPictureInPictureScreenEdgeInsets">
+ 24x24
+ </string>
+
+ <!-- The default gravity for the picture-in-picture window.
+ Currently, this maps to Gravity.BOTTOM | Gravity.RIGHT -->
+ <integer name="config_defaultPictureInPictureGravity">0x55</integer>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values/config.xml b/libs/WindowManager/Shell/res/values/config.xml
index 1b8032b..d416c06 100644
--- a/libs/WindowManager/Shell/res/values/config.xml
+++ b/libs/WindowManager/Shell/res/values/config.xml
@@ -70,4 +70,30 @@
<!-- Animation duration when exit starting window: reveal app -->
<integer name="starting_window_app_reveal_anim_duration">266</integer>
+
+ <!-- Default insets [LEFT/RIGHTxTOP/BOTTOM] from the screen edge for picture-in-picture windows.
+ These values are in DPs and will be converted to pixel sizes internally. -->
+ <string translatable="false" name="config_defaultPictureInPictureScreenEdgeInsets">
+ 16x16
+ </string>
+
+ <!-- The percentage of the screen width to use for the default width or height of
+ picture-in-picture windows. Regardless of the percent set here, calculated size will never
+ be smaller than @dimen/default_minimal_size_pip_resizable_task. -->
+ <item name="config_pictureInPictureDefaultSizePercent" format="float" type="dimen">0.23</item>
+
+ <!-- The default aspect ratio for picture-in-picture windows. -->
+ <item name="config_pictureInPictureDefaultAspectRatio" format="float" type="dimen">
+ 1.777778
+ </item>
+
+ <!-- This is the limit for the max and min aspect ratio (1 / this value) at which the min size
+ will be used instead of an adaptive size based loosely on area. -->
+ <item name="config_pictureInPictureAspectRatioLimitForMinSize" format="float" type="dimen">
+ 1.777778
+ </item>
+
+ <!-- The default gravity for the picture-in-picture window.
+ Currently, this maps to Gravity.BOTTOM | Gravity.RIGHT -->
+ <integer name="config_defaultPictureInPictureGravity">0x55</integer>
</resources>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 8a8231d..2c96786b 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -18,8 +18,8 @@
<dimen name="dismiss_circle_size">96dp</dimen>
<dimen name="dismiss_circle_small">60dp</dimen>
- <!-- The height of the gradient indicating the dismiss edge when moving a PIP. -->
- <dimen name="floating_dismiss_gradient_height">250dp</dimen>
+ <!-- The height of the gradient indicating the dismiss edge when moving a PIP or bubble. -->
+ <dimen name="floating_dismiss_gradient_height">548dp</dimen>
<!-- The padding around a PiP actions. -->
<dimen name="pip_action_padding">16dp</dimen>
@@ -129,6 +129,9 @@
<dimen name="bubble_dismiss_encircle_size">52dp</dimen>
<!-- Padding around the view displayed when the bubble is expanded -->
<dimen name="bubble_expanded_view_padding">16dp</dimen>
+ <!-- Padding for the edge of the expanded view that is closest to the edge of the screen used
+ when displaying in landscape on a large screen. -->
+ <dimen name="bubble_expanded_view_largescreen_landscape_padding">128dp</dimen>
<!-- This should be at least the size of bubble_expanded_view_padding; it is used to include
a slight touch slop around the expanded view. -->
<dimen name="bubble_expanded_view_slop">8dp</dimen>
@@ -251,4 +254,14 @@
<!-- The distance of the shift icon when early exit starting window. -->
<dimen name="starting_surface_early_exit_icon_distance">32dp</dimen>
+
+ <!-- The default minimal size of a PiP task, in both dimensions. -->
+ <dimen name="default_minimal_size_pip_resizable_task">108dp</dimen>
+
+ <!--
+ The overridable minimal size of a PiP task, in both dimensions.
+ Different from default_minimal_size_pip_resizable_task, this is to limit the dimension
+ when the pinned stack size is overridden by app via minWidth/minHeight.
+ -->
+ <dimen name="overridable_minimal_size_pip_resizable_task">48dp</dimen>
</resources>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 241f1a7..d0138a4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -47,7 +47,10 @@
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
@@ -131,6 +134,10 @@
public static final String RIGHT_POSITION = "Right";
public static final String BOTTOM_POSITION = "Bottom";
+ // Should match with PhoneWindowManager
+ private static final String SYSTEM_DIALOG_REASON_KEY = "reason";
+ private static final String SYSTEM_DIALOG_REASON_GESTURE_NAV = "gestureNav";
+
private final Context mContext;
private final BubblesImpl mImpl = new BubblesImpl();
private Bubbles.BubbleExpandListener mExpandListener;
@@ -675,6 +682,7 @@
try {
mAddedToWindowManager = true;
+ registerBroadcastReceiver();
mBubbleData.getOverflow().initialize(this);
mWindowManager.addView(mStackView, mWmLayoutParams);
mStackView.setOnApplyWindowInsetsListener((view, windowInsets) -> {
@@ -717,6 +725,7 @@
try {
mAddedToWindowManager = false;
+ mContext.unregisterReceiver(mBroadcastReceiver);
if (mStackView != null) {
mWindowManager.removeView(mStackView);
mBubbleData.getOverflow().cleanUpExpandedState();
@@ -730,11 +739,34 @@
}
}
+ private void registerBroadcastReceiver() {
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+ filter.addAction(Intent.ACTION_SCREEN_OFF);
+ mContext.registerReceiver(mBroadcastReceiver, filter);
+ }
+
+ private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (!isStackExpanded()) return; // Nothing to do
+
+ String action = intent.getAction();
+ String reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY);
+ if ((Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
+ && SYSTEM_DIALOG_REASON_GESTURE_NAV.equals(reason))
+ || Intent.ACTION_SCREEN_OFF.equals(action)) {
+ mMainExecutor.execute(() -> collapseStack());
+ }
+ }
+ };
+
/**
* Called by the BubbleStackView and whenever all bubbles have animated out, and none have been
* added in the meantime.
*/
- void onAllBubblesAnimatedOut() {
+ @VisibleForTesting
+ public void onAllBubblesAnimatedOut() {
if (mStackView != null) {
mStackView.setVisibility(INVISIBLE);
removeFromWindowManagerMaybe();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
index 75b19fb..bc0db36 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
@@ -67,7 +67,11 @@
/** The max percent of screen width to use for the flyout on phone. */
public static final float FLYOUT_MAX_WIDTH_PERCENT = 0.6f;
/** The percent of screen width that should be used for the expanded view on a large screen. **/
- public static final float EXPANDED_VIEW_LARGE_SCREEN_WIDTH_PERCENT = 0.72f;
+ private static final float EXPANDED_VIEW_LARGE_SCREEN_LANDSCAPE_WIDTH_PERCENT = 0.48f;
+ /** The percent of screen width that should be used for the expanded view on a large screen. **/
+ private static final float EXPANDED_VIEW_LARGE_SCREEN_PORTRAIT_WIDTH_PERCENT = 0.70f;
+ /** The percent of screen width that should be used for the expanded view on a small tablet. **/
+ private static final float EXPANDED_VIEW_SMALL_TABLET_WIDTH_PERCENT = 0.72f;
private Context mContext;
private WindowManager mWindowManager;
@@ -77,6 +81,7 @@
private boolean mImeVisible;
private int mImeHeight;
private boolean mIsLargeScreen;
+ private boolean mIsSmallTablet;
private Rect mPositionRect;
private int mDefaultMaxBubbles;
@@ -86,7 +91,8 @@
private int mExpandedViewMinHeight;
private int mExpandedViewLargeScreenWidth;
- private int mExpandedViewLargeScreenInset;
+ private int mExpandedViewLargeScreenInsetClosestEdge;
+ private int mExpandedViewLargeScreenInsetFurthestEdge;
private int mOverflowWidth;
private int mExpandedViewPadding;
@@ -127,17 +133,26 @@
| WindowInsets.Type.statusBars()
| WindowInsets.Type.displayCutout());
- mIsLargeScreen = mContext.getResources().getConfiguration().smallestScreenWidthDp >= 600;
+ final Rect bounds = windowMetrics.getBounds();
+ Configuration config = mContext.getResources().getConfiguration();
+ mIsLargeScreen = config.smallestScreenWidthDp >= 600;
+ if (mIsLargeScreen) {
+ float largestEdgeDp = Math.max(config.screenWidthDp, config.screenHeightDp);
+ mIsSmallTablet = largestEdgeDp < 960;
+ } else {
+ mIsSmallTablet = false;
+ }
if (BubbleDebugConfig.DEBUG_POSITIONER) {
Log.w(TAG, "update positioner:"
+ " rotation: " + mRotation
+ " insets: " + insets
+ " isLargeScreen: " + mIsLargeScreen
- + " bounds: " + windowMetrics.getBounds()
+ + " isSmallTablet: " + mIsSmallTablet
+ + " bounds: " + bounds
+ " showingInTaskbar: " + mShowingInTaskbar);
}
- updateInternal(mRotation, insets, windowMetrics.getBounds());
+ updateInternal(mRotation, insets, bounds);
}
/**
@@ -172,11 +187,31 @@
mSpacingBetweenBubbles = res.getDimensionPixelSize(R.dimen.bubble_spacing);
mDefaultMaxBubbles = res.getInteger(R.integer.bubbles_max_rendered);
mExpandedViewPadding = res.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding);
- mExpandedViewLargeScreenWidth = (int) (bounds.width()
- * EXPANDED_VIEW_LARGE_SCREEN_WIDTH_PERCENT);
- mExpandedViewLargeScreenInset = mIsLargeScreen
- ? (bounds.width() - mExpandedViewLargeScreenWidth) / 2
- : mExpandedViewPadding;
+ if (mIsSmallTablet) {
+ mExpandedViewLargeScreenWidth = (int) (bounds.width()
+ * EXPANDED_VIEW_SMALL_TABLET_WIDTH_PERCENT);
+ } else {
+ mExpandedViewLargeScreenWidth = isLandscape()
+ ? (int) (bounds.width() * EXPANDED_VIEW_LARGE_SCREEN_LANDSCAPE_WIDTH_PERCENT)
+ : (int) (bounds.width() * EXPANDED_VIEW_LARGE_SCREEN_PORTRAIT_WIDTH_PERCENT);
+ }
+ if (mIsLargeScreen) {
+ if (isLandscape() && !mIsSmallTablet) {
+ mExpandedViewLargeScreenInsetClosestEdge = res.getDimensionPixelSize(
+ R.dimen.bubble_expanded_view_largescreen_landscape_padding);
+ mExpandedViewLargeScreenInsetFurthestEdge = bounds.width()
+ - mExpandedViewLargeScreenInsetClosestEdge
+ - mExpandedViewLargeScreenWidth;
+ } else {
+ final int centeredInset = (bounds.width() - mExpandedViewLargeScreenWidth) / 2;
+ mExpandedViewLargeScreenInsetClosestEdge = centeredInset;
+ mExpandedViewLargeScreenInsetFurthestEdge = centeredInset;
+ }
+ } else {
+ mExpandedViewLargeScreenInsetClosestEdge = mExpandedViewPadding;
+ mExpandedViewLargeScreenInsetFurthestEdge = mExpandedViewPadding;
+ }
+
mOverflowWidth = mIsLargeScreen
? mExpandedViewLargeScreenWidth
: res.getDimensionPixelSize(
@@ -328,15 +363,18 @@
public int[] getExpandedViewContainerPadding(boolean onLeft, boolean isOverflow) {
final int pointerTotalHeight = mPointerHeight - mPointerOverlap;
if (mIsLargeScreen) {
+ // Note:
+ // If we're in portrait OR if we're a small tablet, then the two insets values will
+ // be equal. If we're landscape and a large tablet, the two values will be different.
// [left, top, right, bottom]
mPaddings[0] = onLeft
- ? mExpandedViewLargeScreenInset - pointerTotalHeight
- : mExpandedViewLargeScreenInset;
+ ? mExpandedViewLargeScreenInsetClosestEdge - pointerTotalHeight
+ : mExpandedViewLargeScreenInsetFurthestEdge;
mPaddings[1] = 0;
mPaddings[2] = onLeft
- ? mExpandedViewLargeScreenInset
- : mExpandedViewLargeScreenInset - pointerTotalHeight;
- // Overflow doesn't show manage button / get padding from it so add padding here for it
+ ? mExpandedViewLargeScreenInsetFurthestEdge
+ : mExpandedViewLargeScreenInsetClosestEdge - pointerTotalHeight;
+ // Overflow doesn't show manage button / get padding from it so add padding here
mPaddings[3] = isOverflow ? mExpandedViewPadding : 0;
return mPaddings;
} else {
@@ -494,12 +532,13 @@
float x;
float y;
if (showBubblesVertically()) {
+ int inset = mExpandedViewLargeScreenInsetClosestEdge;
y = rowStart + positionInRow;
int left = mIsLargeScreen
- ? mExpandedViewLargeScreenInset - mExpandedViewPadding - mBubbleSize
+ ? inset - mExpandedViewPadding - mBubbleSize
: mPositionRect.left;
int right = mIsLargeScreen
- ? mPositionRect.right - mExpandedViewLargeScreenInset + mExpandedViewPadding
+ ? mPositionRect.right - inset + mExpandedViewPadding
: mPositionRect.right - mBubbleSize;
x = state.onLeft
? left
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/DismissView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/DismissView.kt
index 74672a3..063dac3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/DismissView.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/DismissView.kt
@@ -16,11 +16,16 @@
package com.android.wm.shell.bubbles
+import android.animation.ObjectAnimator
import android.content.Context
-import android.graphics.drawable.TransitionDrawable
+import android.graphics.Color
+import android.graphics.drawable.GradientDrawable
+import android.util.IntProperty
import android.view.Gravity
import android.view.View
import android.view.ViewGroup
+import android.view.WindowManager
+import android.view.WindowInsets
import android.widget.FrameLayout
import androidx.dynamicanimation.animation.DynamicAnimation
import androidx.dynamicanimation.animation.SpringForce.DAMPING_RATIO_LOW_BOUNCY
@@ -28,8 +33,6 @@
import com.android.wm.shell.R
import com.android.wm.shell.animation.PhysicsAnimator
import com.android.wm.shell.common.DismissCircleView
-import android.view.WindowInsets
-import android.view.WindowManager
/*
* View that handles interactions between DismissCircleView and BubbleStackView.
@@ -41,9 +44,21 @@
private val animator = PhysicsAnimator.getInstance(circle)
private val spring = PhysicsAnimator.SpringConfig(STIFFNESS_LOW, DAMPING_RATIO_LOW_BOUNCY)
- private val DISMISS_SCRIM_FADE_MS = 200
+ private val DISMISS_SCRIM_FADE_MS = 200L
private var wm: WindowManager =
context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
+ private var gradientDrawable = createGradient()
+
+ private val GRADIENT_ALPHA: IntProperty<GradientDrawable> =
+ object : IntProperty<GradientDrawable>("alpha") {
+ override fun setValue(d: GradientDrawable, percent: Int) {
+ d.alpha = percent
+ }
+ override fun get(d: GradientDrawable): Int {
+ return d.alpha
+ }
+ }
+
init {
setLayoutParams(LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
@@ -53,8 +68,7 @@
setClipToPadding(false)
setClipChildren(false)
setVisibility(View.INVISIBLE)
- setBackgroundResource(
- R.drawable.floating_dismiss_gradient_transition)
+ setBackgroundDrawable(gradientDrawable)
val targetSize: Int = resources.getDimensionPixelSize(R.dimen.dismiss_circle_size)
addView(circle, LayoutParams(targetSize, targetSize,
@@ -71,7 +85,11 @@
if (isShowing) return
isShowing = true
setVisibility(View.VISIBLE)
- (getBackground() as TransitionDrawable).startTransition(DISMISS_SCRIM_FADE_MS)
+ val alphaAnim = ObjectAnimator.ofInt(gradientDrawable, GRADIENT_ALPHA,
+ gradientDrawable.alpha, 255)
+ alphaAnim.setDuration(DISMISS_SCRIM_FADE_MS)
+ alphaAnim.start()
+
animator.cancel()
animator
.spring(DynamicAnimation.TRANSLATION_Y, 0f, spring)
@@ -85,7 +103,10 @@
fun hide() {
if (!isShowing) return
isShowing = false
- (getBackground() as TransitionDrawable).reverseTransition(DISMISS_SCRIM_FADE_MS)
+ val alphaAnim = ObjectAnimator.ofInt(gradientDrawable, GRADIENT_ALPHA,
+ gradientDrawable.alpha, 0)
+ alphaAnim.setDuration(DISMISS_SCRIM_FADE_MS)
+ alphaAnim.start()
animator
.spring(DynamicAnimation.TRANSLATION_Y, height.toFloat(),
spring)
@@ -93,6 +114,13 @@
.start()
}
+ /**
+ * Cancels the animator for the dismiss target.
+ */
+ fun cancelAnimators() {
+ animator.cancel()
+ }
+
fun updateResources() {
updatePadding()
layoutParams.height = resources.getDimensionPixelSize(
@@ -104,6 +132,20 @@
circle.requestLayout()
}
+ private fun createGradient(): GradientDrawable {
+ val gradientColor = context.resources.getColor(android.R.color.system_neutral1_900)
+ val alpha = 0.7f * 255
+ val gradientColorWithAlpha = Color.argb(alpha.toInt(),
+ Color.red(gradientColor),
+ Color.green(gradientColor),
+ Color.blue(gradientColor))
+ val gd = GradientDrawable(
+ GradientDrawable.Orientation.BOTTOM_TOP,
+ intArrayOf(gradientColorWithAlpha, Color.TRANSPARENT))
+ gd.setAlpha(0)
+ return gd
+ }
+
private fun updatePadding() {
val insets: WindowInsets = wm.getCurrentWindowMetrics().getWindowInsets()
val navInset = insets.getInsetsIgnoringVisibility(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index f7c92fe..8a482fb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -144,21 +144,42 @@
return Math.max(dividerInset, radius);
}
- /** Gets bounds of the primary split. */
+ /** Gets bounds of the primary split with screen based coordinate. */
public Rect getBounds1() {
return new Rect(mBounds1);
}
- /** Gets bounds of the secondary split. */
+ /** Gets bounds of the primary split with parent based coordinate. */
+ public Rect getRefBounds1() {
+ Rect outBounds = getBounds1();
+ outBounds.offset(-mRootBounds.left, -mRootBounds.top);
+ return outBounds;
+ }
+
+ /** Gets bounds of the secondary split with screen based coordinate. */
public Rect getBounds2() {
return new Rect(mBounds2);
}
- /** Gets bounds of divider window. */
+ /** Gets bounds of the secondary split with parent based coordinate. */
+ public Rect getRefBounds2() {
+ final Rect outBounds = getBounds2();
+ outBounds.offset(-mRootBounds.left, -mRootBounds.top);
+ return outBounds;
+ }
+
+ /** Gets bounds of divider window with screen based coordinate. */
public Rect getDividerBounds() {
return new Rect(mDividerBounds);
}
+ /** Gets bounds of divider window with parent based coordinate. */
+ public Rect getRefDividerBounds() {
+ final Rect outBounds = getDividerBounds();
+ outBounds.offset(-mRootBounds.left, -mRootBounds.top);
+ return outBounds;
+ }
+
/** Returns leash of the current divider bar. */
@Nullable
public SurfaceControl getDividerLeash() {
@@ -452,14 +473,17 @@
SurfaceControl leash2, SurfaceControl dimLayer1, SurfaceControl dimLayer2) {
final SurfaceControl dividerLeash = getDividerLeash();
if (dividerLeash != null) {
- t.setPosition(dividerLeash, mDividerBounds.left, mDividerBounds.top);
+ mTempRect.set(getRefDividerBounds());
+ t.setPosition(dividerLeash, mTempRect.left, mTempRect.top);
// Resets layer of divider bar to make sure it is always on top.
t.setLayer(dividerLeash, SPLIT_DIVIDER_LAYER);
}
- t.setPosition(leash1, mBounds1.left, mBounds1.top)
- .setWindowCrop(leash1, mBounds1.width(), mBounds1.height());
- t.setPosition(leash2, mBounds2.left, mBounds2.top)
- .setWindowCrop(leash2, mBounds2.width(), mBounds2.height());
+ mTempRect.set(getRefBounds1());
+ t.setPosition(leash1, mTempRect.left, mTempRect.top)
+ .setWindowCrop(leash1, mTempRect.width(), mTempRect.height());
+ mTempRect.set(getRefBounds2());
+ t.setPosition(leash2, mTempRect.left, mTempRect.top)
+ .setWindowCrop(leash2, mTempRect.width(), mTempRect.height());
if (mImePositionProcessor.adjustSurfaceLayoutForIme(
t, dividerLeash, leash1, leash2, dimLayer1, dimLayer2)) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
index e29dde2..797df41 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
@@ -32,6 +32,7 @@
import android.util.TypedValue;
import android.view.Gravity;
+import com.android.wm.shell.R;
import com.android.wm.shell.common.DisplayLayout;
import java.io.PrintWriter;
@@ -76,15 +77,15 @@
protected void reloadResources(Context context) {
final Resources res = context.getResources();
mDefaultAspectRatio = res.getFloat(
- com.android.internal.R.dimen.config_pictureInPictureDefaultAspectRatio);
+ R.dimen.config_pictureInPictureDefaultAspectRatio);
mDefaultStackGravity = res.getInteger(
- com.android.internal.R.integer.config_defaultPictureInPictureGravity);
+ R.integer.config_defaultPictureInPictureGravity);
mDefaultMinSize = res.getDimensionPixelSize(
- com.android.internal.R.dimen.default_minimal_size_pip_resizable_task);
+ R.dimen.default_minimal_size_pip_resizable_task);
mOverridableMinSize = res.getDimensionPixelSize(
- com.android.internal.R.dimen.overridable_minimal_size_pip_resizable_task);
+ R.dimen.overridable_minimal_size_pip_resizable_task);
final String screenEdgeInsetsDpString = res.getString(
- com.android.internal.R.string.config_defaultPictureInPictureScreenEdgeInsets);
+ R.string.config_defaultPictureInPictureScreenEdgeInsets);
final Size screenEdgeInsetsDp = !screenEdgeInsetsDpString.isEmpty()
? Size.parseSize(screenEdgeInsetsDpString)
: null;
@@ -96,9 +97,9 @@
mMaxAspectRatio = res.getFloat(
com.android.internal.R.dimen.config_pictureInPictureMaxAspectRatio);
mDefaultSizePercent = res.getFloat(
- com.android.internal.R.dimen.config_pictureInPictureDefaultSizePercent);
+ R.dimen.config_pictureInPictureDefaultSizePercent);
mMaxAspectRatioForMinSize = res.getFloat(
- com.android.internal.R.dimen.config_pictureInPictureAspectRatioLimitForMinSize);
+ R.dimen.config_pictureInPictureAspectRatioLimitForMinSize);
mMinAspectRatioForMinSize = 1f / mMaxAspectRatioForMinSize;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
index 180e3fb..d7322ce 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
@@ -138,8 +138,8 @@
// destination are different.
final float scale = srcW <= srcH ? (float) destW / srcW : (float) destH / srcH;
final Rect crop = mTmpDestinationRect;
- crop.set(0, 0, Transitions.ENABLE_SHELL_TRANSITIONS ? destH
- : destW, Transitions.ENABLE_SHELL_TRANSITIONS ? destW : destH);
+ crop.set(0, 0, Transitions.SHELL_TRANSITIONS_ROTATION ? destH
+ : destW, Transitions.SHELL_TRANSITIONS_ROTATION ? destW : destH);
// Inverse scale for crop to fit in screen coordinates.
crop.scale(1 / scale);
crop.offset(insets.left, insets.top);
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 60aac68..91615fe 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
@@ -97,7 +97,7 @@
* meaningful if {@link #mInFixedRotation} is true.
*/
@Surface.Rotation
- private int mFixedRotation;
+ private int mEndFixedRotation;
/** Whether the PIP window has fade out for fixed rotation. */
private boolean mHasFadeOut;
@@ -153,7 +153,7 @@
final TransitionInfo.Change currentPipChange = findCurrentPipChange(info);
final TransitionInfo.Change fixedRotationChange = findFixedRotationChange(info);
mInFixedRotation = fixedRotationChange != null;
- mFixedRotation = mInFixedRotation
+ mEndFixedRotation = mInFixedRotation
? fixedRotationChange.getEndFixedRotation()
: ROTATION_UNDEFINED;
@@ -257,7 +257,7 @@
final ActivityManager.RunningTaskInfo taskInfo = mPipOrganizer.getTaskInfo();
if (taskInfo != null) {
startExpandAnimation(taskInfo, mPipOrganizer.getSurfaceControl(),
- new Rect(mExitDestinationBounds));
+ new Rect(mExitDestinationBounds), Surface.ROTATION_0);
}
mExitDestinationBounds.setEmpty();
mCurrentPipTaskToken = null;
@@ -332,30 +332,31 @@
@NonNull SurfaceControl.Transaction finishTransaction,
@NonNull Transitions.TransitionFinishCallback finishCallback,
@NonNull TransitionInfo.Change pipChange) {
- TransitionInfo.Change displayRotationChange = null;
- for (int i = info.getChanges().size() - 1; i >= 0; --i) {
- final TransitionInfo.Change change = info.getChanges().get(i);
- if (change.getMode() == TRANSIT_CHANGE
- && (change.getFlags() & FLAG_IS_DISPLAY) != 0
- && change.getStartRotation() != change.getEndRotation()) {
- displayRotationChange = change;
- break;
- }
- }
-
- if (displayRotationChange != null) {
- // Exiting PIP to fullscreen with orientation change.
- startExpandAndRotationAnimation(info, startTransaction, finishTransaction,
- finishCallback, displayRotationChange, pipChange);
- return;
- }
-
- // When there is no rotation, we can simply expand the PIP window.
mFinishCallback = (wct, wctCB) -> {
mPipOrganizer.onExitPipFinished(pipChange.getTaskInfo());
finishCallback.onTransitionFinished(wct, wctCB);
};
+ // Check if it is Shell rotation.
+ if (Transitions.SHELL_TRANSITIONS_ROTATION) {
+ TransitionInfo.Change displayRotationChange = null;
+ for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+ final TransitionInfo.Change change = info.getChanges().get(i);
+ if (change.getMode() == TRANSIT_CHANGE
+ && (change.getFlags() & FLAG_IS_DISPLAY) != 0
+ && change.getStartRotation() != change.getEndRotation()) {
+ displayRotationChange = change;
+ break;
+ }
+ }
+ if (displayRotationChange != null) {
+ // Exiting PIP to fullscreen with orientation change.
+ startExpandAndRotationAnimation(info, startTransaction, finishTransaction,
+ displayRotationChange, pipChange);
+ return;
+ }
+ }
+
// Set the initial frame as scaling the end to the start.
final Rect destinationBounds = new Rect(pipChange.getEndAbsBounds());
final Point offset = pipChange.getEndRelOffset();
@@ -364,13 +365,41 @@
mSurfaceTransactionHelper.scale(startTransaction, pipChange.getLeash(),
destinationBounds, mPipBoundsState.getBounds());
startTransaction.apply();
- startExpandAnimation(pipChange.getTaskInfo(), pipChange.getLeash(), destinationBounds);
+
+ // Check if it is fixed rotation.
+ final int rotationDelta;
+ if (mInFixedRotation) {
+ final int startRotation = pipChange.getStartRotation();
+ final int endRotation = mEndFixedRotation;
+ rotationDelta = deltaRotation(startRotation, endRotation);
+ final Rect endBounds = new Rect(destinationBounds);
+
+ // Set the end frame since the display won't rotate until fixed rotation is finished
+ // in the next display change transition.
+ rotateBounds(endBounds, destinationBounds, rotationDelta);
+ final int degree, x, y;
+ if (rotationDelta == ROTATION_90) {
+ degree = 90;
+ x = destinationBounds.right;
+ y = destinationBounds.top;
+ } else {
+ degree = -90;
+ x = destinationBounds.left;
+ y = destinationBounds.bottom;
+ }
+ mSurfaceTransactionHelper.rotateAndScaleWithCrop(finishTransaction,
+ pipChange.getLeash(), endBounds, endBounds, new Rect(), degree, x, y,
+ true /* isExpanding */, rotationDelta == ROTATION_270 /* clockwise */);
+ } else {
+ rotationDelta = Surface.ROTATION_0;
+ }
+ startExpandAnimation(pipChange.getTaskInfo(), pipChange.getLeash(), destinationBounds,
+ rotationDelta);
}
private void startExpandAndRotationAnimation(@NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction startTransaction,
@NonNull SurfaceControl.Transaction finishTransaction,
- @NonNull Transitions.TransitionFinishCallback finishCallback,
@NonNull TransitionInfo.Change displayRotationChange,
@NonNull TransitionInfo.Change pipChange) {
final int rotateDelta = deltaRotation(displayRotationChange.getStartRotation(),
@@ -380,11 +409,6 @@
final CounterRotatorHelper rotator = new CounterRotatorHelper();
rotator.handleClosingChanges(info, startTransaction, displayRotationChange);
- mFinishCallback = (wct, wctCB) -> {
- mPipOrganizer.onExitPipFinished(pipChange.getTaskInfo());
- finishCallback.onTransitionFinished(wct, wctCB);
- };
-
// Get the start bounds in new orientation.
final Rect startBounds = new Rect(pipChange.getStartAbsBounds());
rotateBounds(startBounds, displayRotationChange.getStartAbsBounds(), rotateDelta);
@@ -425,12 +449,11 @@
}
private void startExpandAnimation(final TaskInfo taskInfo, final SurfaceControl leash,
- final Rect destinationBounds) {
- PipAnimationController.PipTransitionAnimator animator =
+ final Rect destinationBounds, final int rotationDelta) {
+ final PipAnimationController.PipTransitionAnimator animator =
mPipAnimationController.getAnimator(taskInfo, leash, mPipBoundsState.getBounds(),
mPipBoundsState.getBounds(), destinationBounds, null,
- TRANSITION_DIRECTION_LEAVE_PIP, 0 /* startingAngle */, Surface.ROTATION_0);
-
+ TRANSITION_DIRECTION_LEAVE_PIP, 0 /* startingAngle */, rotationDelta);
animator.setTransitionDirection(TRANSITION_DIRECTION_LEAVE_PIP)
.setPipAnimationCallback(mPipAnimationCallback)
.setDuration(mEnterExitAnimationDuration)
@@ -526,7 +549,7 @@
mPipTransitionState.setTransitionState(PipTransitionState.ENTERING_PIP);
mFinishCallback = finishCallback;
- final int endRotation = mInFixedRotation ? mFixedRotation : enterPip.getEndRotation();
+ final int endRotation = mInFixedRotation ? mEndFixedRotation : enterPip.getEndRotation();
return startEnterAnimation(enterPip.getTaskInfo(), enterPip.getLeash(),
startTransaction, finishTransaction, enterPip.getStartRotation(),
endRotation);
@@ -545,8 +568,8 @@
taskInfo.pictureInPictureParams, currentBounds);
if (rotationDelta != Surface.ROTATION_0 && mInFixedRotation) {
// Need to get the bounds of new rotation in old rotation for fixed rotation,
- sourceHintRect = computeRotatedBounds(rotationDelta, startRotation, endRotation,
- taskInfo, TRANSITION_DIRECTION_TO_PIP, destinationBounds, sourceHintRect);
+ computeEnterPipRotatedBounds(rotationDelta, startRotation, endRotation, taskInfo,
+ destinationBounds, sourceHintRect);
}
PipAnimationController.PipTransitionAnimator animator;
// Set corner radius for entering pip.
@@ -583,8 +606,6 @@
startTransaction.setMatrix(leash, tmpTransform, new float[9]);
}
if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) {
- // Reverse the rotation for Shell transition animation.
- rotationDelta = deltaRotation(rotationDelta, 0);
animator = mPipAnimationController.getAnimator(taskInfo, leash, currentBounds,
currentBounds, destinationBounds, sourceHintRect, TRANSITION_DIRECTION_TO_PIP,
0 /* startingAngle */, rotationDelta);
@@ -617,33 +638,22 @@
return true;
}
- /** Computes destination bounds in old rotation and returns source hint rect if available. */
- @Nullable
- private Rect computeRotatedBounds(int rotationDelta, int startRotation, int endRotation,
- TaskInfo taskInfo, int direction, Rect outDestinationBounds,
- @Nullable Rect sourceHintRect) {
- if (direction == TRANSITION_DIRECTION_TO_PIP) {
- mPipBoundsState.getDisplayLayout().rotateTo(mContext.getResources(), endRotation);
- final Rect displayBounds = mPipBoundsState.getDisplayBounds();
- outDestinationBounds.set(mPipBoundsAlgorithm.getEntryDestinationBounds());
- // Transform the destination bounds to current display coordinates.
- rotateBounds(outDestinationBounds, displayBounds, endRotation, startRotation);
- // When entering PiP (from button navigation mode), adjust the source rect hint by
- // display cutout if applicable.
- if (sourceHintRect != null && taskInfo.displayCutoutInsets != null) {
- if (rotationDelta == Surface.ROTATION_270) {
- sourceHintRect.offset(taskInfo.displayCutoutInsets.left,
- taskInfo.displayCutoutInsets.top);
- }
+ /** Computes destination bounds in old rotation and updates source hint rect if available. */
+ private void computeEnterPipRotatedBounds(int rotationDelta, int startRotation, int endRotation,
+ TaskInfo taskInfo, Rect outDestinationBounds, @Nullable Rect outSourceHintRect) {
+ mPipBoundsState.getDisplayLayout().rotateTo(mContext.getResources(), endRotation);
+ final Rect displayBounds = mPipBoundsState.getDisplayBounds();
+ outDestinationBounds.set(mPipBoundsAlgorithm.getEntryDestinationBounds());
+ // Transform the destination bounds to current display coordinates.
+ rotateBounds(outDestinationBounds, displayBounds, endRotation, startRotation);
+ // When entering PiP (from button navigation mode), adjust the source rect hint by
+ // display cutout if applicable.
+ if (outSourceHintRect != null && taskInfo.displayCutoutInsets != null) {
+ if (rotationDelta == Surface.ROTATION_270) {
+ outSourceHintRect.offset(taskInfo.displayCutoutInsets.left,
+ taskInfo.displayCutoutInsets.top);
}
- } else if (direction == TRANSITION_DIRECTION_LEAVE_PIP) {
- final Rect rotatedDestinationBounds = new Rect(outDestinationBounds);
- rotateBounds(rotatedDestinationBounds, mPipBoundsState.getDisplayBounds(),
- rotationDelta);
- return PipBoundsAlgorithm.getValidSourceHintRect(taskInfo.pictureInPictureParams,
- rotatedDestinationBounds);
}
- return sourceHintRect;
}
private void startExitToSplitAnimation(TransitionInfo info,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
index 915c593..3115f8a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
@@ -20,27 +20,20 @@
import android.content.Context;
import android.content.res.Resources;
-import android.graphics.Insets;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
-import android.graphics.drawable.TransitionDrawable;
-import android.view.Gravity;
import android.view.MotionEvent;
import android.view.SurfaceControl;
import android.view.View;
-import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.WindowInsets;
import android.view.WindowManager;
-import android.widget.FrameLayout;
import androidx.annotation.NonNull;
-import androidx.dynamicanimation.animation.DynamicAnimation;
-import androidx.dynamicanimation.animation.SpringForce;
import com.android.wm.shell.R;
-import com.android.wm.shell.animation.PhysicsAnimator;
+import com.android.wm.shell.bubbles.DismissView;
import com.android.wm.shell.common.DismissCircleView;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
@@ -56,9 +49,6 @@
/* The multiplier to apply scale the target size by when applying the magnetic field radius */
private static final float MAGNETIC_FIELD_RADIUS_MULTIPLIER = 1.25f;
- /** Duration of the dismiss scrim fading in/out. */
- private static final int DISMISS_TRANSITION_DURATION_MS = 200;
-
/**
* MagnetizedObject wrapper for PIP. This allows the magnetic target library to locate and move
* PIP.
@@ -69,7 +59,7 @@
* Container for the dismiss circle, so that it can be animated within the container via
* translation rather than within the WindowManager via slow layout animations.
*/
- private ViewGroup mTargetViewContainer;
+ private DismissView mTargetViewContainer;
/** Circle view used to render the dismiss target. */
private DismissCircleView mTargetView;
@@ -79,16 +69,6 @@
*/
private MagnetizedObject.MagneticTarget mMagneticTarget;
- /**
- * PhysicsAnimator instance for animating the dismiss target in/out.
- */
- private PhysicsAnimator<View> mMagneticTargetAnimator;
-
- /** Default configuration to use for springing the dismiss target in/out. */
- private final PhysicsAnimator.SpringConfig mTargetSpringConfig =
- new PhysicsAnimator.SpringConfig(
- SpringForce.STIFFNESS_LOW, SpringForce.DAMPING_RATIO_LOW_BOUNCY);
-
// Allow dragging the PIP to a location to close it
private boolean mEnableDismissDragToEdge;
@@ -125,12 +105,8 @@
cleanUpDismissTarget();
}
- mTargetView = new DismissCircleView(mContext);
- mTargetViewContainer = new FrameLayout(mContext);
- mTargetViewContainer.setBackgroundDrawable(
- mContext.getDrawable(R.drawable.floating_dismiss_gradient_transition));
- mTargetViewContainer.setClipChildren(false);
- mTargetViewContainer.addView(mTargetView);
+ mTargetViewContainer = new DismissView(mContext);
+ mTargetView = mTargetViewContainer.getCircle();
mTargetViewContainer.setOnApplyWindowInsetsListener((view, windowInsets) -> {
if (!windowInsets.equals(mWindowInsets)) {
mWindowInsets = windowInsets;
@@ -187,7 +163,6 @@
}
});
- mMagneticTargetAnimator = PhysicsAnimator.getInstance(mTargetView);
}
@Override
@@ -213,19 +188,13 @@
if (mTargetView == null) {
return;
}
+ if (mTargetViewContainer != null) {
+ mTargetViewContainer.updateResources();
+ }
final Resources res = mContext.getResources();
mTargetSize = res.getDimensionPixelSize(R.dimen.dismiss_circle_size);
mDismissAreaHeight = res.getDimensionPixelSize(R.dimen.floating_dismiss_gradient_height);
- final WindowInsets insets = mWindowManager.getCurrentWindowMetrics().getWindowInsets();
- final Insets navInset = insets.getInsetsIgnoringVisibility(
- WindowInsets.Type.navigationBars());
- final FrameLayout.LayoutParams newParams =
- new FrameLayout.LayoutParams(mTargetSize, mTargetSize);
- newParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
- newParams.bottomMargin = navInset.bottom + mContext.getResources().getDimensionPixelSize(
- R.dimen.floating_dismiss_bottom_margin);
- mTargetView.setLayoutParams(newParams);
// Set the magnetic field radius equal to the target size from the center of the target
setMagneticFieldRadiusPercent(mMagneticFieldRadiusPercent);
@@ -261,7 +230,7 @@
/** Adds the magnetic target view to the WindowManager so it's ready to be animated in. */
public void createOrUpdateDismissTarget() {
if (!mTargetViewContainer.isAttachedToWindow()) {
- mMagneticTargetAnimator.cancel();
+ mTargetViewContainer.cancelAnimators();
mTargetViewContainer.setVisibility(View.INVISIBLE);
mTargetViewContainer.getViewTreeObserver().removeOnPreDrawListener(this);
@@ -312,18 +281,8 @@
createOrUpdateDismissTarget();
if (mTargetViewContainer.getVisibility() != View.VISIBLE) {
- mTargetView.setTranslationY(mTargetViewContainer.getHeight());
- mTargetViewContainer.setVisibility(View.VISIBLE);
mTargetViewContainer.getViewTreeObserver().addOnPreDrawListener(this);
-
- // Cancel in case we were in the middle of animating it out.
- mMagneticTargetAnimator.cancel();
- mMagneticTargetAnimator
- .spring(DynamicAnimation.TRANSLATION_Y, 0f, mTargetSpringConfig)
- .start();
-
- ((TransitionDrawable) mTargetViewContainer.getBackground()).startTransition(
- DISMISS_TRANSITION_DURATION_MS);
+ mTargetViewContainer.show();
}
}
@@ -332,16 +291,7 @@
if (!mEnableDismissDragToEdge) {
return;
}
-
- mMagneticTargetAnimator
- .spring(DynamicAnimation.TRANSLATION_Y,
- mTargetViewContainer.getHeight(),
- mTargetSpringConfig)
- .withEndActions(() -> mTargetViewContainer.setVisibility(View.GONE))
- .start();
-
- ((TransitionDrawable) mTargetViewContainer.getBackground()).reverseTransition(
- DISMISS_TRANSITION_DURATION_MS);
+ mTargetViewContainer.hide();
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
index 69d6c9e..32ebe2d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
@@ -33,6 +33,7 @@
import android.util.Log;
import android.view.SurfaceControl;
import android.view.SyncRtSurfaceTransactionApplier;
+import android.view.WindowManagerGlobal;
import androidx.annotation.Nullable;
@@ -143,7 +144,6 @@
mSystemWindows.addView(mPipMenuView,
getPipMenuLayoutParams(MENU_WINDOW_TITLE, 0 /* width */, 0 /* height */),
0, SHELL_ROOT_LAYER_PIP);
- mPipMenuView.setFocusGrantToken(mSystemWindows.getFocusGrantToken(mPipMenuView));
}
@Override
@@ -164,6 +164,7 @@
t.setPosition(menuSurfaceControl, menuBounds.left, menuBounds.top);
t.apply();
}
+ grantPipMenuFocus(true);
mPipMenuView.show(mInMoveMode, mDelegate.getPipGravity());
}
}
@@ -194,8 +195,9 @@
if (DEBUG) Log.d(TAG, "hideMenu()");
}
- mPipMenuView.hide(mInMoveMode);
+ mPipMenuView.hide();
if (!mInMoveMode) {
+ grantPipMenuFocus(false);
mDelegate.closeMenu();
}
}
@@ -453,4 +455,15 @@
void closePip();
}
+
+ private void grantPipMenuFocus(boolean grantFocus) {
+ if (DEBUG) Log.d(TAG, "grantWindowFocus(" + grantFocus + ")");
+
+ try {
+ WindowManagerGlobal.getWindowSession().grantEmbeddedWindowFocus(null /* window */,
+ mSystemWindows.getFocusGrantToken(mPipMenuView), grantFocus);
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to update focus", e);
+ }
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java
index 773e9bf..3090139 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java
@@ -30,7 +30,6 @@
import android.content.Context;
import android.graphics.Rect;
import android.os.Handler;
-import android.os.IBinder;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
@@ -39,7 +38,6 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewRootImpl;
-import android.view.WindowManagerGlobal;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
@@ -72,7 +70,6 @@
private final ImageView mArrowRight;
private final ImageView mArrowDown;
private final ImageView mArrowLeft;
- private IBinder mFocusGrantToken = null;
private final ViewGroup mScrollView;
private final ViewGroup mHorizontalScrollView;
@@ -152,10 +149,6 @@
mListener = listener;
}
- void setFocusGrantToken(IBinder token) {
- mFocusGrantToken = token;
- }
-
void setExpandedModeEnabled(boolean enabled) {
mExpandButton.setVisibility(enabled ? VISIBLE : GONE);
}
@@ -170,8 +163,6 @@
void show(boolean inMoveMode, int gravity) {
if (DEBUG) Log.d(TAG, "show(), inMoveMode: " + inMoveMode);
- grantWindowFocus(true);
-
if (inMoveMode) {
showMovementHints(gravity);
} else {
@@ -180,15 +171,11 @@
animateAlphaTo(1, mMenuFrameView);
}
- void hide(boolean isInMoveMode) {
+ void hide() {
if (DEBUG) Log.d(TAG, "hide()");
animateAlphaTo(0, mActionButtonsContainer);
animateAlphaTo(0, mMenuFrameView);
hideMovementHints();
-
- if (!isInMoveMode) {
- grantWindowFocus(false);
- }
}
private void animateAlphaTo(float alpha, View view) {
@@ -217,17 +204,6 @@
|| mArrowLeft.getAlpha() != 0f;
}
- private void grantWindowFocus(boolean grantFocus) {
- if (DEBUG) Log.d(TAG, "grantWindowFocus(" + grantFocus + ")");
-
- try {
- WindowManagerGlobal.getWindowSession().grantEmbeddedWindowFocus(null /* window */,
- mFocusGrantToken, grantFocus);
- } catch (Exception e) {
- Log.e(TAG, "Unable to update focus", e);
- }
- }
-
void setAdditionalActions(List<RemoteAction> actions, Handler mainHandler) {
if (DEBUG) Log.d(TAG, "setAdditionalActions()");
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 81dacdb..76641f0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -979,7 +979,8 @@
t.setAlpha(dividerLeash, 1);
t.setLayer(dividerLeash, SPLIT_DIVIDER_LAYER);
t.setPosition(dividerLeash,
- mSplitLayout.getDividerBounds().left, mSplitLayout.getDividerBounds().top);
+ mSplitLayout.getRefDividerBounds().left,
+ mSplitLayout.getRefDividerBounds().top);
} else {
t.hide(dividerLeash);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index 5af1530..4bc5850 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -26,6 +26,7 @@
import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_UP;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_RESOURCE_UPDATED;
+import static android.app.admin.DevicePolicyManager.EXTRA_RESOURCE_TYPE;
import static android.app.admin.DevicePolicyManager.EXTRA_RESOURCE_TYPE_DRAWABLE;
import static android.app.admin.DevicePolicyResources.Drawables.Source.PROFILE_SWITCH_ANIMATION;
import static android.app.admin.DevicePolicyResources.Drawables.Style.OUTLINE;
@@ -156,9 +157,8 @@
private BroadcastReceiver mEnterpriseResourceUpdatedReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- boolean isDrawable = intent.getBooleanExtra(
- EXTRA_RESOURCE_TYPE_DRAWABLE, /* default= */ false);
- if (!isDrawable) {
+ if (intent.getIntExtra(EXTRA_RESOURCE_TYPE, /* default= */ -1)
+ != EXTRA_RESOURCE_TYPE_DRAWABLE) {
return;
}
updateEnterpriseThumbnailDrawable();
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt
index 65eb9aa..57bcbc0 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt
@@ -17,6 +17,7 @@
package com.android.wm.shell.flicker.apppairs
import android.platform.test.annotations.Presubmit
+import android.view.Display
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
@@ -24,6 +25,7 @@
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group1
import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.traces.common.WindowManagerConditionsFactory
import com.android.wm.shell.flicker.appPairsDividerIsVisibleAtEnd
import com.android.wm.shell.flicker.helpers.AppPairsHelper
import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig
@@ -60,7 +62,18 @@
// TODO pair apps through normal UX flow
executeShellCommand(
composePairsCommand(primaryTaskId, nonResizeableTaskId, pair = true))
- nonResizeableApp?.run { wmHelper.waitForFullScreenApp(nonResizeableApp.component) }
+ val waitConditions = mutableListOf(
+ WindowManagerConditionsFactory.isWindowVisible(primaryApp.component),
+ WindowManagerConditionsFactory.isLayerVisible(primaryApp.component),
+ WindowManagerConditionsFactory.isAppTransitionIdle(Display.DEFAULT_DISPLAY))
+
+ nonResizeableApp?.let {
+ waitConditions.add(
+ WindowManagerConditionsFactory.isWindowVisible(nonResizeableApp.component))
+ waitConditions.add(
+ WindowManagerConditionsFactory.isLayerVisible(nonResizeableApp.component))
+ }
+ wmHelper.waitFor(*waitConditions.toTypedArray())
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt
index 0f00ede..cc5b9f9 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt
@@ -62,7 +62,7 @@
if (wmHelper == null) {
device.waitForIdle()
} else {
- require(wmHelper.waitImeShown()) { "IME did not appear" }
+ wmHelper.waitImeShown()
}
}
@@ -79,7 +79,7 @@
if (wmHelper == null) {
uiDevice.waitForIdle()
} else {
- require(wmHelper.waitImeGone()) { "IME did did not close" }
+ wmHelper.waitImeGone()
}
} else {
// While pressing the back button should close the IME on TV as well, it may also lead
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
index 7e232ea..e9d438a 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
@@ -58,17 +58,27 @@
}
}
- /** {@inheritDoc} */
- override fun launchViaIntent(
+ /**
+ * Launches the app through an intent instead of interacting with the launcher and waits
+ * until the app window is in PIP mode
+ */
+ @JvmOverloads
+ fun launchViaIntentAndWaitForPip(
wmHelper: WindowManagerStateHelper,
- expectedWindowName: String,
- action: String?,
+ expectedWindowName: String = "",
+ action: String? = null,
stringExtras: Map<String, String>
) {
- super.launchViaIntent(wmHelper, expectedWindowName, action, stringExtras)
- wmHelper.waitPipShown()
+ launchViaIntentAndWaitShown(wmHelper, expectedWindowName, action, stringExtras,
+ waitConditions = arrayOf(WindowManagerStateHelper.pipShownCondition))
}
+ /**
+ * Expand the PIP window back to full screen via intent and wait until the app is visible
+ */
+ fun exitPipToFullScreenViaIntent(wmHelper: WindowManagerStateHelper) =
+ launchViaIntentAndWaitShown(wmHelper)
+
private fun focusOnObject(selector: BySelector): Boolean {
// We expect all the focusable UI elements to be arranged in a way so that it is possible
// to "cycle" over all them by clicking the D-Pad DOWN button, going back up to "the top"
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
index f2c5093..274d34b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
@@ -64,7 +64,18 @@
* Defines the transition used to run the test
*/
override val transition: FlickerBuilder.() -> Unit
- get() = buildTransition(eachRun = true, stringExtras = emptyMap()) {
+ get() = {
+ setupAndTeardown(this)
+ setup {
+ eachRun {
+ pipApp.launchViaIntent(wmHelper)
+ }
+ }
+ teardown {
+ eachRun {
+ pipApp.exit(wmHelper)
+ }
+ }
transitions {
pipApp.clickEnterPipButton(wmHelper)
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt
index 4f98b70..e2d0834 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt
@@ -74,7 +74,7 @@
// This will bring PipApp to fullscreen
pipApp.expandPipWindowToApp(wmHelper)
// Wait until the other app is no longer visible
- wmHelper.waitForSurfaceAppeared(testApp.component.toWindowName())
+ wmHelper.waitForSurfaceAppeared(testApp.component)
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt
index e00d749..3fe6f02 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt
@@ -72,9 +72,9 @@
}
transitions {
// This will bring PipApp to fullscreen
- pipApp.launchViaIntent(wmHelper)
+ pipApp.exitPipToFullScreenViaIntent(wmHelper)
// Wait until the other app is no longer visible
- wmHelper.waitForSurfaceAppeared(testApp.component.toWindowName())
+ wmHelper.waitForWindowSurfaceDisappeared(testApp.component)
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
index bb66f7b..8d542c8 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
@@ -56,13 +56,6 @@
.sendBroadcast(createIntentWithAction(broadcastAction))
}
- fun requestOrientationForPip(orientation: Int) {
- instrumentation.context.sendBroadcast(
- createIntentWithAction(Components.PipActivity.ACTION_SET_REQUESTED_ORIENTATION)
- .putExtra(Components.PipActivity.EXTRA_PIP_ORIENTATION, orientation.toString())
- )
- }
-
companion object {
// Corresponds to ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
@JvmStatic
@@ -122,15 +115,14 @@
setup {
test {
- removeAllTasksButHome()
if (!eachRun) {
- pipApp.launchViaIntent(wmHelper, stringExtras = stringExtras)
+ pipApp.launchViaIntentAndWaitForPip(wmHelper, stringExtras = stringExtras)
wmHelper.waitPipShown()
}
}
eachRun {
if (eachRun) {
- pipApp.launchViaIntent(wmHelper, stringExtras = stringExtras)
+ pipApp.launchViaIntentAndWaitForPip(wmHelper, stringExtras = stringExtras)
wmHelper.waitPipShown()
}
}
@@ -145,7 +137,6 @@
if (!eachRun) {
pipApp.exit(wmHelper)
}
- removeAllTasksButHome()
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
index d65388b..f7384e74 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
@@ -25,11 +25,14 @@
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group4
import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.helpers.WindowUtils
import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome
import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE
+import com.android.wm.shell.flicker.testapp.Components
import com.android.wm.shell.flicker.testapp.Components.FixedActivity.EXTRA_FIXED_ORIENTATION
-import com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_ENTER_PIP
import org.junit.Assume
import org.junit.Before
import org.junit.FixMethodOrder
@@ -39,7 +42,7 @@
import org.junit.runners.Parameterized
/**
- * Test Pip with orientation changes.
+ * Test exiting Pip with orientation changes.
* To run this test: `atest WMShellFlickerTests:SetRequestedOrientationWhilePinnedTest`
*/
@RequiresDevice
@@ -61,30 +64,41 @@
override val transition: FlickerBuilder.() -> Unit
get() = {
- setupAndTeardown(this)
-
setup {
+ test {
+ removeAllTasksButHome()
+ device.wakeUpAndGoToHomeScreen()
+ }
eachRun {
- // Launch the PiP activity fixed as landscape
+ // Launch the PiP activity fixed as landscape.
pipApp.launchViaIntent(wmHelper, stringExtras = mapOf(
- EXTRA_FIXED_ORIENTATION to ORIENTATION_LANDSCAPE.toString(),
- EXTRA_ENTER_PIP to "true"))
+ EXTRA_FIXED_ORIENTATION to ORIENTATION_LANDSCAPE.toString()))
+ // Enter PiP.
+ broadcastActionTrigger.doAction(Components.PipActivity.ACTION_ENTER_PIP)
+ wmHelper.waitPipShown()
+ wmHelper.waitForRotation(Surface.ROTATION_0)
+ wmHelper.waitForAppTransitionIdle()
+ // System bar may fade out during fixed rotation.
+ wmHelper.waitForNavBarStatusBarVisible()
}
}
teardown {
eachRun {
pipApp.exit(wmHelper)
+ setRotation(Surface.ROTATION_0)
+ }
+ test {
+ removeAllTasksButHome()
}
}
transitions {
- // Request that the orientation is set to landscape
- broadcastActionTrigger.requestOrientationForPip(ORIENTATION_LANDSCAPE)
-
- // Launch the activity back into fullscreen and
- // ensure that it is now in landscape
+ // Launch the activity back into fullscreen and ensure that it is now in landscape
pipApp.launchViaIntent(wmHelper)
wmHelper.waitForFullScreenApp(pipApp.component)
wmHelper.waitForRotation(Surface.ROTATION_90)
+ wmHelper.waitForAppTransitionIdle()
+ // System bar may fade out during fixed rotation.
+ wmHelper.waitForNavBarStatusBarVisible()
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTestShellTransit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTestShellTransit.kt
index 36e2804..8d764a8 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTestShellTransit.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTestShellTransit.kt
@@ -29,6 +29,10 @@
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
+/**
+ * Test exiting Pip with orientation changes.
+ * To run this test: `atest WMShellFlickerTests:SetRequestedOrientationWhilePinnedTestShellTransit`
+ */
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java
index 90f898a..0059846 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java
@@ -29,6 +29,7 @@
import androidx.test.filters.SmallTest;
+import com.android.wm.shell.R;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.common.DisplayLayout;
@@ -72,16 +73,16 @@
private void initializeMockResources() {
final TestableResources res = mContext.getOrCreateTestableResources();
res.addOverride(
- com.android.internal.R.dimen.config_pictureInPictureDefaultAspectRatio,
+ R.dimen.config_pictureInPictureDefaultAspectRatio,
DEFAULT_ASPECT_RATIO);
res.addOverride(
- com.android.internal.R.integer.config_defaultPictureInPictureGravity,
+ R.integer.config_defaultPictureInPictureGravity,
Gravity.END | Gravity.BOTTOM);
res.addOverride(
- com.android.internal.R.dimen.default_minimal_size_pip_resizable_task,
+ R.dimen.default_minimal_size_pip_resizable_task,
DEFAULT_MIN_EDGE_SIZE);
res.addOverride(
- com.android.internal.R.string.config_defaultPictureInPictureScreenEdgeInsets,
+ R.string.config_defaultPictureInPictureScreenEdgeInsets,
"16x16");
res.addOverride(
com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio,
@@ -107,7 +108,7 @@
public void onConfigurationChanged_reloadResources() {
final float newDefaultAspectRatio = (DEFAULT_ASPECT_RATIO + MAX_ASPECT_RATIO) / 2;
final TestableResources res = mContext.getOrCreateTestableResources();
- res.addOverride(com.android.internal.R.dimen.config_pictureInPictureDefaultAspectRatio,
+ res.addOverride(R.dimen.config_pictureInPictureDefaultAspectRatio,
newDefaultAspectRatio);
mPipBoundsAlgorithm.onConfigurationChanged(mContext);
@@ -463,7 +464,7 @@
private void overrideDefaultAspectRatio(float aspectRatio) {
final TestableResources res = mContext.getOrCreateTestableResources();
res.addOverride(
- com.android.internal.R.dimen.config_pictureInPictureDefaultAspectRatio,
+ R.dimen.config_pictureInPictureDefaultAspectRatio,
aspectRatio);
mPipBoundsAlgorithm.onConfigurationChanged(mContext);
}
@@ -471,7 +472,7 @@
private void overrideDefaultStackGravity(int stackGravity) {
final TestableResources res = mContext.getOrCreateTestableResources();
res.addOverride(
- com.android.internal.R.integer.config_defaultPictureInPictureGravity,
+ R.integer.config_defaultPictureInPictureGravity,
stackGravity);
mPipBoundsAlgorithm.onConfigurationChanged(mContext);
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
index dda1a82..85527c8 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
@@ -18,6 +18,7 @@
import static android.view.Display.DEFAULT_DISPLAY;
import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER;
+
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -51,6 +52,7 @@
final SurfaceControl leash = createMockSurface();
SplitLayout out = mock(SplitLayout.class);
doReturn(dividerBounds).when(out).getDividerBounds();
+ doReturn(dividerBounds).when(out).getRefDividerBounds();
doReturn(leash).when(out).getDividerLeash();
return out;
}
diff --git a/location/java/android/location/SatellitePvt.java b/location/java/android/location/SatellitePvt.java
index f140c68..f3e1508 100644
--- a/location/java/android/location/SatellitePvt.java
+++ b/location/java/android/location/SatellitePvt.java
@@ -144,8 +144,8 @@
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 @@
@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 @@
mClockInfo = clockInfo;
mIonoDelayMeters = ionoDelayMeters;
mTropoDelayMeters = tropoDelayMeters;
- mTimeOfClock = timeOfClock;
- mTimeOfEphemeris = timeOfEphemeris;
+ mTimeOfClockSeconds = timeOfClockSeconds;
+ mTimeOfEphemerisSeconds = timeOfEphemerisSeconds;
mIssueOfDataClock = issueOfDataClock;
mIssueOfDataEphemeris = issueOfDataEphemeris;
mEphemerisSource = ephemerisSource;
@@ -545,31 +545,31 @@
}
/**
- * 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 @@
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 @@
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 @@
+ ", ClockInfo=" + mClockInfo
+ ", IonoDelayMeters=" + mIonoDelayMeters
+ ", TropoDelayMeters=" + mTropoDelayMeters
- + ", TimeOfClock=" + mTimeOfClock
- + ", TimeOfEphemeris=" + mTimeOfEphemeris
+ + ", TimeOfClockSeconds=" + mTimeOfClockSeconds
+ + ", TimeOfEphemerisSeconds=" + mTimeOfEphemerisSeconds
+ ", IssueOfDataClock=" + mIssueOfDataClock
+ ", IssueOfDataEphemeris=" + mIssueOfDataEphemeris
+ ", EphemerisSource=" + mEphemerisSource
@@ -709,8 +709,8 @@
@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 @@
*
* <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 @@
*
* <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 @@
@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/ImageWriter.java b/media/java/android/media/ImageWriter.java
index e0f04a1..9f52bf1 100644
--- a/media/java/android/media/ImageWriter.java
+++ b/media/java/android/media/ImageWriter.java
@@ -108,7 +108,6 @@
private long mUsage = HardwareBuffer.USAGE_CPU_WRITE_OFTEN;
private @HardwareBuffer.Format int mHardwareBufferFormat;
private @NamedDataSpace int mDataSpace;
- private boolean mUseLegacyImageFormat;
// Field below is used by native code, do not access or modify.
private int mWriterFormat;
@@ -257,7 +256,6 @@
+ ", maxImages: " + maxImages);
}
- mUseLegacyImageFormat = useLegacyImageFormat;
// Note that the underlying BufferQueue is working in synchronous mode
// to avoid dropping any buffers.
mNativeContext = nativeInit(new WeakReference<>(this), surface, maxImages, width, height,
@@ -334,12 +332,21 @@
int hardwareBufferFormat, int dataSpace, int width, int height, long usage) {
mMaxImages = maxImages;
mUsage = usage;
- mHardwareBufferFormat = hardwareBufferFormat;
- mDataSpace = dataSpace;
- int publicFormat = PublicFormatUtils.getPublicFormat(hardwareBufferFormat, dataSpace);
+ int imageFormat;
+ // if useSurfaceImageFormatInfo is true, imageFormat will be set to UNKNOWN
+ // and retrieve corresponding hardwareBufferFormat and dataSpace here.
+ if (useSurfaceImageFormatInfo) {
+ imageFormat = ImageFormat.UNKNOWN;
+ mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat);
+ mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat);
+ } else {
+ imageFormat = PublicFormatUtils.getPublicFormat(hardwareBufferFormat, dataSpace);
+ mHardwareBufferFormat = hardwareBufferFormat;
+ mDataSpace = dataSpace;
+ }
initializeImageWriter(surface, maxImages, useSurfaceImageFormatInfo, false,
- publicFormat, hardwareBufferFormat, dataSpace, width, height, usage);
+ imageFormat, hardwareBufferFormat, dataSpace, width, height, usage);
}
/**
@@ -884,27 +891,17 @@
private @HardwareBuffer.Format int mHardwareBufferFormat = HardwareBuffer.RGBA_8888;
private @NamedDataSpace int mDataSpace = DataSpace.DATASPACE_UNKNOWN;
private boolean mUseSurfaceImageFormatInfo = true;
- // set this as true temporarily now as a workaround to get correct format
- // when using surface format by default without overriding the image format
- // in the builder pattern
- private boolean mUseLegacyImageFormat = true;
+ private boolean mUseLegacyImageFormat = false;
/**
* Constructs a new builder for {@link ImageWriter}.
*
- * <p>Uses {@code surface} input parameter to retrieve image format, hal format
- * and hal dataspace value for default. </p>
- *
* @param surface The destination Surface this writer produces Image data into.
*
* @throws IllegalArgumentException if the surface is already abandoned.
*/
public Builder(@NonNull Surface surface) {
mSurface = surface;
- // retrieve format from surface
- mImageFormat = SurfaceUtils.getSurfaceFormat(surface);
- mDataSpace = SurfaceUtils.getSurfaceDataspace(surface);
- mHardwareBufferFormat = PublicFormatUtils.getHalFormat(mImageFormat);
}
/**
@@ -1058,11 +1055,6 @@
mWidth = writer.mWidth;
mHeight = writer.mHeight;
mDataSpace = writer.mDataSpace;
-
- if (!mOwner.mUseLegacyImageFormat) {
- mFormat = PublicFormatUtils.getPublicFormat(
- mOwner.mHardwareBufferFormat, mDataSpace);
- }
}
@Override
@@ -1083,7 +1075,7 @@
public int getFormat() {
throwISEIfImageIsInvalid();
- if (mOwner.mUseLegacyImageFormat && mFormat == -1) {
+ if (mFormat == -1) {
mFormat = nativeGetFormat(mDataSpace);
}
return mFormat;
diff --git a/packages/CompanionDeviceManager/Android.bp b/packages/CompanionDeviceManager/Android.bp
index 6ded1637..9f5bfd4 100644
--- a/packages/CompanionDeviceManager/Android.bp
+++ b/packages/CompanionDeviceManager/Android.bp
@@ -34,6 +34,7 @@
android_app {
name: "CompanionDeviceManager",
defaults: ["platform_app_defaults"],
+ certificate: "platform",
srcs: ["src/**/*.java"],
static_libs: [
diff --git a/packages/CompanionDeviceManager/AndroidManifest.xml b/packages/CompanionDeviceManager/AndroidManifest.xml
index 06f2d9d..8b5d214 100644
--- a/packages/CompanionDeviceManager/AndroidManifest.xml
+++ b/packages/CompanionDeviceManager/AndroidManifest.xml
@@ -31,6 +31,7 @@
<uses-permission android:name="android.permission.RADIO_SCAN_WITHOUT_LOCATION"/>
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
<uses-permission android:name="android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS"/>
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"/>
<application
android:allowClearUserData="true"
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
index b51d310..a6a8fcf 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
@@ -37,6 +37,7 @@
import android.companion.CompanionDeviceManager;
import android.companion.IAssociationRequestCallback;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.net.MacAddress;
import android.os.Bundle;
import android.os.Handler;
@@ -71,6 +72,9 @@
private static final String EXTRA_ASSOCIATION_REQUEST = "association_request";
private static final String EXTRA_RESULT_RECEIVER = "result_receiver";
+ // Activity result: Internal Error.
+ private static final int RESULT_INTERNAL_ERROR = 2;
+
// AssociationRequestsProcessor -> UI
private static final int RESULT_CODE_ASSOCIATION_CREATED = 0;
private static final String EXTRA_ASSOCIATION = "association";
@@ -191,6 +195,20 @@
private void initUI() {
if (DEBUG) Log.d(TAG, "initUI(), request=" + mRequest);
+ final String packageName = mRequest.getPackageName();
+ final int userId = mRequest.getUserId();
+ final CharSequence appLabel;
+
+ try {
+ appLabel = getApplicationLabel(this, packageName, userId);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(TAG, "Package u" + userId + "/" + packageName + " not found.");
+
+ CompanionDeviceDiscoveryService.stop(this);
+ setResultAndFinish(null, RESULT_INTERNAL_ERROR);
+ return;
+ }
+
setContentView(R.layout.activity_confirmation);
mTitle = findViewById(R.id.title);
@@ -203,8 +221,6 @@
mButtonAllow.setOnClickListener(this::onPositiveButtonClick);
findViewById(R.id.btn_negative).setOnClickListener(this::onNegativeButtonClick);
- final CharSequence appLabel = getApplicationLabel(this, mRequest.getPackageName());
-
if (mRequest.isSelfManaged()) {
initUiForSelfManagedAssociation(appLabel);
} else if (mRequest.isSingleDevice()) {
@@ -257,7 +273,7 @@
if (DEBUG) Log.i(TAG, "onAssociationCreated(), association=" + association);
// Don't need to notify the app, CdmService has already done that. Just finish.
- setResultAndFinish(association);
+ setResultAndFinish(association, RESULT_OK);
}
private void cancel(boolean discoveryTimeout) {
@@ -284,10 +300,10 @@
}
// ... then set result and finish ("sending" onActivityResult()).
- setResultAndFinish(null);
+ setResultAndFinish(null, RESULT_CANCELED);
}
- private void setResultAndFinish(@Nullable AssociationInfo association) {
+ private void setResultAndFinish(@Nullable AssociationInfo association, int resultCode) {
if (DEBUG) Log.i(TAG, "setResultAndFinish(), association=" + association);
final Intent data = new Intent();
@@ -297,7 +313,7 @@
data.putExtra(CompanionDeviceManager.EXTRA_DEVICE, mSelectedDevice.getDevice());
}
}
- setResult(association != null ? RESULT_OK : RESULT_CANCELED, data);
+ setResult(resultCode, data);
finish();
}
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/Utils.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/Utils.java
index eab421e..e3e563d 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/Utils.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/Utils.java
@@ -50,14 +50,13 @@
}
static @NonNull CharSequence getApplicationLabel(
- @NonNull Context context, @NonNull String packageName) {
+ @NonNull Context context, @NonNull String packageName, int userId)
+ throws PackageManager.NameNotFoundException {
final PackageManager packageManager = context.getPackageManager();
- final ApplicationInfo appInfo;
- try {
- appInfo = packageManager.getApplicationInfo(packageName, 0);
- } catch (PackageManager.NameNotFoundException e) {
- throw new RuntimeException(e);
- }
+
+ final ApplicationInfo appInfo = packageManager.getApplicationInfoAsUser(
+ packageName, PackageManager.ApplicationInfoFlags.of(0), userId);
+
return packageManager.getApplicationLabel(appInfo);
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/devicestate/AndroidSecureSettings.java b/packages/SettingsLib/src/com/android/settingslib/devicestate/AndroidSecureSettings.java
new file mode 100644
index 0000000..8aee576
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/devicestate/AndroidSecureSettings.java
@@ -0,0 +1,54 @@
+/*
+ * 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.settingslib.devicestate;
+
+import android.content.ContentResolver;
+import android.database.ContentObserver;
+import android.provider.Settings;
+
+/**
+ * Implementation of {@link SecureSettings} that uses Android's {@link Settings.Secure}
+ * implementation.
+ */
+class AndroidSecureSettings implements SecureSettings {
+
+ private final ContentResolver mContentResolver;
+
+ AndroidSecureSettings(ContentResolver contentResolver) {
+ mContentResolver = contentResolver;
+ }
+
+ @Override
+ public void putStringForUser(String name, String value, int userHandle) {
+ Settings.Secure.putStringForUser(mContentResolver, name, value, userHandle);
+ }
+
+ @Override
+ public String getStringForUser(String name, int userHandle) {
+ return Settings.Secure.getStringForUser(mContentResolver, name, userHandle);
+ }
+
+ @Override
+ public void registerContentObserver(String name, boolean notifyForDescendants,
+ ContentObserver observer, int userHandle) {
+ mContentResolver.registerContentObserver(
+ Settings.Secure.getUriFor(name),
+ notifyForDescendants,
+ observer,
+ userHandle);
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManager.java b/packages/SettingsLib/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManager.java
index afd3626..4ed7e19 100644
--- a/packages/SettingsLib/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManager.java
@@ -22,8 +22,10 @@
import android.content.ContentResolver;
import android.content.Context;
+import android.content.res.Resources;
import android.database.ContentObserver;
import android.os.Handler;
+import android.os.Looper;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
@@ -33,7 +35,10 @@
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
+import java.util.ArrayList;
import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
import java.util.Set;
/**
@@ -47,32 +52,44 @@
private static DeviceStateRotationLockSettingsManager sSingleton;
- private final ContentResolver mContentResolver;
- private final String[] mDeviceStateRotationLockDefaults;
- private final Handler mMainHandler = Handler.getMain();
+ private final Handler mMainHandler = new Handler(Looper.getMainLooper());
private final Set<DeviceStateRotationLockSettingsListener> mListeners = new HashSet<>();
+ private final SecureSettings mSecureSettings;
+ private String[] mDeviceStateRotationLockDefaults;
private SparseIntArray mDeviceStateRotationLockSettings;
private SparseIntArray mDeviceStateRotationLockFallbackSettings;
+ private String mLastSettingValue;
+ private List<SettableDeviceState> mSettableDeviceStates;
- private DeviceStateRotationLockSettingsManager(Context context) {
- mContentResolver = context.getContentResolver();
+ @VisibleForTesting
+ DeviceStateRotationLockSettingsManager(Context context, SecureSettings secureSettings) {
+ this.mSecureSettings = secureSettings;
mDeviceStateRotationLockDefaults =
context.getResources()
.getStringArray(R.array.config_perDeviceStateRotationLockDefaults);
loadDefaults();
initializeInMemoryMap();
- listenForSettingsChange(context);
+ listenForSettingsChange();
}
/** Returns a singleton instance of this class */
public static synchronized DeviceStateRotationLockSettingsManager getInstance(Context context) {
if (sSingleton == null) {
+ Context applicationContext = context.getApplicationContext();
+ ContentResolver contentResolver = applicationContext.getContentResolver();
+ SecureSettings secureSettings = new AndroidSecureSettings(contentResolver);
sSingleton =
- new DeviceStateRotationLockSettingsManager(context.getApplicationContext());
+ new DeviceStateRotationLockSettingsManager(applicationContext, secureSettings);
}
return sSingleton;
}
+ /** Resets the singleton instance of this class. Only used for testing. */
+ @VisibleForTesting
+ public static synchronized void resetInstance() {
+ sSingleton = null;
+ }
+
/** Returns true if device-state based rotation lock settings are enabled. */
public static boolean isDeviceStateRotationLockEnabled(Context context) {
return context.getResources()
@@ -81,11 +98,11 @@
> 0;
}
- private void listenForSettingsChange(Context context) {
- context.getContentResolver()
+ private void listenForSettingsChange() {
+ mSecureSettings
.registerContentObserver(
- Settings.Secure.getUriFor(Settings.Secure.DEVICE_STATE_ROTATION_LOCK),
- /* notifyForDescendents= */ false, //NOTYPO
+ Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
+ /* notifyForDescendants= */ false,
new ContentObserver(mMainHandler) {
@Override
public void onChange(boolean selfChange) {
@@ -180,10 +197,15 @@
return true;
}
+ /** Returns a list of device states and their respective auto-rotation setting availability. */
+ public List<SettableDeviceState> getSettableDeviceStates() {
+ // Returning a copy to make sure that nothing outside can mutate our internal list.
+ return new ArrayList<>(mSettableDeviceStates);
+ }
+
private void initializeInMemoryMap() {
String serializedSetting =
- Settings.Secure.getStringForUser(
- mContentResolver,
+ mSecureSettings.getStringForUser(
Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
UserHandle.USER_CURRENT);
if (TextUtils.isEmpty(serializedSetting)) {
@@ -215,6 +237,17 @@
}
}
+ /**
+ * Resets the state of the class and saved settings back to the default values provided by the
+ * resources config.
+ */
+ @VisibleForTesting
+ public void resetStateForTesting(Resources resources) {
+ mDeviceStateRotationLockDefaults =
+ resources.getStringArray(R.array.config_perDeviceStateRotationLockDefaults);
+ fallbackOnDefaults();
+ }
+
private void fallbackOnDefaults() {
loadDefaults();
persistSettings();
@@ -222,11 +255,7 @@
private void persistSettings() {
if (mDeviceStateRotationLockSettings.size() == 0) {
- Settings.Secure.putStringForUser(
- mContentResolver,
- Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
- /* value= */ "",
- UserHandle.USER_CURRENT);
+ persistSettingIfChanged(/* newSettingValue= */ "");
return;
}
@@ -243,14 +272,22 @@
.append(SEPARATOR_REGEX)
.append(mDeviceStateRotationLockSettings.valueAt(i));
}
- Settings.Secure.putStringForUser(
- mContentResolver,
+ persistSettingIfChanged(stringBuilder.toString());
+ }
+
+ private void persistSettingIfChanged(String newSettingValue) {
+ if (TextUtils.equals(mLastSettingValue, newSettingValue)) {
+ return;
+ }
+ mLastSettingValue = newSettingValue;
+ mSecureSettings.putStringForUser(
Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
- stringBuilder.toString(),
+ /* value= */ newSettingValue,
UserHandle.USER_CURRENT);
}
private void loadDefaults() {
+ mSettableDeviceStates = new ArrayList<>(mDeviceStateRotationLockDefaults.length);
mDeviceStateRotationLockSettings = new SparseIntArray(
mDeviceStateRotationLockDefaults.length);
mDeviceStateRotationLockFallbackSettings = new SparseIntArray(1);
@@ -271,6 +308,8 @@
+ values.length);
}
}
+ boolean isSettable = rotationLockSetting != DEVICE_STATE_ROTATION_LOCK_IGNORED;
+ mSettableDeviceStates.add(new SettableDeviceState(deviceState, isSettable));
mDeviceStateRotationLockSettings.put(deviceState, rotationLockSetting);
} catch (NumberFormatException e) {
Log.wtf(TAG, "Error parsing settings entry. Entry was: " + entry, e);
@@ -300,4 +339,38 @@
/** Called whenever the settings have changed. */
void onSettingsChanged();
}
+
+ /** Represents a device state and whether it has an auto-rotation setting. */
+ public static class SettableDeviceState {
+ private final int mDeviceState;
+ private final boolean mIsSettable;
+
+ SettableDeviceState(int deviceState, boolean isSettable) {
+ mDeviceState = deviceState;
+ mIsSettable = isSettable;
+ }
+
+ /** Returns the device state associated with this object. */
+ public int getDeviceState() {
+ return mDeviceState;
+ }
+
+ /** Returns whether there is an auto-rotation setting for this device state. */
+ public boolean isSettable() {
+ return mIsSettable;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof SettableDeviceState)) return false;
+ SettableDeviceState that = (SettableDeviceState) o;
+ return mDeviceState == that.mDeviceState && mIsSettable == that.mIsSettable;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mDeviceState, mIsSettable);
+ }
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/devicestate/SecureSettings.java b/packages/SettingsLib/src/com/android/settingslib/devicestate/SecureSettings.java
new file mode 100644
index 0000000..1052873
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/devicestate/SecureSettings.java
@@ -0,0 +1,30 @@
+/*
+ * 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.settingslib.devicestate;
+
+import android.database.ContentObserver;
+
+/** Minimal wrapper interface around {@link android.provider.Settings.Secure} for easier testing. */
+interface SecureSettings {
+
+ void putStringForUser(String name, String value, int userHandle);
+
+ String getStringForUser(String name, int userHandle);
+
+ void registerContentObserver(String name, boolean notifyForDescendants,
+ ContentObserver settingsObserver, int userHandle);
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/AvatarPickerActivity.java b/packages/SettingsLib/src/com/android/settingslib/users/AvatarPickerActivity.java
index 93be66a..1e1dfae 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/AvatarPickerActivity.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/AvatarPickerActivity.java
@@ -81,6 +81,7 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ setTheme(R.style.SudThemeGlifV3_DayNight);
ThemeHelper.trySetDynamicColor(this);
setContentView(R.layout.avatar_picker);
setUpButtons();
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java
new file mode 100644
index 0000000..81006dd
--- /dev/null
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java
@@ -0,0 +1,120 @@
+/*
+ * 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.settingslib.devicestate;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.database.ContentObserver;
+import android.os.UserHandle;
+import android.provider.Settings;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.R;
+import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager.SettableDeviceState;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.List;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DeviceStateRotationLockSettingsManagerTest {
+
+ @Mock private Context mMockContext;
+ @Mock private Resources mMockResources;
+
+ private DeviceStateRotationLockSettingsManager mManager;
+ private int mNumSettingsChanges = 0;
+ private final ContentObserver mContentObserver = new ContentObserver(null) {
+ @Override
+ public void onChange(boolean selfChange) {
+ mNumSettingsChanges++;
+ }
+ };
+ private final FakeSecureSettings mFakeSecureSettings = new FakeSecureSettings();
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ Context context = InstrumentationRegistry.getTargetContext();
+ when(mMockContext.getApplicationContext()).thenReturn(mMockContext);
+ when(mMockContext.getResources()).thenReturn(mMockResources);
+ when(mMockContext.getContentResolver()).thenReturn(context.getContentResolver());
+ mFakeSecureSettings.registerContentObserver(
+ Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
+ /* notifyForDescendents= */ false, //NOTYPO
+ mContentObserver,
+ UserHandle.USER_CURRENT);
+ mManager = new DeviceStateRotationLockSettingsManager(context, mFakeSecureSettings);
+ }
+
+ @Test
+ public void initialization_settingsAreChangedOnce() {
+ assertThat(mNumSettingsChanges).isEqualTo(1);
+ }
+
+ @Test
+ public void updateSetting_multipleTimes_sameValue_settingsAreChangedOnlyOnce() {
+ mNumSettingsChanges = 0;
+
+ mManager.updateSetting(/* deviceState= */ 1, /* rotationLocked= */ true);
+ mManager.updateSetting(/* deviceState= */ 1, /* rotationLocked= */ true);
+ mManager.updateSetting(/* deviceState= */ 1, /* rotationLocked= */ true);
+
+ assertThat(mNumSettingsChanges).isEqualTo(1);
+ }
+
+ @Test
+ public void updateSetting_multipleTimes_differentValues_settingsAreChangedMultipleTimes() {
+ mNumSettingsChanges = 0;
+
+ mManager.updateSetting(/* deviceState= */ 1, /* rotationLocked= */ true);
+ mManager.updateSetting(/* deviceState= */ 1, /* rotationLocked= */ false);
+ mManager.updateSetting(/* deviceState= */ 1, /* rotationLocked= */ true);
+
+ assertThat(mNumSettingsChanges).isEqualTo(3);
+ }
+
+ @Test
+ public void getSettableDeviceStates_returnsExpectedValuesInOriginalOrder() {
+ when(mMockResources.getStringArray(
+ R.array.config_perDeviceStateRotationLockDefaults)).thenReturn(
+ new String[]{"2:2", "4:0", "1:1", "0:0"});
+
+ List<SettableDeviceState> settableDeviceStates =
+ DeviceStateRotationLockSettingsManager.getInstance(
+ mMockContext).getSettableDeviceStates();
+
+ assertThat(settableDeviceStates).containsExactly(
+ new SettableDeviceState(/* deviceState= */ 2, /* isSettable= */ true),
+ new SettableDeviceState(/* deviceState= */ 4, /* isSettable= */ false),
+ new SettableDeviceState(/* deviceState= */ 1, /* isSettable= */ true),
+ new SettableDeviceState(/* deviceState= */ 0, /* isSettable= */ false)
+ ).inOrder();
+ }
+}
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/FakeSecureSettings.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/FakeSecureSettings.java
new file mode 100644
index 0000000..91baa68
--- /dev/null
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/FakeSecureSettings.java
@@ -0,0 +1,60 @@
+/*
+ * 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.settingslib.devicestate;
+
+import android.database.ContentObserver;
+import android.util.Pair;
+
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/** Fake implementation of {@link SecureSettings} that stores everything in memory. */
+class FakeSecureSettings implements SecureSettings {
+
+ private final Map<SettingsKey, String> mValues = new HashMap<>();
+ private final Multimap<SettingsKey, ContentObserver> mContentObservers = HashMultimap.create();
+
+ @Override
+ public void putStringForUser(String name, String value, int userHandle) {
+ SettingsKey settingsKey = new SettingsKey(userHandle, name);
+ mValues.put(settingsKey, value);
+ for (ContentObserver observer : mContentObservers.get(settingsKey)) {
+ observer.onChange(/* selfChange= */ false);
+ }
+ }
+
+ @Override
+ public String getStringForUser(String name, int userHandle) {
+ return mValues.getOrDefault(new SettingsKey(userHandle, name), "");
+ }
+
+ @Override
+ public void registerContentObserver(String name, boolean notifyForDescendants,
+ ContentObserver settingsObserver, int userHandle) {
+ mContentObservers.put(new SettingsKey(userHandle, name), settingsObserver);
+ }
+
+ private static class SettingsKey extends Pair<Integer, String> {
+
+ SettingsKey(Integer userHandle, String settingName) {
+ super(userHandle, settingName);
+ }
+ }
+}
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/OWNERS b/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/OWNERS
new file mode 100644
index 0000000..98f4123
--- /dev/null
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/OWNERS
@@ -0,0 +1,3 @@
+# Default reviewers for this and subdirectories.
+alexflo@google.com
+chrisgollner@google.com
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/enterprise/BiometricActionDisabledByAdminControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/enterprise/BiometricActionDisabledByAdminControllerTest.java
index 06b6fc8..b2258e1 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/enterprise/BiometricActionDisabledByAdminControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/enterprise/BiometricActionDisabledByAdminControllerTest.java
@@ -80,8 +80,8 @@
assertEquals(Settings.ACTION_MANAGE_SUPERVISOR_RESTRICTED_SETTING,
intentCaptor.getValue().getAction());
assertEquals(Settings.SUPERVISOR_VERIFICATION_SETTING_BIOMETRICS,
- intentCaptor.getValue().getStringExtra(
- Settings.EXTRA_SUPERVISOR_RESTRICTED_SETTING_KEY));
+ intentCaptor.getValue().getIntExtra(
+ Settings.EXTRA_SUPERVISOR_RESTRICTED_SETTING_KEY, -1));
assertEquals(componentName.getPackageName(), intentCaptor.getValue().getPackage());
}
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index 8e35ee96..c7673aa 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 @@
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 5f549fd..42aa205 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 @@
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/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index f0b180e..c0e2b2e 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -588,8 +588,14 @@
<uses-permission android:name="android.permission.MANAGE_HOTWORD_DETECTION" />
<uses-permission android:name="android.permission.BIND_HOTWORD_DETECTION_SERVICE" />
+ <!-- Permission required for CTS test - KeyguardLockedStateApiTest -->
+ <uses-permission android:name="android.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE" />
+
<uses-permission android:name="android.permission.MANAGE_APP_HIBERNATION"/>
+ <!-- Permission required for CTS test - MediaCodecResourceTest -->
+ <uses-permission android:name="android.permission.MEDIA_RESOURCE_OVERRIDE_PID" />
+
<!-- Permission required for CTS test - ResourceObserverNativeTest -->
<uses-permission android:name="android.permission.REGISTER_MEDIA_RESOURCE_OBSERVER" />
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index ad6074a..7f8b2f5 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 -->
@@ -311,6 +311,9 @@
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
<uses-permission android:name="android.permission.SUPPRESS_CLIPBOARD_ACCESS_NOTIFICATION" />
+ <!-- To change system captions state -->
+ <uses-permission android:name="android.permission.SET_SYSTEM_AUDIO_CAPTION" />
+
<protected-broadcast android:name="com.android.settingslib.action.REGISTER_SLICE_RECEIVER" />
<protected-broadcast android:name="com.android.settingslib.action.UNREGISTER_SLICE_RECEIVER" />
<protected-broadcast android:name="com.android.settings.flashlight.action.FLASHLIGHT_CHANGED" />
@@ -767,22 +770,6 @@
</intent-filter>
</activity>
- <activity android:name=".chooser.ChooserActivity"
- android:theme="@*android:style/Theme.NoDisplay"
- android:finishOnCloseSystemDialogs="true"
- android:excludeFromRecents="true"
- android:documentLaunchMode="never"
- android:relinquishTaskIdentity="true"
- android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
- android:process=":ui"
- android:visibleToInstantApps="true"
- android:exported="true">
- <intent-filter>
- <action android:name="android.intent.action.CHOOSER" />
- <category android:name="android.intent.category.VOICE" />
- </intent-filter>
- </activity>
-
<activity android:name=".clipboardoverlay.EditTextActivity"
android:theme="@style/EditTextActivity"
android:exported="false"
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
index c3f6a5d..74b759f 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
@@ -172,7 +172,7 @@
if (packageName != null && animationAdapter != null) {
try {
ActivityTaskManager.getService().registerRemoteAnimationForNextActivityStart(
- packageName, animationAdapter)
+ packageName, animationAdapter, null /* launchCookie */)
} catch (e: RemoteException) {
Log.w(TAG, "Unable to register the remote animation", e)
}
@@ -298,6 +298,9 @@
*
* Important: The view must be attached to a [ViewGroup] when calling this function and
* during the animation. For safety, this method will return null when it is not.
+ *
+ * Note: The background of [view] should be a (rounded) rectangle so that it can be
+ * properly animated.
*/
@JvmStatic
fun fromView(view: View, cujType: Int? = null): Controller? {
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
index a3c5649..50178f4 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
@@ -79,6 +79,9 @@
* If [animateBackgroundBoundsChange] is true, then the background of the dialog will be
* animated when the dialog bounds change.
*
+ * Note: The background of [view] should be a (rounded) rectangle so that it can be properly
+ * animated.
+ *
* Caveats: When calling this function and [dialog] is not a fullscreen dialog, then it will be
* made fullscreen and 2 views will be inserted between the dialog DecorView and its children.
*/
@@ -153,6 +156,9 @@
* activity started, when the dialog to app animation is done (or when it is cancelled). If this
* method returns null, then the dialog won't be dismissed.
*
+ * Note: The background of [view] should be a (rounded) rectangle so that it can be properly
+ * animated.
+ *
* @param view any view inside the dialog to animate.
*/
@JvmOverloads
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java
index 0a0530c0..3d2f570 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java
@@ -60,7 +60,6 @@
boolean areCaptionsEnabled();
void setCaptionsEnabled(boolean isEnabled);
- boolean isCaptionStreamOptedOut();
void getCaptionsComponentState(boolean fromTooltip);
diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags
index 6352f81..c97ebe8 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/fgs_footer.xml b/packages/SystemUI/res-keyguard/layout/fgs_footer.xml
index 59f87da..9d801d2 100644
--- a/packages/SystemUI/res-keyguard/layout/fgs_footer.xml
+++ b/packages/SystemUI/res-keyguard/layout/fgs_footer.xml
@@ -28,7 +28,7 @@
android:layout_height="match_parent"
android:layout_marginEnd="@dimen/new_qs_footer_action_inset"
android:background="@drawable/qs_security_footer_background"
- android:layout_gravity="center"
+ android:layout_gravity="end"
android:gravity="center"
android:paddingHorizontal="@dimen/qs_footer_padding"
>
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index dad4c19..b98f413 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -123,6 +123,7 @@
<dimen name="bouncer_user_switcher_icon_size">190dp</dimen>
<dimen name="bouncer_user_switcher_icon_size_plus_margin">222dp</dimen>
+ <dimen name="user_switcher_fullscreen_horizontal_gap">64dp</dimen>
<dimen name="user_switcher_icon_selected_width">8dp</dimen>
<dimen name="user_switcher_fullscreen_button_text_size">14sp</dimen>
<dimen name="user_switcher_fullscreen_button_padding">12dp</dimen>
diff --git a/packages/SystemUI/res/color/caption_tint_color_selector.xml b/packages/SystemUI/res/color/caption_tint_color_selector.xml
index 30843ec..5239d26 100644
--- a/packages/SystemUI/res/color/caption_tint_color_selector.xml
+++ b/packages/SystemUI/res/color/caption_tint_color_selector.xml
@@ -16,8 +16,5 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:sysui="http://schemas.android.com/apk/res-auto">
- <item sysui:optedOut="true"
- android:color="?android:attr/colorButtonNormal"/>
-
<item android:color="?android:attr/colorAccent"/>
</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable-mdpi/dream_preview_back_arrow.png b/packages/SystemUI/res/drawable-mdpi/dream_preview_back_arrow.png
new file mode 100644
index 0000000..2c2f94e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/dream_preview_back_arrow.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/dream_preview_back_arrow.png b/packages/SystemUI/res/drawable-xhdpi/dream_preview_back_arrow.png
new file mode 100644
index 0000000..881b9af
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/dream_preview_back_arrow.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/dream_preview_back_arrow.png b/packages/SystemUI/res/drawable-xxhdpi/dream_preview_back_arrow.png
new file mode 100644
index 0000000..6063b42
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/dream_preview_back_arrow.png
Binary files differ
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 e456e29..0000000
--- 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/drawable/qs_dialog_btn_filled_large.xml b/packages/SystemUI/res/drawable/qs_dialog_btn_filled_large.xml
new file mode 100644
index 0000000..0544b871
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_dialog_btn_filled_large.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:color="?android:attr/colorControlHighlight">
+ <item android:id="@android:id/mask">
+ <shape android:shape="rectangle">
+ <solid android:color="@android:color/white"/>
+ <corners android:radius="18dp"/>
+ </shape>
+ </item>
+ <item>
+ <shape android:shape="rectangle">
+ <corners android:radius="18dp"/>
+ <solid android:color="?androidprv:attr/colorAccentPrimary"/>
+ </shape>
+ </item>
+</ripple>
diff --git a/packages/SystemUI/res/drawable/qs_footer_action_circle.xml b/packages/SystemUI/res/drawable/qs_footer_action_circle.xml
index d057f5f..31a8c3b 100644
--- a/packages/SystemUI/res/drawable/qs_footer_action_circle.xml
+++ b/packages/SystemUI/res/drawable/qs_footer_action_circle.xml
@@ -19,13 +19,17 @@
<ripple
android:color="?android:attr/colorControlHighlight">
<item android:id="@android:id/mask">
- <shape android:shape="oval">
+ <!-- We make this shape a rounded rectangle instead of a oval so that it can animate -->
+ <!-- properly into an app/dialog. -->
+ <shape android:shape="rectangle">
<solid android:color="@android:color/white"/>
+ <corners android:radius="@dimen/qs_footer_action_corner_radius"/>
</shape>
</item>
<item>
- <shape android:shape="oval">
+ <shape android:shape="rectangle">
<solid android:color="?attr/offStateColor"/>
+ <corners android:radius="@dimen/qs_footer_action_corner_radius"/>
</shape>
</item>
diff --git a/packages/SystemUI/res/drawable/qs_footer_action_circle_color.xml b/packages/SystemUI/res/drawable/qs_footer_action_circle_color.xml
index 944061c..021a85f 100644
--- a/packages/SystemUI/res/drawable/qs_footer_action_circle_color.xml
+++ b/packages/SystemUI/res/drawable/qs_footer_action_circle_color.xml
@@ -19,13 +19,17 @@
<ripple
android:color="?android:attr/colorControlHighlight">
<item android:id="@android:id/mask">
- <shape android:shape="oval">
+ <!-- We make this shape a rounded rectangle instead of a oval so that it can animate -->
+ <!-- properly into an app/dialog. -->
+ <shape android:shape="rectangle">
<solid android:color="@android:color/white"/>
+ <corners android:radius="@dimen/qs_footer_action_corner_radius"/>
</shape>
</item>
<item>
- <shape android:shape="oval">
+ <shape android:shape="rectangle">
<solid android:color="?android:attr/colorAccent"/>
+ <corners android:radius="@dimen/qs_footer_action_corner_radius"/>
</shape>
</item>
diff --git a/packages/SystemUI/res/layout-land-television/volume_dialog.xml b/packages/SystemUI/res/layout-land-television/volume_dialog.xml
index 6b5629f..0fbc519 100644
--- a/packages/SystemUI/res/layout-land-television/volume_dialog.xml
+++ b/packages/SystemUI/res/layout-land-television/volume_dialog.xml
@@ -73,8 +73,7 @@
android:layout_height="match_parent"
android:tint="@color/caption_tint_color_selector"
android:layout_gravity="center"
- android:soundEffectsEnabled="false"
- sysui:optedOut="false"/>
+ android:soundEffectsEnabled="false"/>
</FrameLayout>
diff --git a/packages/SystemUI/res/layout-land/volume_dialog.xml b/packages/SystemUI/res/layout-land/volume_dialog.xml
index f1cda27..3b70dc0 100644
--- a/packages/SystemUI/res/layout-land/volume_dialog.xml
+++ b/packages/SystemUI/res/layout-land/volume_dialog.xml
@@ -136,8 +136,7 @@
android:layout_height="match_parent"
android:tint="?android:attr/colorAccent"
android:layout_gravity="center"
- android:soundEffectsEnabled="false"
- sysui:optedOut="false"/>
+ android:soundEffectsEnabled="false" />
</FrameLayout>
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/alert_dialog_button_bar_systemui.xml b/packages/SystemUI/res/layout/alert_dialog_button_bar_systemui.xml
index a3e289a..e06bfdc 100644
--- a/packages/SystemUI/res/layout/alert_dialog_button_bar_systemui.xml
+++ b/packages/SystemUI/res/layout/alert_dialog_button_bar_systemui.xml
@@ -22,10 +22,6 @@
android:scrollbarAlwaysDrawVerticalTrack="true"
android:scrollIndicators="top|bottom"
android:fillViewport="true"
- android:paddingTop="@dimen/dialog_button_bar_top_padding"
- android:paddingStart="@dimen/dialog_side_padding"
- android:paddingEnd="@dimen/dialog_side_padding"
- android:paddingBottom="@dimen/dialog_bottom_padding"
style="?android:attr/buttonBarStyle">
<com.android.internal.widget.ButtonBarLayout
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/alert_dialog_systemui.xml b/packages/SystemUI/res/layout/alert_dialog_systemui.xml
index f280cbd..ca8fadd 100644
--- a/packages/SystemUI/res/layout/alert_dialog_systemui.xml
+++ b/packages/SystemUI/res/layout/alert_dialog_systemui.xml
@@ -83,9 +83,15 @@
android:layout_height="wrap_content" />
</FrameLayout>
- <include
+ <FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- layout="@layout/alert_dialog_button_bar_systemui" />
+ android:paddingStart="@dimen/dialog_side_padding"
+ android:paddingEnd="@dimen/dialog_side_padding">
+ <include
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ layout="@layout/alert_dialog_button_bar_systemui" />
+ </FrameLayout>
</com.android.internal.widget.AlertDialogLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/dream_overlay_complication_preview.xml b/packages/SystemUI/res/layout/dream_overlay_complication_preview.xml
new file mode 100644
index 0000000..ca5c499
--- /dev/null
+++ b/packages/SystemUI/res/layout/dream_overlay_complication_preview.xml
@@ -0,0 +1,28 @@
+<?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.
+ -->
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/dream_preview_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="@dimen/dream_overlay_complication_preview_text_size"
+ android:textColor="@android:color/white"
+ android:shadowColor="@color/keyguard_shadow_color"
+ android:shadowRadius="?attr/shadowRadius"
+ android:gravity="center_vertical"
+ 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_container.xml b/packages/SystemUI/res/layout/dream_overlay_container.xml
index 330f515..8e83b4a 100644
--- a/packages/SystemUI/res/layout/dream_overlay_container.xml
+++ b/packages/SystemUI/res/layout/dream_overlay_container.xml
@@ -34,34 +34,5 @@
app:layout_constraintBottom_toBottomOf="parent"
/>
- <com.android.systemui.dreams.DreamOverlayStatusBarView
- android:id="@+id/dream_overlay_status_bar"
- android:layout_width="match_parent"
- android:layout_height="@dimen/dream_overlay_status_bar_height"
- android:paddingEnd="@dimen/dream_overlay_status_bar_margin"
- android:paddingStart="@dimen/dream_overlay_status_bar_margin"
- app:layout_constraintTop_toTopOf="parent">
-
- <androidx.constraintlayout.widget.ConstraintLayout
- android:id="@+id/dream_overlay_system_status"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- app:layout_constraintEnd_toEndOf="parent">
-
- <com.android.systemui.statusbar.AlphaOptimizedImageView
- android:id="@+id/dream_overlay_wifi_status"
- android:layout_width="@dimen/status_bar_wifi_signal_size"
- android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/dream_overlay_status_icon_margin"
- android:visibility="gone"
- app:layout_constraintEnd_toStartOf="@id/dream_overlay_battery" />
-
- <com.android.systemui.battery.BatteryMeterView
- android:id="@+id/dream_overlay_battery"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- app:layout_constraintEnd_toEndOf="parent" />
-
- </androidx.constraintlayout.widget.ConstraintLayout>
- </com.android.systemui.dreams.DreamOverlayStatusBarView>
+ <include layout="@layout/dream_overlay_status_bar_view" />
</com.android.systemui.dreams.DreamOverlayContainerView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml b/packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml
new file mode 100644
index 0000000..1cbc3c2
--- /dev/null
+++ b/packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<com.android.systemui.dreams.DreamOverlayStatusBarView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/dream_overlay_status_bar"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/dream_overlay_status_bar_height"
+ android:paddingEnd="@dimen/dream_overlay_status_bar_margin"
+ android:paddingStart="@dimen/dream_overlay_status_bar_margin"
+ app:layout_constraintTop_toTopOf="parent">
+
+ <com.android.systemui.dreams.DreamOverlayDotImageView
+ android:id="@+id/dream_overlay_notification_indicator"
+ android:layout_width="@dimen/dream_overlay_notification_indicator_size"
+ android:layout_height="@dimen/dream_overlay_notification_indicator_size"
+ android:visibility="gone"
+ app:dotColor="@android:color/white"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent" />
+
+ <LinearLayout
+ android:id="@+id/dream_overlay_system_status"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:orientation="horizontal"
+ app:layout_constraintEnd_toEndOf="parent">
+
+ <com.android.systemui.statusbar.AlphaOptimizedImageView
+ android:id="@+id/dream_overlay_assistant_guest_mode_enabled"
+ 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_account_circle"
+ android:tint="@android:color/white"
+ android:visibility="gone"
+ android:contentDescription=
+ "@string/dream_overlay_status_bar_assistant_guest_mode_enabled" />
+
+ <com.android.systemui.statusbar.AlphaOptimizedImageView
+ android:id="@+id/dream_overlay_alarm_set"
+ 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_alarm"
+ android:tint="@android:color/white"
+ android:visibility="gone"
+ android:contentDescription="@string/dream_overlay_status_bar_alarm_set" />
+
+ <com.android.systemui.statusbar.AlphaOptimizedImageView
+ android:id="@+id/dream_overlay_priority_mode"
+ 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_qs_dnd_on"
+ android:tint="@android:color/white"
+ android:visibility="gone"
+ android:contentDescription="@string/dream_overlay_status_bar_priority_mode" />
+
+ <com.android.systemui.statusbar.AlphaOptimizedImageView
+ android:id="@+id/dream_overlay_wifi_status"
+ 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_signal_wifi_off"
+ android:visibility="gone"
+ android:contentDescription="@string/dream_overlay_status_bar_wifi_off" />
+
+ <com.android.systemui.dreams.DreamOverlayDotImageView
+ android:id="@+id/dream_overlay_camera_mic_off"
+ android:layout_width="@dimen/dream_overlay_camera_mic_off_indicator_size"
+ android:layout_height="@dimen/dream_overlay_camera_mic_off_indicator_size"
+ android:layout_gravity="center_vertical"
+ android:layout_marginEnd="@dimen/dream_overlay_status_icon_margin"
+ android:visibility="gone"
+ android:contentDescription="@string/dream_overlay_status_bar_camera_mic_off"
+ app:dotColor="@color/dream_overlay_camera_mic_off_dot_color" />
+
+ </LinearLayout>
+</com.android.systemui.dreams.DreamOverlayStatusBarView>
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 d4e98e2..0000000
--- 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 a6f1638..0000000
--- 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 b9e39da..0000000
--- 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/media_ttt_chip.xml b/packages/SystemUI/res/layout/media_ttt_chip.xml
index a5fdcd9..a502d33 100644
--- a/packages/SystemUI/res/layout/media_ttt_chip.xml
+++ b/packages/SystemUI/res/layout/media_ttt_chip.xml
@@ -16,6 +16,7 @@
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:id="@+id/media_ttt_sender_chip"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/packages/SystemUI/res/layout/media_ttt_chip_receiver.xml b/packages/SystemUI/res/layout/media_ttt_chip_receiver.xml
index 88feacd..5e8b892 100644
--- a/packages/SystemUI/res/layout/media_ttt_chip_receiver.xml
+++ b/packages/SystemUI/res/layout/media_ttt_chip_receiver.xml
@@ -17,6 +17,7 @@
<!-- TODO(b/203800646): layout_marginTop doesn't seem to work on some large screens. -->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/media_ttt_receiver_chip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/media_ttt_chip_background_receiver"
diff --git a/packages/SystemUI/res/layout/user_switcher_fullscreen.xml b/packages/SystemUI/res/layout/user_switcher_fullscreen.xml
index 2d883bc..0f2d372 100644
--- a/packages/SystemUI/res/layout/user_switcher_fullscreen.xml
+++ b/packages/SystemUI/res/layout/user_switcher_fullscreen.xml
@@ -21,9 +21,8 @@
android:id="@+id/user_switcher_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_marginBottom="40dp"
- android:layout_marginEnd="60dp"
- android:layout_marginStart="60dp">
+ android:layout_marginVertical="40dp"
+ android:layout_marginHorizontal="60dp">
<androidx.constraintlayout.helper.widget.Flow
android:id="@+id/flow"
@@ -36,7 +35,7 @@
app:flow_horizontalBias="0.5"
app:flow_verticalAlign="center"
app:flow_wrapMode="chain"
- app:flow_horizontalGap="64dp"
+ app:flow_horizontalGap="@dimen/user_switcher_fullscreen_horizontal_gap"
app:flow_verticalGap="44dp"
app:flow_horizontalStyle="packed"/>
@@ -56,16 +55,17 @@
<TextView
android:id="@+id/add"
- android:visibility="gone"
+ style="@style/Widget.Dialog.Button.BorderButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
- app:layout_constraintHeight_min="48dp"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
android:paddingHorizontal="@dimen/user_switcher_fullscreen_button_padding"
- android:textSize="@dimen/user_switcher_fullscreen_button_text_size"
+ android:text="@string/add"
android:textColor="?androidprv:attr/colorAccentPrimary"
- android:text="@string/add" />
+ android:textSize="@dimen/user_switcher_fullscreen_button_text_size"
+ android:visibility="gone"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHeight_min="48dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/packages/SystemUI/res/layout/user_switcher_fullscreen_item.xml b/packages/SystemUI/res/layout/user_switcher_fullscreen_item.xml
index 3319442..60e840c 100644
--- a/packages/SystemUI/res/layout/user_switcher_fullscreen_item.xml
+++ b/packages/SystemUI/res/layout/user_switcher_fullscreen_item.xml
@@ -13,21 +13,30 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<LinearLayout
+<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
- <ImageView
- android:id="@+id/user_switcher_icon"
- android:layout_gravity="center"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
- <TextView
- style="@style/Bouncer.UserSwitcher.Spinner.Item"
- android:id="@+id/user_switcher_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textColor="@*android:color/text_color_primary_device_default_dark"
- android:layout_gravity="center" />
-</LinearLayout>
+
+ <ImageView
+ android:id="@+id/user_switcher_icon"
+ android:layout_width="@dimen/bouncer_user_switcher_icon_size_plus_margin"
+ android:layout_height="@dimen/bouncer_user_switcher_icon_size_plus_margin"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <TextView
+ android:id="@+id/user_switcher_text"
+ style="@style/Bouncer.UserSwitcher.Spinner.Item"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:ellipsize="end"
+ android:gravity="center"
+ android:textColor="@*android:color/text_color_primary_device_default_dark"
+ app:layout_constraintEnd_toEndOf="@id/user_switcher_icon"
+ app:layout_constraintStart_toStartOf="@id/user_switcher_icon"
+ app:layout_constraintTop_toBottomOf="@id/user_switcher_icon" />
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index 51718d9..6a192d4 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -135,8 +135,7 @@
android:layout_height="match_parent"
android:tint="?android:attr/colorAccent"
android:layout_gravity="center"
- android:soundEffectsEnabled="false"
- sysui:optedOut="false"/>
+ android:soundEffectsEnabled="false"/>
</FrameLayout>
</LinearLayout>
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index 01eb09b..c386a3e 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -22,7 +22,6 @@
<dimen name="docked_divider_handle_width">2dp</dimen>
<dimen name="docked_divider_handle_height">16dp</dimen>
- <dimen name="qs_tile_height">84dp</dimen>
<dimen name="qs_brightness_margin_top">0dp</dimen>
<dimen name="qs_brightness_margin_bottom">12dp</dimen>
<dimen name="qqs_layout_margin_top">8dp</dimen>
diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
index c37c804..8a4516a 100644
--- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
@@ -42,4 +42,8 @@
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>
+
</resources>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 2992859..62903d5 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -154,10 +154,6 @@
<attr name="showAirplaneMode" format="boolean" />
</declare-styleable>
- <declare-styleable name="CaptionsToggleImageButton">
- <attr name="optedOut" format="boolean" />
- </declare-styleable>
-
<declare-styleable name="IlluminationDrawable">
<attr name="highlight" format="integer" />
<attr name="cornerRadius" format="dimension" />
@@ -199,5 +195,9 @@
</declare-styleable>
<attr name="overlayButtonTextColor" format="color" />
+
+ <declare-styleable name="DreamOverlayDotImageView">
+ <attr name="dotColor" format="color" />
+ </declare-styleable>
</resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index f4e7cf3..dc74700 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -225,4 +225,6 @@
<color name="settingslib_track_off_color">@color/settingslib_track_off</color>
<color name="connected_network_primary_color">#191C18</color>
<color name="connected_network_secondary_color">#41493D</color>
+
+ <color name="dream_overlay_camera_mic_off_dot_color">#FCBE03</color>
</resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 178f93a..2de8324 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -74,7 +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
+ internet,bt,flashlight,dnd,alarm,airplane,controls,wallet,rotation,battery,cast,screenrecord,mictoggle,cameratoggle,custom(com.android.permissioncontroller/.permission.service.SafetyHubQsTileService)
+ </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)
</string>
<!-- The minimum number of tiles to display in QuickSettings -->
@@ -690,4 +695,7 @@
<!-- How often in milliseconds to jitter the dream overlay in order to avoid burn-in. -->
<integer name="config_dreamOverlayBurnInProtectionUpdateIntervalMillis">500</integer>
+
+ <!-- How long in milliseconds before full burn-in protection is achieved. -->
+ <integer name="config_dreamOverlayMillisUntilFullJitter">240000</integer>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 3704134..92bc864 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -470,7 +470,7 @@
<dimen name="pull_span_min">25dp</dimen>
<dimen name="qs_corner_radius">28dp</dimen>
- <dimen name="qs_tile_height">84dp</dimen>
+ <dimen name="qs_tile_height">80dp</dimen>
<dimen name="qs_tile_margin_horizontal">8dp</dimen>
<dimen name="qs_tile_margin_vertical">@dimen/qs_tile_margin_horizontal</dimen>
<dimen name="qs_tile_margin_top_bottom">4dp</dimen>
@@ -1332,17 +1332,23 @@
<dimen name="fgs_manager_min_width_minor">100%</dimen>
<!-- Dream overlay related dimensions -->
- <dimen name="dream_overlay_status_bar_height">80dp</dimen>
+ <dimen name="dream_overlay_status_bar_height">60dp</dimen>
<dimen name="dream_overlay_status_bar_margin">40dp</dimen>
<dimen name="dream_overlay_status_icon_margin">8dp</dimen>
+ <dimen name="dream_overlay_status_bar_icon_size">
+ @*android:dimen/status_bar_system_icon_size</dimen>
<!-- Height of the area at the top of the dream overlay to allow dragging down the notifications
shade. -->
<dimen name="dream_overlay_notifications_drag_area_height">100dp</dimen>
+ <dimen name="dream_overlay_camera_mic_off_indicator_size">8dp</dimen>
+ <dimen name="dream_overlay_notification_indicator_size">6dp</dimen>
<!-- Dream overlay complications related dimensions -->
<dimen name="dream_overlay_complication_clock_time_text_size">72sp</dimen>
<dimen name="dream_overlay_complication_clock_date_text_size">18sp</dimen>
<dimen name="dream_overlay_complication_weather_text_size">18sp</dimen>
+ <dimen name="dream_overlay_complication_preview_text_size">36sp</dimen>
+ <dimen name="dream_overlay_complication_preview_icon_padding">28dp</dimen>
<!-- The position of the end guide, which dream overlay complications can align their start with
if their end is aligned with the parent end. Represented as the percentage over from the
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 23b2529..6ec6c23 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2410,4 +2410,20 @@
<!-- Toast shown when a notification does not support dragging to split [CHAR LIMIT=NONE] -->
<string name="drag_split_not_supported">This notification does not support dragging to Splitscreen.</string>
+
+ <!-- Content description for the Wi-Fi off icon in the dream overlay status bar [CHAR LIMIT=NONE] -->
+ <string name="dream_overlay_status_bar_wifi_off">Wi\u2011Fi unavailable</string>
+ <!-- Content description for the priority mode icon in the dream overlay status bar [CHAR LIMIT=NONE] -->
+ <string name="dream_overlay_status_bar_priority_mode">Priority mode</string>
+ <!-- Content description for the alarm set icon in the dream overlay status bar [CHAR LIMIT=NONE] -->
+ <string name="dream_overlay_status_bar_alarm_set">Alarm set</string>
+ <!-- Content description for the assistant guest mode enabled icon in the dream overlay status bar [CHAR LIMIT=NONE] -->
+ <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 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/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 9d65c38..f2eaa75 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -381,12 +381,19 @@
<item name="android:buttonBarNeutralButtonStyle">@style/Widget.Dialog.Button.BorderButton</item>
<item name="android:colorBackground">?androidprv:attr/colorSurface</item>
<item name="android:alertDialogStyle">@style/AlertDialogStyle</item>
+ <item name="android:buttonBarStyle">@style/ButtonBarStyle</item>
+ <item name="android:buttonBarButtonStyle">@style/Widget.Dialog.Button.Large</item>
</style>
<style name="AlertDialogStyle" parent="@androidprv:style/AlertDialog.DeviceDefault">
<item name="android:layout">@layout/alert_dialog_systemui</item>
</style>
+ <style name="ButtonBarStyle" parent="@androidprv:style/DeviceDefault.ButtonBar.AlertDialog">
+ <item name="android:paddingTop">@dimen/dialog_button_bar_top_padding</item>
+ <item name="android:paddingBottom">@dimen/dialog_bottom_padding</item>
+ </style>
+
<style name="Theme.SystemUI.Dialog.Alert" parent="@*android:style/Theme.DeviceDefault.Light.Dialog.Alert" />
<style name="Theme.SystemUI.Dialog.GlobalActions" parent="@android:style/Theme.DeviceDefault.Light.NoActionBar.Fullscreen">
@@ -962,6 +969,11 @@
<item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
+ <style name="Widget.Dialog.Button.Large">
+ <item name="android:background">@drawable/qs_dialog_btn_filled_large</item>
+ <item name="android:minHeight">56dp</item>
+ </style>
+
<style name="MainSwitch.Settingslib" parent="@android:style/Theme.DeviceDefault">
<item name="android:switchMinWidth">@dimen/settingslib_min_switch_width</item>
</style>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt b/packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt
index b611c96..6ad9161 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt
@@ -35,6 +35,11 @@
val resourceId: Int
}
+interface SysPropFlag<T> : Flag<T> {
+ val name: String
+ val default: T
+}
+
// Consider using the "parcelize" kotlin library.
data class BooleanFlag @JvmOverloads constructor(
@@ -66,6 +71,12 @@
@BoolRes override val resourceId: Int
) : ResourceFlag<Boolean>
+data class SysPropBooleanFlag constructor(
+ override val id: Int,
+ override val name: String,
+ override val default: Boolean = false
+) : SysPropFlag<Boolean>
+
data class StringFlag @JvmOverloads constructor(
override val id: Int,
override val default: String = ""
diff --git a/packages/SystemUI/shared/src/com/android/systemui/flags/FlagManager.kt b/packages/SystemUI/shared/src/com/android/systemui/flags/FlagManager.kt
index ec619dd..149f6e8 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/flags/FlagManager.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/flags/FlagManager.kt
@@ -54,7 +54,7 @@
* An action called on restart which takes as an argument whether the listeners requested
* that the restart be suppressed
*/
- var restartAction: Consumer<Boolean>? = null
+ var onSettingsChangedAction: Consumer<Boolean>? = null
var clearCacheAction: Consumer<Int>? = null
private val listeners: MutableSet<PerFlagListener> = mutableSetOf()
private val settingsObserver: ContentObserver = SettingsObserver()
@@ -154,11 +154,11 @@
val idStr = parts[parts.size - 1]
val id = try { idStr.toInt() } catch (e: NumberFormatException) { return }
clearCacheAction?.accept(id)
- dispatchListenersAndMaybeRestart(id)
+ dispatchListenersAndMaybeRestart(id, onSettingsChangedAction)
}
}
- fun dispatchListenersAndMaybeRestart(id: Int) {
+ fun dispatchListenersAndMaybeRestart(id: Int, restartAction: Consumer<Boolean>?) {
val filteredListeners: List<FlagListenable.Listener> = synchronized(listeners) {
listeners.mapNotNull { if (it.id == id) it.listener else null }
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
index b3983d2..e743c4e 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
@@ -43,6 +43,7 @@
/**
* Get the secondary split screen app's rectangle when not minimized.
+ * @deprecated
*/
Rect getNonMinimizedSplitScreenSecondaryBounds() = 7;
@@ -104,6 +105,7 @@
/**
* Sets the split-screen divider minimized state
+ * @deprecated
*/
void setSplitScreenMinimized(boolean minimized) = 22;
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/AppTrace.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/AppTrace.java
deleted file mode 100644
index 0241c59..0000000
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/AppTrace.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.systemui.shared.recents.utilities;
-
-import static android.os.Trace.TRACE_TAG_APP;
-
-/**
- * Helper class for internal trace functions.
- */
-public class AppTrace {
-
- /**
- * Begins a new async trace section with the given {@param key} and {@param cookie}.
- */
- public static void start(String key, int cookie) {
- android.os.Trace.asyncTraceBegin(TRACE_TAG_APP, key, cookie);
- }
-
- /**
- * Begins a new async trace section with the given {@param key}.
- */
- public static void start(String key) {
- android.os.Trace.asyncTraceBegin(TRACE_TAG_APP, key, 0);
- }
-
- /**
- * Ends an existing async trace section with the given {@param key}.
- */
- public static void end(String key) {
- android.os.Trace.asyncTraceEnd(TRACE_TAG_APP, key, 0);
- }
-
- /**
- * Ends an existing async trace section with the given {@param key} and {@param cookie}.
- */
- public static void end(String key, int cookie) {
- android.os.Trace.asyncTraceEnd(TRACE_TAG_APP, key, cookie);
- }
-
- /**
- * Begins a new trace section with the given {@param key}. Can be nested.
- */
- public static void beginSection(String key) {
- android.os.Trace.beginSection(key);
- }
-
- /**
- * Ends an existing trace section started in the last {@link #beginSection(String)}.
- */
- public static void endSection() {
- android.os.Trace.endSection();
- }
-
- /**
- * Traces a counter value.
- */
- public static void count(String name, int count) {
- android.os.Trace.traceCounter(TRACE_TAG_APP, name, count);
- }
-}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/RectFEvaluator.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/RectFEvaluator.java
deleted file mode 100644
index 51c1b5a..0000000
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/RectFEvaluator.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.systemui.shared.recents.utilities;
-
-import android.animation.TypeEvaluator;
-import android.graphics.RectF;
-
-/**
- * This evaluator can be used to perform type interpolation between <code>RectF</code> values.
- */
-public class RectFEvaluator implements TypeEvaluator<RectF> {
-
- private final RectF mRect = new RectF();
-
- /**
- * This function returns the result of linearly interpolating the start and
- * end Rect values, with <code>fraction</code> representing the proportion
- * between the start and end values. The calculation is a simple parametric
- * calculation on each of the separate components in the Rect objects
- * (left, top, right, and bottom).
- *
- * <p>The object returned will be the <code>reuseRect</code> passed into the constructor.</p>
- *
- * @param fraction The fraction from the starting to the ending values
- * @param startValue The start Rect
- * @param endValue The end Rect
- * @return A linear interpolation between the start and end values, given the
- * <code>fraction</code> parameter.
- */
- @Override
- public RectF evaluate(float fraction, RectF startValue, RectF endValue) {
- float left = startValue.left + ((endValue.left - startValue.left) * fraction);
- float top = startValue.top + ((endValue.top - startValue.top) * fraction);
- float right = startValue.right + ((endValue.right - startValue.right) * fraction);
- float bottom = startValue.bottom + ((endValue.bottom - startValue.bottom) * fraction);
- mRect.set(left, top, right, bottom);
- return mRect;
- }
-}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityCompat.java
index 0c7e56e..0f937bd 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityCompat.java
@@ -42,31 +42,4 @@
public void unregisterRemoteAnimations() {
mWrapped.unregisterRemoteAnimations();
}
-
- /**
- * @see android.view.ViewDebug#dumpv2(View, ByteArrayOutputStream)
- */
- public boolean encodeViewHierarchy(ByteArrayOutputStream out) {
- View view = null;
- if (mWrapped.getWindow() != null &&
- mWrapped.getWindow().peekDecorView() != null &&
- mWrapped.getWindow().peekDecorView().getViewRootImpl() != null) {
- view = mWrapped.getWindow().peekDecorView().getViewRootImpl().getView();
- }
- if (view == null) {
- return false;
- }
-
- final ViewHierarchyEncoder encoder = new ViewHierarchyEncoder(out);
- int[] location = view.getLocationOnScreen();
- encoder.addProperty("window:left", location[0]);
- encoder.addProperty("window:top", location[1]);
- view.encode(encoder);
- encoder.endStream();
- return true;
- }
-
- public int getDisplayId() {
- return mWrapped.getDisplayId();
- }
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index 48fcbbd..461c2dc 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -262,7 +262,6 @@
* Starts a task from Recents synchronously.
*/
public boolean startActivityFromRecents(Task.TaskKey taskKey, ActivityOptions options) {
- ActivityOptionsCompat.addTaskInfo(options, taskKey);
return startActivityFromRecents(taskKey.id, options);
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java
index e2ca349..db62f88 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java
@@ -104,15 +104,4 @@
opts.setSourceInfo(ActivityOptions.SourceInfo.TYPE_LAUNCHER, uptimeMillis);
return opts;
}
-
- /**
- * Sets Task specific information to the activity options
- */
- public static void addTaskInfo(ActivityOptions opts, Task.TaskKey taskKey) {
- if (taskKey.windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
- // We show non-visible docked tasks in Recents, but we always want to launch
- // them in the fullscreen stack.
- opts.setLaunchWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
- }
- }
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ClipDescriptionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ClipDescriptionCompat.java
deleted file mode 100644
index 0b1141e..0000000
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ClipDescriptionCompat.java
+++ /dev/null
@@ -1,39 +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.shared.system;
-
-import android.content.ClipDescription;
-import android.content.Intent;
-
-/**
- * Wrapper around ClipDescription.
- */
-public abstract class ClipDescriptionCompat {
-
- public static String MIMETYPE_APPLICATION_ACTIVITY =
- ClipDescription.MIMETYPE_APPLICATION_ACTIVITY;
-
- public static String MIMETYPE_APPLICATION_SHORTCUT =
- ClipDescription.MIMETYPE_APPLICATION_SHORTCUT;
-
- public static String MIMETYPE_APPLICATION_TASK =
- ClipDescription.MIMETYPE_APPLICATION_TASK;
-
- public static String EXTRA_PENDING_INTENT = ClipDescription.EXTRA_PENDING_INTENT;
-
- public static String EXTRA_TASK_ID = Intent.EXTRA_TASK_ID;
-}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ConfigurationCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ConfigurationCompat.java
deleted file mode 100644
index d1c77a6..0000000
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ConfigurationCompat.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.systemui.shared.system;
-
-import android.content.res.Configuration;
-
-/**
- * Wraps the Configuration to access the window configuration.
- */
-public class ConfigurationCompat {
-
- public static int getWindowConfigurationRotation(Configuration c) {
- return c.windowConfiguration.getRotation();
- }
-}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/DockedStackListenerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/DockedStackListenerCompat.java
deleted file mode 100644
index bb319e6..0000000
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/DockedStackListenerCompat.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.shared.system;
-
-import android.view.IDockedStackListener;
-
-/**
- * An interface to track docked stack changes.
- */
-public class DockedStackListenerCompat {
-
- IDockedStackListener.Stub mListener = new IDockedStackListener.Stub() {
- @Override
- public void onDividerVisibilityChanged(boolean visible) {}
-
- @Override
- public void onDockedStackExistsChanged(boolean exists) {
- DockedStackListenerCompat.this.onDockedStackExistsChanged(exists);
- }
-
- @Override
- public void onDockedStackMinimizedChanged(boolean minimized, long animDuration,
- boolean isHomeStackResizable) {
- DockedStackListenerCompat.this.onDockedStackMinimizedChanged(minimized, animDuration,
- isHomeStackResizable);
- }
-
- @Override
- public void onAdjustedForImeChanged(boolean adjustedForIme, long animDuration) {}
-
- @Override
- public void onDockSideChanged(final int newDockSide) {
- DockedStackListenerCompat.this.onDockSideChanged(newDockSide);
- }
- };
-
- public void onDockedStackExistsChanged(boolean exists) {
- // To be overridden
- }
-
- public void onDockedStackMinimizedChanged(boolean minimized, long animDuration,
- boolean isHomeStackResizable) {
- // To be overridden
- }
-
- public void onDockSideChanged(final int newDockSide) {
- // To be overridden
- }
-}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/LatencyTrackerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/LatencyTrackerCompat.java
index a8c19ec..e6ae19e 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/LatencyTrackerCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/LatencyTrackerCompat.java
@@ -24,14 +24,6 @@
* @see LatencyTracker
*/
public class LatencyTrackerCompat {
- /**
- * @see LatencyTracker
- * @deprecated Please use {@link LatencyTrackerCompat#logToggleRecents(Context, int)} instead.
- */
- @Deprecated
- public static void logToggleRecents(int duration) {
- LatencyTracker.logActionDeprecated(LatencyTracker.ACTION_TOGGLE_RECENTS, duration, false);
- }
/** @see LatencyTracker */
public static void logToggleRecents(Context context, int duration) {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/LauncherAppsCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/LauncherAppsCompat.java
deleted file mode 100644
index d24c779..0000000
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/LauncherAppsCompat.java
+++ /dev/null
@@ -1,34 +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.shared.system;
-
-import android.app.PendingIntent;
-import android.content.ComponentName;
-import android.content.pm.LauncherApps;
-import android.os.Bundle;
-import android.os.UserHandle;
-
-/**
- * Wrapper around LauncherApps.
- */
-public abstract class LauncherAppsCompat {
-
- public static PendingIntent getMainActivityLaunchIntent(LauncherApps launcherApps,
- ComponentName component, Bundle startActivityOptions, UserHandle user) {
- return launcherApps.getMainActivityLaunchIntent(component, startActivityOptions, user);
- }
-}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/MetricsLoggerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/MetricsLoggerCompat.java
deleted file mode 100644
index 952c8ae..0000000
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/MetricsLoggerCompat.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.shared.system;
-
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-
-public class MetricsLoggerCompat {
-
- private final MetricsLogger mMetricsLogger;
- public static final int OVERVIEW_ACTIVITY = MetricsEvent.OVERVIEW_ACTIVITY;
-
- public MetricsLoggerCompat() {
- mMetricsLogger = new MetricsLogger();
- }
-
- public void action(int category) {
- mMetricsLogger.action(category);
- }
-
- public void action(int category, int value) {
- mMetricsLogger.action(category, value);
- }
-
- public void visible(int category) {
- mMetricsLogger.visible(category);
- }
-
- public void hidden(int category) {
- mMetricsLogger.hidden(category);
- }
-
- public void visibility(int category, boolean visible) {
- mMetricsLogger.visibility(category, visible);
- }
-}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
index 08b4d3f..2b1c47f 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
@@ -103,8 +103,8 @@
// enabled (since it's used to navigate back within the bubbled app, or to collapse the bubble
// stack.
public static final int SYSUI_STATE_BUBBLES_EXPANDED = 1 << 14;
- // The global actions dialog is showing
- public static final int SYSUI_STATE_GLOBAL_ACTIONS_SHOWING = 1 << 15;
+ // A SysUI dialog is showing.
+ public static final int SYSUI_STATE_DIALOG_SHOWING = 1 << 15;
// The one-handed mode is active
public static final int SYSUI_STATE_ONE_HANDED_ACTIVE = 1 << 16;
// Allow system gesture no matter the system bar(s) is visible or not
@@ -140,7 +140,7 @@
SYSUI_STATE_TRACING_ENABLED,
SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED,
SYSUI_STATE_BUBBLES_EXPANDED,
- SYSUI_STATE_GLOBAL_ACTIONS_SHOWING,
+ SYSUI_STATE_DIALOG_SHOWING,
SYSUI_STATE_ONE_HANDED_ACTIVE,
SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY,
SYSUI_STATE_IME_SHOWING,
@@ -166,7 +166,7 @@
str.add((flags & SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED) != 0
? "keygrd_occluded" : "");
str.add((flags & SYSUI_STATE_BOUNCER_SHOWING) != 0 ? "bouncer_visible" : "");
- str.add((flags & SYSUI_STATE_GLOBAL_ACTIONS_SHOWING) != 0 ? "global_actions" : "");
+ str.add((flags & SYSUI_STATE_DIALOG_SHOWING) != 0 ? "dialog_showing" : "");
str.add((flags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0 ? "a11y_click" : "");
str.add((flags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0 ? "a11y_long_click" : "");
str.add((flags & SYSUI_STATE_TRACING_ENABLED) != 0 ? "tracing" : "");
@@ -256,7 +256,7 @@
public static boolean isBackGestureDisabled(int sysuiStateFlags) {
// Always allow when the bouncer/global actions is showing (even on top of the keyguard)
if ((sysuiStateFlags & SYSUI_STATE_BOUNCER_SHOWING) != 0
- || (sysuiStateFlags & SYSUI_STATE_GLOBAL_ACTIONS_SHOWING) != 0) {
+ || (sysuiStateFlags & SYSUI_STATE_DIALOG_SHOWING) != 0) {
return false;
}
if ((sysuiStateFlags & SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY) != 0) {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
index ace7938..98e48f6 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
@@ -132,12 +132,13 @@
// the current going-away task on top of recents, though, so move it to front
final ArrayList<WindowContainerToken> pausingTasks = new ArrayList<>();
WindowContainerToken pipTask = null;
+ WindowContainerToken recentsTask = null;
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
+ final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
if (change.getMode() == TRANSIT_CLOSE || change.getMode() == TRANSIT_TO_BACK) {
t.setLayer(leashMap.get(change.getLeash()),
info.getChanges().size() * 3 - i);
- final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
if (taskInfo == null) {
continue;
}
@@ -147,11 +148,14 @@
&& taskInfo.pictureInPictureParams.isAutoEnterEnabled()) {
pipTask = taskInfo.token;
}
- } else if (change.getTaskInfo() != null
- && change.getTaskInfo().topActivityType == ACTIVITY_TYPE_RECENTS) {
+ } else if (taskInfo != null
+ && taskInfo.topActivityType == ACTIVITY_TYPE_RECENTS) {
// This task is for recents, keep it on top.
t.setLayer(leashMap.get(change.getLeash()),
info.getChanges().size() * 3 - i);
+ recentsTask = taskInfo.token;
+ } else if (taskInfo != null && taskInfo.topActivityType == ACTIVITY_TYPE_HOME) {
+ recentsTask = taskInfo.token;
}
}
// Also make all the wallpapers opaque since we want the visible from the start
@@ -160,7 +164,7 @@
}
t.apply();
mRecentsSession.setup(controller, info, finishedCallback, pausingTasks, pipTask,
- leashMap, mToken);
+ recentsTask, leashMap, mToken);
recents.onAnimationStart(mRecentsSession, apps, wallpapers, new Rect(0, 0, 0, 0),
new Rect());
}
@@ -209,6 +213,7 @@
private IRemoteTransitionFinishedCallback mFinishCB = null;
private ArrayList<WindowContainerToken> mPausingTasks = null;
private WindowContainerToken mPipTask = null;
+ private WindowContainerToken mRecentsTask = null;
private TransitionInfo mInfo = null;
private ArrayList<SurfaceControl> mOpeningLeashes = null;
private ArrayMap<SurfaceControl, SurfaceControl> mLeashMap = null;
@@ -218,7 +223,8 @@
void setup(RecentsAnimationControllerCompat wrapped, TransitionInfo info,
IRemoteTransitionFinishedCallback finishCB,
ArrayList<WindowContainerToken> pausingTasks, WindowContainerToken pipTask,
- ArrayMap<SurfaceControl, SurfaceControl> leashMap, IBinder transition) {
+ WindowContainerToken recentsTask, ArrayMap<SurfaceControl, SurfaceControl> leashMap,
+ IBinder transition) {
if (mInfo != null) {
throw new IllegalStateException("Trying to run a new recents animation while"
+ " recents is already active.");
@@ -228,6 +234,7 @@
mFinishCB = finishCB;
mPausingTasks = pausingTasks;
mPipTask = pipTask;
+ mRecentsTask = recentsTask;
mLeashMap = leashMap;
mTransition = transition;
}
@@ -329,6 +336,9 @@
wct.reorder(mPausingTasks.get(i), true /* onTop */);
t.show(mInfo.getChange(mPausingTasks.get(i)).getLeash());
}
+ if (mRecentsTask != null) {
+ wct.restoreTransientOrder(mRecentsTask);
+ }
} else {
wct = null;
if (mPipTask != null && mPipTransaction != null) {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RotationWatcher.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RotationWatcher.java
deleted file mode 100644
index 7c8c23e..0000000
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RotationWatcher.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.systemui.shared.system;
-
-import android.content.Context;
-import android.os.RemoteException;
-import android.util.Log;
-import android.view.IRotationWatcher;
-import android.view.WindowManagerGlobal;
-
-public abstract class RotationWatcher {
-
- private static final String TAG = "RotationWatcher";
-
- private final Context mContext;
-
- private final IRotationWatcher mWatcher = new IRotationWatcher.Stub() {
-
- @Override
- public void onRotationChanged(int rotation) {
- RotationWatcher.this.onRotationChanged(rotation);
-
- }
- };
-
- private boolean mIsWatching = false;
-
- public RotationWatcher(Context context) {
- mContext = context;
- }
-
- protected abstract void onRotationChanged(int rotation);
-
- public void enable() {
- if (!mIsWatching) {
- try {
- WindowManagerGlobal.getWindowManagerService().watchRotation(mWatcher,
- mContext.getDisplayId());
- mIsWatching = true;
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to set rotation watcher", e);
- }
- }
- }
-
- public void disable() {
- if (mIsWatching) {
- try {
- WindowManagerGlobal.getWindowManagerService().removeRotationWatcher(mWatcher);
- mIsWatching = false;
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to remove rotation watcher", e);
- }
- }
- }
-}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskDescriptionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskDescriptionCompat.java
deleted file mode 100644
index 35952f5..0000000
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskDescriptionCompat.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.shared.system;
-
-import android.app.ActivityManager;
-import android.graphics.Bitmap;
-
-public class TaskDescriptionCompat {
-
- private ActivityManager.TaskDescription mTaskDescription;
-
- public TaskDescriptionCompat(ActivityManager.TaskDescription td) {
- mTaskDescription = td;
- }
-
- public int getPrimaryColor() {
- return mTaskDescription != null
- ? mTaskDescription.getPrimaryColor()
- : 0;
- }
-
- public int getBackgroundColor() {
- return mTaskDescription != null
- ? mTaskDescription.getBackgroundColor()
- : 0;
- }
-
- public static Bitmap getIcon(ActivityManager.TaskDescription desc, int userId) {
- if (desc.getInMemoryIcon() != null) {
- return desc.getInMemoryIcon();
- }
- return ActivityManager.TaskDescription.loadTaskDescriptionIcon(
- desc.getIconFilename(), userId);
- }
-}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ThreadedRendererCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ThreadedRendererCompat.java
deleted file mode 100644
index ffd8a08..0000000
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ThreadedRendererCompat.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.shared.system;
-
-import android.view.ThreadedRenderer;
-
-/**
- * @see ThreadedRenderer
- */
-public class ThreadedRendererCompat {
-
- public static int EGL_CONTEXT_PRIORITY_REALTIME_NV = 0x3357;
- public static int EGL_CONTEXT_PRIORITY_HIGH_IMG = 0x3101;
- public static int EGL_CONTEXT_PRIORITY_MEDIUM_IMG = 0x3102;
- public static int EGL_CONTEXT_PRIORITY_LOW_IMG = 0x3103;
-
- public static void setContextPriority(int priority) {
- ThreadedRenderer.setContextPriority(priority);
- }
-}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TonalCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TonalCompat.java
deleted file mode 100644
index 4a0f89b..0000000
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TonalCompat.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.systemui.shared.system;
-
-import android.app.WallpaperColors;
-import android.content.Context;
-
-import com.android.internal.colorextraction.ColorExtractor.GradientColors;
-import com.android.internal.colorextraction.types.Tonal;
-
-public class TonalCompat {
-
- private final Tonal mTonal;
-
- public TonalCompat(Context context) {
- mTonal = new Tonal(context);
- }
-
- public ExtractionInfo extractDarkColors(WallpaperColors colors) {
- GradientColors darkColors = new GradientColors();
- mTonal.extractInto(colors, new GradientColors(), darkColors, new GradientColors());
-
- ExtractionInfo result = new ExtractionInfo();
- result.mainColor = darkColors.getMainColor();
- result.secondaryColor = darkColors.getSecondaryColor();
- result.supportsDarkText = darkColors.supportsDarkText();
- if (colors != null) {
- result.supportsDarkTheme =
- (colors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_THEME) != 0;
- }
- return result;
- }
-
- public static class ExtractionInfo {
- public int mainColor;
- public int secondaryColor;
- public boolean supportsDarkText;
- public boolean supportsDarkTheme;
- }
-}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java
deleted file mode 100644
index 89c60f1..0000000
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java
+++ /dev/null
@@ -1,67 +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.shared.system;
-
-import android.graphics.HardwareRenderer;
-import android.view.SurfaceControl;
-import android.view.View;
-import android.view.ViewRootImpl;
-
-import java.util.function.LongConsumer;
-
-/**
- * Helper class to expose some ViewRoomImpl methods
- */
-public class ViewRootImplCompat {
-
- private final ViewRootImpl mViewRoot;
-
- public ViewRootImplCompat(View view) {
- mViewRoot = view == null ? null : view.getViewRootImpl();
- }
-
- public SurfaceControl getRenderSurfaceControl() {
- return mViewRoot == null ? null : mViewRoot.getSurfaceControl();
- }
-
- public boolean isValid() {
- return mViewRoot != null;
- }
-
- public View getView() {
- return mViewRoot == null ? null : mViewRoot.getView();
- }
-
- public void registerRtFrameCallback(LongConsumer callback) {
- if (mViewRoot != null) {
- mViewRoot.registerRtFrameCallback(
- new HardwareRenderer.FrameDrawingCallback() {
- @Override
- public void onFrameDraw(long l) {
- callback.accept(l);
- }
- });
- }
- }
-
- public void mergeWithNextTransaction(SurfaceControl.Transaction t, long frame) {
- if (mViewRoot != null) {
- mViewRoot.mergeWithNextTransaction(t, frame);
- } else {
- t.apply();
- }
- }
-}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WallpaperEngineCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WallpaperEngineCompat.java
deleted file mode 100644
index 73dc60d..0000000
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WallpaperEngineCompat.java
+++ /dev/null
@@ -1,56 +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.shared.system;
-
-import android.graphics.Rect;
-import android.service.wallpaper.IWallpaperEngine;
-import android.util.Log;
-
-/**
- * @see IWallpaperEngine
- */
-public class WallpaperEngineCompat {
-
- private static final String TAG = "WallpaperEngineCompat";
-
- /**
- * Returns true if {@link IWallpaperEngine#scalePreview(Rect)} is available.
- */
- public static boolean supportsScalePreview() {
- try {
- return IWallpaperEngine.class.getMethod("scalePreview", Rect.class) != null;
- } catch (NoSuchMethodException | SecurityException e) {
- return false;
- }
- }
-
- private final IWallpaperEngine mWrappedEngine;
-
- public WallpaperEngineCompat(IWallpaperEngine wrappedEngine) {
- mWrappedEngine = wrappedEngine;
- }
-
- /**
- * @see IWallpaperEngine#scalePreview(Rect)
- */
- public void scalePreview(Rect scaleToRect) {
- try {
- mWrappedEngine.scalePreview(scaleToRect);
- } catch (Exception e) {
- Log.i(TAG, "Couldn't call scalePreview method on WallpaperEngine", e);
- }
- }
-}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WallpaperManagerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WallpaperManagerCompat.java
deleted file mode 100644
index 1f194eca..0000000
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WallpaperManagerCompat.java
+++ /dev/null
@@ -1,51 +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.shared.system;
-
-import android.app.WallpaperManager;
-import android.content.Context;
-import android.content.res.Resources;
-import android.os.IBinder;
-
-/**
- * @see WallpaperManager
- */
-public class WallpaperManagerCompat {
- private final WallpaperManager mWallpaperManager;
-
- public WallpaperManagerCompat(Context context) {
- mWallpaperManager = context.getSystemService(WallpaperManager.class);
- }
-
- /**
- * @see WallpaperManager#setWallpaperZoomOut(IBinder, float)
- */
- public void setWallpaperZoomOut(IBinder windowToken, float zoom) {
- mWallpaperManager.setWallpaperZoomOut(windowToken, zoom);
- }
-
- /**
- * @return the max scale for the wallpaper when it's fully zoomed out
- */
- public static float getWallpaperZoomOutMaxScale(Context context) {
- return context.getResources()
- .getFloat(Resources.getSystem().getIdentifier(
- /* name= */ "config_wallpaperMaxScale",
- /* defType= */ "dimen",
- /* defPackage= */ "android"));
- }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeSensorAngleProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeSensorAngleProvider.kt
index f6fe1ed..a50d852 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeSensorAngleProvider.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeSensorAngleProvider.kt
@@ -4,6 +4,7 @@
import android.hardware.SensorEvent
import android.hardware.SensorEventListener
import android.hardware.SensorManager
+import android.os.Trace
import androidx.core.util.Consumer
internal class HingeSensorAngleProvider(private val sensorManager: SensorManager) :
@@ -13,8 +14,10 @@
private val listeners: MutableList<Consumer<Float>> = arrayListOf()
override fun start() {
+ Trace.beginSection("HingeSensorAngleProvider#start")
val sensor = sensorManager.getDefaultSensor(Sensor.TYPE_HINGE_ANGLE)
sensorManager.registerListener(sensorListener, sensor, SensorManager.SENSOR_DELAY_FASTEST)
+ Trace.endSection()
}
override fun stop() {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
index 848b8ab..1ede76f 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
@@ -26,6 +26,7 @@
import android.media.MediaRouter;
import android.media.MediaRouter.RouteInfo;
import android.os.Bundle;
+import android.os.Trace;
import android.util.Log;
import android.util.SparseArray;
import android.view.Display;
@@ -67,11 +68,14 @@
@Override
public void onDisplayAdded(int displayId) {
+ Trace.beginSection(
+ "KeyguardDisplayManager#onDisplayAdded(displayId=" + displayId + ")");
final Display display = mDisplayService.getDisplay(displayId);
if (mShowing) {
updateNavigationBarVisibility(displayId, false /* navBarVisible */);
showPresentation(display);
}
+ Trace.endSection();
}
@Override
@@ -81,7 +85,10 @@
@Override
public void onDisplayRemoved(int displayId) {
+ Trace.beginSection(
+ "KeyguardDisplayManager#onDisplayRemoved(displayId=" + displayId + ")");
hidePresentation(displayId);
+ Trace.endSection();
}
};
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java
index 122f3d7..295d77d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java
@@ -24,9 +24,9 @@
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 @@
// 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 4ad5183..370686a 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.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 @@
* 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 207ac28..8dbe5e0 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 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 ba0642f..f498ef3 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 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 880822a..aeae8e3 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 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 cc166c2..5bd620e 100644
--- a/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
@@ -23,7 +23,7 @@
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 @@
/**
* 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/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index b32c2b6..84b6ace 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -38,6 +38,7 @@
import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver;
import com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuController;
+import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.appops.AppOpsController;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.broadcast.BroadcastDispatcher;
@@ -107,6 +108,7 @@
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider;
import com.android.systemui.statusbar.phone.StatusBarIconController;
+import com.android.systemui.statusbar.phone.SystemUIDialogManager;
import com.android.systemui.statusbar.policy.AccessibilityController;
import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
import com.android.systemui.statusbar.policy.BatteryController;
@@ -372,6 +374,8 @@
@Inject Lazy<AmbientState> mAmbientStateLazy;
@Inject Lazy<GroupMembershipManager> mGroupMembershipManagerLazy;
@Inject Lazy<GroupExpansionManager> mGroupExpansionManagerLazy;
+ @Inject Lazy<SystemUIDialogManager> mSystemUIDialogManagerLazy;
+ @Inject Lazy<DialogLaunchAnimator> mDialogLaunchAnimatorLazy;
@Inject
public Dependency() {
@@ -592,6 +596,8 @@
mProviders.put(AmbientState.class, mAmbientStateLazy::get);
mProviders.put(GroupMembershipManager.class, mGroupMembershipManagerLazy::get);
mProviders.put(GroupExpansionManager.class, mGroupExpansionManagerLazy::get);
+ mProviders.put(SystemUIDialogManager.class, mSystemUIDialogManagerLazy::get);
+ mProviders.put(DialogLaunchAnimator.class, mDialogLaunchAnimatorLazy::get);
Dependency.setInstance(this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt b/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt
index 6bec8aa..56046d9 100644
--- a/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt
+++ b/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt
@@ -49,7 +49,7 @@
private val shouldDrawCutout: Boolean = DisplayCutout.getFillBuiltInDisplayCutout(
context.resources, context.display?.uniqueId)
private var displayMode: Display.Mode? = null
- private val location = IntArray(2)
+ protected val location = IntArray(2)
protected var displayRotation = 0
@VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
@@ -65,7 +65,8 @@
@JvmField val protectionPath: Path = Path()
private val protectionRectOrig: RectF = RectF()
private val protectionPathOrig: Path = Path()
- private var cameraProtectionProgress: Float = HIDDEN_CAMERA_PROTECTION_SCALE
+ @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
+ var cameraProtectionProgress: Float = HIDDEN_CAMERA_PROTECTION_SCALE
private var cameraProtectionAnimator: ValueAnimator? = null
constructor(context: Context) : super(context)
@@ -273,4 +274,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt b/packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt
index ee1d9a3..4b86862 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt
@@ -26,11 +26,22 @@
import android.graphics.PorterDuff
import android.graphics.PorterDuffColorFilter
import android.graphics.PorterDuffXfermode
+import android.graphics.Rect
+import android.graphics.Region
import android.graphics.drawable.Drawable
import android.hardware.graphics.common.AlphaInterpretation
import android.hardware.graphics.common.DisplayDecorationSupport
+import android.view.DisplayCutout.BOUNDS_POSITION_BOTTOM
+import android.view.DisplayCutout.BOUNDS_POSITION_LEFT
+import android.view.DisplayCutout.BOUNDS_POSITION_LENGTH
+import android.view.DisplayCutout.BOUNDS_POSITION_TOP
+import android.view.DisplayCutout.BOUNDS_POSITION_RIGHT
import android.view.RoundedCorner
import android.view.RoundedCorners
+import android.view.Surface
+import androidx.annotation.VisibleForTesting
+import kotlin.math.ceil
+import kotlin.math.floor
/**
* When the HWC of the device supports Composition.DISPLAY_DECORATON, we use this layer to draw
@@ -38,13 +49,16 @@
*/
class ScreenDecorHwcLayer(context: Context, displayDecorationSupport: DisplayDecorationSupport)
: DisplayCutoutBaseView(context) {
- public val colorMode: Int
+ val colorMode: Int
private val useInvertedAlphaColor: Boolean
private val color: Int
private val bgColor: Int
private val cornerFilter: ColorFilter
private val cornerBgFilter: ColorFilter
private val clearPaint: Paint
+ @JvmField val transparentRect: Rect = Rect()
+ private val debugTransparentRegionPaint: Paint?
+ private val tempRect: Rect = Rect()
private var roundedCornerTopSize = 0
private var roundedCornerBottomSize = 0
@@ -61,6 +75,10 @@
bgColor = Color.TRANSPARENT
colorMode = ActivityInfo.COLOR_MODE_DEFAULT
useInvertedAlphaColor = false
+ debugTransparentRegionPaint = Paint().apply {
+ color = 0x2f00ff00 // semi-transparent green
+ style = Paint.Style.FILL
+ }
} else {
colorMode = ActivityInfo.COLOR_MODE_A8
useInvertedAlphaColor = displayDecorationSupport.alphaInterpretation ==
@@ -72,6 +90,7 @@
color = Color.BLACK
bgColor = Color.TRANSPARENT
}
+ debugTransparentRegionPaint = null
}
cornerFilter = PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN)
cornerBgFilter = PorterDuffColorFilter(bgColor, PorterDuff.Mode.SRC_OUT)
@@ -82,6 +101,9 @@
override fun onAttachedToWindow() {
super.onAttachedToWindow()
+ if (!DEBUG_COLOR) {
+ parent.requestTransparentRegion(this)
+ }
viewRootImpl.setDisplayDecoration(true)
if (useInvertedAlphaColor) {
@@ -93,12 +115,172 @@
}
override fun onDraw(canvas: Canvas) {
+ // If updating onDraw, also update gatherTransparentRegion
if (useInvertedAlphaColor) {
canvas.drawColor(bgColor)
}
// Cutouts are drawn in DisplayCutoutBaseView.onDraw()
super.onDraw(canvas)
drawRoundedCorners(canvas)
+
+ debugTransparentRegionPaint?.let {
+ calculateTransparentRect()
+ canvas.drawRect(transparentRect, it)
+ }
+ }
+
+ override fun gatherTransparentRegion(region: Region?): Boolean {
+ region?.let {
+ calculateTransparentRect()
+ region.op(transparentRect, Region.Op.INTERSECT)
+ }
+ // Always return false - views underneath this should always be visible.
+ return false
+ }
+
+ /**
+ * The transparent rect is calculated by subtracting the regions of cutouts, cutout protect and
+ * rounded corners from the region with fullscreen display size.
+ */
+ @VisibleForTesting
+ fun calculateTransparentRect() {
+ transparentRect.set(0, 0, width, height)
+
+ // Remove cutout region.
+ removeCutoutFromTransparentRegion()
+
+ // Remove cutout protection region.
+ removeCutoutProtectionFromTransparentRegion()
+
+ // Remove rounded corner region.
+ removeRoundedCornersFromTransparentRegion()
+ }
+
+ private fun removeCutoutFromTransparentRegion() {
+ displayInfo.displayCutout?.let {
+ cutout ->
+ if (!cutout.boundingRectLeft.isEmpty) {
+ transparentRect.left =
+ cutout.boundingRectLeft.right.coerceAtLeast(transparentRect.left)
+ }
+ if (!cutout.boundingRectTop.isEmpty) {
+ transparentRect.top =
+ cutout.boundingRectTop.bottom.coerceAtLeast(transparentRect.top)
+ }
+ if (!cutout.boundingRectRight.isEmpty) {
+ transparentRect.right =
+ cutout.boundingRectRight.left.coerceAtMost(transparentRect.right)
+ }
+ if (!cutout.boundingRectBottom.isEmpty) {
+ transparentRect.bottom =
+ cutout.boundingRectBottom.top.coerceAtMost(transparentRect.bottom)
+ }
+ }
+ }
+
+ private fun removeCutoutProtectionFromTransparentRegion() {
+ if (protectionRect.isEmpty) {
+ return
+ }
+
+ val centerX = protectionRect.centerX()
+ val centerY = protectionRect.centerY()
+ val scaledDistanceX = (centerX - protectionRect.left) * cameraProtectionProgress
+ val scaledDistanceY = (centerY - protectionRect.top) * cameraProtectionProgress
+ tempRect.set(
+ floor(centerX - scaledDistanceX).toInt(),
+ floor(centerY - scaledDistanceY).toInt(),
+ ceil(centerX + scaledDistanceX).toInt(),
+ ceil(centerY + scaledDistanceY).toInt()
+ )
+
+ // Find out which edge the protectionRect belongs and remove that edge from the transparent
+ // region.
+ val leftDistance = tempRect.left
+ val topDistance = tempRect.top
+ val rightDistance = width - tempRect.right
+ val bottomDistance = height - tempRect.bottom
+ val minDistance = minOf(leftDistance, topDistance, rightDistance, bottomDistance)
+ when (minDistance) {
+ leftDistance -> {
+ transparentRect.left = tempRect.right.coerceAtLeast(transparentRect.left)
+ }
+ topDistance -> {
+ transparentRect.top = tempRect.bottom.coerceAtLeast(transparentRect.top)
+ }
+ rightDistance -> {
+ transparentRect.right = tempRect.left.coerceAtMost(transparentRect.right)
+ }
+ bottomDistance -> {
+ transparentRect.bottom = tempRect.top.coerceAtMost(transparentRect.bottom)
+ }
+ }
+ }
+
+ private fun removeRoundedCornersFromTransparentRegion() {
+ var hasTopOrBottomCutouts = false
+ var hasLeftOrRightCutouts = false
+ displayInfo.displayCutout?.let {
+ cutout ->
+ hasTopOrBottomCutouts = !cutout.boundingRectTop.isEmpty ||
+ !cutout.boundingRectBottom.isEmpty
+ hasLeftOrRightCutouts = !cutout.boundingRectLeft.isEmpty ||
+ !cutout.boundingRectRight.isEmpty
+ }
+ // The goal is to remove the rounded corner areas as small as possible so that we can have a
+ // larger transparent region. Therefore, we should always remove from the short edge sides
+ // if possible.
+ val isShortEdgeTopBottom = width < height
+ if (isShortEdgeTopBottom) {
+ // Short edges on top & bottom.
+ if (!hasTopOrBottomCutouts && hasLeftOrRightCutouts) {
+ // If there are cutouts only on left or right edges, remove left and right sides
+ // for rounded corners.
+ transparentRect.left = getRoundedCornerSizeByPosition(BOUNDS_POSITION_LEFT)
+ .coerceAtLeast(transparentRect.left)
+ transparentRect.right =
+ (width - getRoundedCornerSizeByPosition(BOUNDS_POSITION_RIGHT))
+ .coerceAtMost(transparentRect.right)
+ } else {
+ // If there are cutouts on top or bottom edges or no cutout at all, remove top
+ // and bottom sides for rounded corners.
+ transparentRect.top = getRoundedCornerSizeByPosition(BOUNDS_POSITION_TOP)
+ .coerceAtLeast(transparentRect.top)
+ transparentRect.bottom =
+ (height - getRoundedCornerSizeByPosition(BOUNDS_POSITION_BOTTOM))
+ .coerceAtMost(transparentRect.bottom)
+ }
+ } else {
+ // Short edges on left & right.
+ if (hasTopOrBottomCutouts && !hasLeftOrRightCutouts) {
+ // If there are cutouts only on top or bottom edges, remove top and bottom sides
+ // for rounded corners.
+ transparentRect.top = getRoundedCornerSizeByPosition(BOUNDS_POSITION_TOP)
+ .coerceAtLeast(transparentRect.top)
+ transparentRect.bottom =
+ (height - getRoundedCornerSizeByPosition(BOUNDS_POSITION_BOTTOM))
+ .coerceAtMost(transparentRect.bottom)
+ } else {
+ // If there are cutouts on left or right edges or no cutout at all, remove left
+ // and right sides for rounded corners.
+ transparentRect.left = getRoundedCornerSizeByPosition(BOUNDS_POSITION_LEFT)
+ .coerceAtLeast(transparentRect.left)
+ transparentRect.right =
+ (width - getRoundedCornerSizeByPosition(BOUNDS_POSITION_RIGHT))
+ .coerceAtMost(transparentRect.right)
+ }
+ }
+ }
+
+ private fun getRoundedCornerSizeByPosition(position: Int): Int {
+ val delta = displayRotation - Surface.ROTATION_0
+ return when ((position + delta) % BOUNDS_POSITION_LENGTH) {
+ BOUNDS_POSITION_LEFT -> roundedCornerTopSize.coerceAtLeast(roundedCornerBottomSize)
+ BOUNDS_POSITION_TOP -> roundedCornerTopSize
+ BOUNDS_POSITION_RIGHT -> roundedCornerTopSize.coerceAtLeast(roundedCornerBottomSize)
+ BOUNDS_POSITION_BOTTOM -> roundedCornerBottomSize
+ else -> throw IllegalArgumentException("Incorrect position: $position")
+ }
}
private fun drawRoundedCorners(canvas: Canvas) {
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 2ec5f4f..ae41cae 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -847,14 +847,20 @@
pw.println(" mIsRoundedCornerMultipleRadius:" + mIsRoundedCornerMultipleRadius);
pw.println(" mIsPrivacyDotEnabled:" + isPrivacyDotEnabled());
pw.println(" mPendingRotationChange:" + mPendingRotationChange);
- pw.println(" mHwcScreenDecorationSupport:");
- if (mHwcScreenDecorationSupport == null) {
- pw.println(" null");
- } else {
- pw.println(" format: "
+ if (mHwcScreenDecorationSupport != null) {
+ pw.println(" mHwcScreenDecorationSupport:");
+ pw.println(" format="
+ PixelFormat.formatToString(mHwcScreenDecorationSupport.format));
- pw.println(" alphaInterpretation: "
+ pw.println(" alphaInterpretation="
+ alphaInterpretationToString(mHwcScreenDecorationSupport.alphaInterpretation));
+ } else {
+ pw.println(" mHwcScreenDecorationSupport: null");
+ }
+ if (mScreenDecorHwcLayer != null) {
+ pw.println(" mScreenDecorHwcLayer:");
+ pw.println(" transparentRegion=" + mScreenDecorHwcLayer.transparentRect);
+ } else {
+ pw.println(" mScreenDecorHwcLayer: null");
}
pw.println(" mRoundedDefault(x,y)=(" + mRoundedDefault.x + "," + mRoundedDefault.y + ")");
pw.println(" mRoundedDefaultTop(x,y)=(" + mRoundedDefaultTop.x + "," + mRoundedDefaultTop.y
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index ec11065..3a6165c 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -38,13 +38,13 @@
import android.util.Log;
import android.util.TimingsTraceLog;
import android.view.SurfaceControl;
+import android.view.ThreadedRenderer;
import com.android.internal.protolog.common.ProtoLog;
import com.android.systemui.dagger.ContextComponentHelper;
import com.android.systemui.dagger.GlobalRootComponent;
import com.android.systemui.dagger.SysUIComponent;
import com.android.systemui.dump.DumpManager;
-import com.android.systemui.shared.system.ThreadedRendererCompat;
import com.android.systemui.util.NotificationChannels;
import java.lang.reflect.Constructor;
@@ -118,11 +118,11 @@
// The priority is defaulted at medium.
int sfPriority = SurfaceControl.getGPUContextPriority();
Log.i(TAG, "Found SurfaceFlinger's GPU Priority: " + sfPriority);
- if (sfPriority == ThreadedRendererCompat.EGL_CONTEXT_PRIORITY_REALTIME_NV) {
+ if (sfPriority == ThreadedRenderer.EGL_CONTEXT_PRIORITY_REALTIME_NV) {
Log.i(TAG, "Setting SysUI's GPU Context priority to: "
- + ThreadedRendererCompat.EGL_CONTEXT_PRIORITY_HIGH_IMG);
- ThreadedRendererCompat.setContextPriority(
- ThreadedRendererCompat.EGL_CONTEXT_PRIORITY_HIGH_IMG);
+ + ThreadedRenderer.EGL_CONTEXT_PRIORITY_HIGH_IMG);
+ ThreadedRenderer.setContextPriority(
+ ThreadedRenderer.EGL_CONTEXT_PRIORITY_HIGH_IMG);
}
// Enable binder tracing on system server for calls originating from SysUI
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
index 881e6a9..bd8e44c 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.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 @@
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 @@
@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 @@
// NotificationShadeWindowController.registerCallback() only keeps weak references.
mNotificationShadeCallback = (keyguardShowing, keyguardOccluded, bouncerShowing, mDozing) ->
registerOrUnregisterDismissNotificationShadeAction();
- mStatusBarOptionalLazy = statusBarOptionalLazy;
+ mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy;
}
@Override
@@ -311,9 +311,10 @@
// 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 @@
}
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 @@
}
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/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index 0d20403..de03993 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -43,6 +43,7 @@
import android.os.RemoteException;
import android.util.Log;
import android.util.Range;
+import android.util.Size;
import android.view.Choreographer;
import android.view.Display;
import android.view.Gravity;
@@ -62,6 +63,8 @@
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.view.accessibility.IRemoteMagnificationAnimationCallback;
+import androidx.core.math.MathUtils;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import com.android.systemui.R;
@@ -166,6 +169,7 @@
private final Rect mMagnificationFrameBoundary = new Rect();
// The top Y of the system gesture rect at the bottom. Set to -1 if it is invalid.
private int mSystemGestureTop = -1;
+ private int mMinWindowSize;
private final WindowMagnificationAnimationController mAnimationController;
private final SfVsyncFrameCallbackProvider mSfVsyncFrameProvider;
@@ -208,8 +212,10 @@
mBounceEffectDuration = mResources.getInteger(
com.android.internal.R.integer.config_shortAnimTime);
updateDimensions();
- setMagnificationFrameWith(mWindowBounds, mWindowBounds.width() / 2,
- mWindowBounds.height() / 2);
+
+ final Size windowSize = getDefaultWindowSizeWithWindowBounds(mWindowBounds);
+ setMagnificationFrame(windowSize.getWidth(), windowSize.getHeight(),
+ mWindowBounds.width() / 2, mWindowBounds.height() / 2);
computeBounceAnimationScale();
mMirrorWindowControl = mirrorWindowControl;
@@ -281,6 +287,8 @@
R.dimen.magnification_drag_view_size);
mOuterBorderSize = mResources.getDimensionPixelSize(
R.dimen.magnification_outer_border_margin);
+ mMinWindowSize = mResources.getDimensionPixelSize(
+ com.android.internal.R.dimen.accessibility_window_magnifier_min_size);
}
private void computeBounceAnimationScale() {
@@ -414,9 +422,12 @@
return false;
}
mWindowBounds.set(currentWindowBounds);
+ final Size windowSize = getDefaultWindowSizeWithWindowBounds(mWindowBounds);
final float newCenterX = (getCenterX()) * mWindowBounds.width() / oldWindowBounds.width();
final float newCenterY = (getCenterY()) * mWindowBounds.height() / oldWindowBounds.height();
- setMagnificationFrameWith(mWindowBounds, (int) newCenterX, (int) newCenterY);
+
+ setMagnificationFrame(windowSize.getWidth(), windowSize.getHeight(), (int) newCenterX,
+ (int) newCenterY);
calculateMagnificationFrameBoundary();
return true;
}
@@ -454,11 +465,6 @@
mWindowBounds.set(currentWindowBounds);
- calculateMagnificationFrameBoundary();
-
- if (!isWindowVisible()) {
- return;
- }
// Keep MirrorWindow position on the screen unchanged when device rotates 90°
// clockwise or anti-clockwise.
@@ -469,14 +475,13 @@
} else if (rotationDegree == 270) {
matrix.postTranslate(0, mWindowBounds.height());
}
- // The rect of MirrorView is going to be transformed.
- LayoutParams params =
- (LayoutParams) mMirrorView.getLayoutParams();
- mTmpRect.set(params.x, params.y, params.x + params.width, params.y + params.height);
- final RectF transformedRect = new RectF(mTmpRect);
+
+ final RectF transformedRect = new RectF(mMagnificationFrame);
+ // The window frame is going to be transformed by the rotation matrix.
+ transformedRect.inset(-mMirrorSurfaceMargin, -mMirrorSurfaceMargin);
matrix.mapRect(transformedRect);
- moveWindowMagnifier(transformedRect.left - mTmpRect.left,
- transformedRect.top - mTmpRect.top);
+ setWindowSizeAndCenter((int) transformedRect.width(), (int) transformedRect.height(),
+ (int) transformedRect.centerX(), (int) transformedRect.centerY());
}
/** Returns the rotation degree change of two {@link Surface.Rotation} */
@@ -573,16 +578,52 @@
}
}
- private void setMagnificationFrameWith(Rect windowBounds, int centerX, int centerY) {
+ /**
+ * Sets the window size with given width and height in pixels without changing the
+ * window center. The width or the height will be clamped in the range
+ * [{@link #mMinWindowSize}, screen width or height].
+ *
+ * @param width the window width in pixels
+ * @param height the window height in pixels.
+ */
+ public void setWindowSize(int width, int height) {
+ setWindowSizeAndCenter(width, height, Float.NaN, Float.NaN);
+ }
+
+ void setWindowSizeAndCenter(int width, int height, float centerX, float centerY) {
+ width = MathUtils.clamp(width, mMinWindowSize, mWindowBounds.width());
+ height = MathUtils.clamp(height, mMinWindowSize, mWindowBounds.height());
+
+ if (Float.isNaN(centerX)) {
+ centerX = mMagnificationFrame.centerX();
+ }
+ if (Float.isNaN(centerX)) {
+ centerY = mMagnificationFrame.centerY();
+ }
+
+ final int frameWidth = width - 2 * mMirrorSurfaceMargin;
+ final int frameHeight = height - 2 * mMirrorSurfaceMargin;
+ setMagnificationFrame(frameWidth, frameHeight, (int) centerX, (int) centerY);
+ calculateMagnificationFrameBoundary();
+ // Correct the frame position to ensure it is inside the boundary.
+ updateMagnificationFramePosition(0, 0);
+ modifyWindowMagnification(true);
+ }
+
+ private void setMagnificationFrame(int width, int height, int centerX, int centerY) {
// Sets the initial frame area for the mirror and place it to the given center on the
// display.
+ final int initX = centerX - width / 2;
+ final int initY = centerY - height / 2;
+ mMagnificationFrame.set(initX, initY, initX + width, initY + height);
+ }
+
+ private Size getDefaultWindowSizeWithWindowBounds(Rect windowBounds) {
int initSize = Math.min(windowBounds.width(), windowBounds.height()) / 2;
initSize = Math.min(mResources.getDimensionPixelSize(R.dimen.magnification_max_frame_size),
initSize);
initSize += 2 * mMirrorSurfaceMargin;
- final int initX = centerX - initSize / 2;
- final int initY = centerY - initSize / 2;
- mMagnificationFrame.set(initX, initY, initX + initSize, initY + initSize);
+ return new Size(initSize, initSize);
}
/**
@@ -596,8 +637,7 @@
}
mTransaction.show(mMirrorSurface)
.reparent(mMirrorSurface, mMirrorSurfaceView.getSurfaceControl());
-
- modifyWindowMagnification(mTransaction);
+ modifyWindowMagnification(false);
}
private void addDragTouchListeners() {
@@ -615,18 +655,25 @@
}
/**
- * Modifies the placement of the mirrored content when the position of mMirrorView is updated.
+ * Modifies the placement of the mirrored content when the position or size of mMirrorView is
+ * updated.
+ *
+ * @param computeWindowSize set to {@code true} to compute window size with
+ * {@link #mMagnificationFrame}.
*/
- private void modifyWindowMagnification(SurfaceControl.Transaction t) {
+ private void modifyWindowMagnification(boolean computeWindowSize) {
mSfVsyncFrameProvider.postFrameCallback(mMirrorViewGeometryVsyncCallback);
- updateMirrorViewLayout();
+ updateMirrorViewLayout(computeWindowSize);
}
/**
- * Updates the layout params of MirrorView and translates MirrorView position when the view is
- * moved close to the screen edges.
+ * Updates the layout params of MirrorView based on the size of {@link #mMagnificationFrame}
+ * and translates MirrorView position when the view is moved close to the screen edges;
+ *
+ * @param computeWindowSize set to {@code true} to compute window size with
+ * {@link #mMagnificationFrame}.
*/
- private void updateMirrorViewLayout() {
+ private void updateMirrorViewLayout(boolean computeWindowSize) {
if (!isWindowVisible()) {
return;
}
@@ -637,6 +684,10 @@
(LayoutParams) mMirrorView.getLayoutParams();
params.x = mMagnificationFrame.left - mMirrorSurfaceMargin;
params.y = mMagnificationFrame.top - mMirrorSurfaceMargin;
+ if (computeWindowSize) {
+ params.width = mMagnificationFrame.width() + 2 * mMirrorSurfaceMargin;
+ params.height = mMagnificationFrame.height() + 2 * mMirrorSurfaceMargin;
+ }
// Translates MirrorView position to make MirrorSurfaceView that is inside MirrorView
// able to move close to the screen edges.
@@ -899,7 +950,7 @@
createMirrorWindow();
showControls();
} else {
- modifyWindowMagnification(mTransaction);
+ modifyWindowMagnification(false);
}
}
@@ -930,7 +981,7 @@
return;
}
if (updateMagnificationFramePosition((int) offsetX, (int) offsetY)) {
- modifyWindowMagnification(mTransaction);
+ modifyWindowMagnification(false);
}
}
@@ -1014,9 +1065,15 @@
pw.println(" mOverlapWithGestureInsets:" + mOverlapWithGestureInsets);
pw.println(" mScale:" + mScale);
pw.println(" mMirrorViewBounds:" + (isWindowVisible() ? mMirrorViewBounds : "empty"));
+ pw.println(" mMagnificationFrameBoundary:"
+ + (isWindowVisible() ? mMagnificationFrameBoundary : "empty"));
+ pw.println(" mMagnificationFrame:"
+ + (isWindowVisible() ? mMagnificationFrame : "empty"));
pw.println(" mSourceBounds:"
+ (isWindowVisible() ? mSourceBounds : "empty"));
pw.println(" mSystemGestureTop:" + mSystemGestureTop);
+ pw.println(" mMagnificationFrameOffsetX:" + mMagnificationFrameOffsetX);
+ pw.println(" mMagnificationFrameOffsetY:" + mMagnificationFrameOffsetY);
}
private class MirrorWindowA11yDelegate extends View.AccessibilityDelegate {
diff --git a/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java b/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java
index aedaf96..dfff00b 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.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 @@
};
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 @@
@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 @@
}
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 f82ea79..99f27d7 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.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 @@
* 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 @@
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 @@
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 @@
}
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 @@
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 7204a15..7efdd1a 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 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 @@
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 @@
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 @@
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 @@
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 @@
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 3ece3cc..5ac21ff 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
@@ -18,8 +18,10 @@
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;
import android.util.MathUtils;
import android.view.MotionEvent;
@@ -30,6 +32,7 @@
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;
@@ -47,6 +50,7 @@
* Class that coordinates non-HBM animations during keyguard authentication.
*/
public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<UdfpsKeyguardView> {
+ public static final String TAG = "UdfpsKeyguardViewCtrl";
@NonNull private final StatusBarKeyguardViewManager mKeyguardViewManager;
@NonNull private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@NonNull private final LockscreenShadeTransitionController mLockScreenShadeTransitionController;
@@ -57,6 +61,7 @@
@NonNull private final UnlockedScreenOffAnimationController
mUnlockedScreenOffAnimationController;
@NonNull private final ActivityLaunchAnimator mActivityLaunchAnimator;
+ private final ValueAnimator mUnlockedScreenOffDozeAnimator = ValueAnimator.ofFloat(0f, 1f);
private boolean mShowingUdfpsBouncer;
private boolean mUdfpsRequested;
@@ -105,6 +110,18 @@
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
@@ -141,7 +158,6 @@
mKeyguardViewManager.setAlternateAuthInterceptor(mAlternateAuthInterceptor);
mLockScreenShadeTransitionController.setUdfpsKeyguardViewController(this);
- mUnlockedScreenOffAnimationController.addCallback(mUnlockedScreenOffCallback);
mActivityLaunchAnimator.addListener(mActivityLaunchAnimatorListener);
}
@@ -159,7 +175,6 @@
if (mLockScreenShadeTransitionController.getUdfpsKeyguardViewController() == this) {
mLockScreenShadeTransitionController.setUdfpsKeyguardViewController(null);
}
- mUnlockedScreenOffAnimationController.removeCallback(mUnlockedScreenOffCallback);
mActivityLaunchAnimator.removeListener(mActivityLaunchAnimatorListener);
}
@@ -177,6 +192,7 @@
pw.println("mUdfpsRequested=" + mUdfpsRequested);
pw.println("mView.mUdfpsRequested=" + mView.mUdfpsRequested);
pw.println("mLaunchTransitionFadingAway=" + mLaunchTransitionFadingAway);
+ pw.println("mLastDozeAmount=" + mLastDozeAmount);
}
/**
@@ -237,7 +253,11 @@
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;
}
@@ -246,7 +266,12 @@
}
if (mInputBouncerHiddenAmount < .5f || mIsBouncerVisible) {
- return true;
+ if (!getStatusBarStateController().isDozing()) {
+ return true;
+ } else {
+ Log.e(TAG, "Bouncer state claims visible on doze hiddenAmount="
+ + mInputBouncerHiddenAmount + " bouncerVisible=" + mIsBouncerVisible);
+ }
}
return false;
@@ -292,6 +317,10 @@
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
@@ -320,7 +349,18 @@
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();
}
@@ -439,9 +479,6 @@
}
};
- 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/chooser/ChooserActivity.java b/packages/SystemUI/src/com/android/systemui/chooser/ChooserActivity.java
deleted file mode 100644
index 28a3808..0000000
--- a/packages/SystemUI/src/com/android/systemui/chooser/ChooserActivity.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2017 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.chooser;
-
-import android.app.Activity;
-import android.os.Bundle;
-
-/**
- * Activity for selecting which application ought to handle an ACTION_SEND intent.
- */
-public final class ChooserActivity extends Activity {
-
- private static final String TAG = "ChooserActivity";
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- ChooserHelper.onChoose(this);
- finish();
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/chooser/ChooserHelper.java b/packages/SystemUI/src/com/android/systemui/chooser/ChooserHelper.java
deleted file mode 100644
index 6c1da47..0000000
--- a/packages/SystemUI/src/com/android/systemui/chooser/ChooserHelper.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2017 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.chooser;
-
-import android.app.Activity;
-import android.app.ActivityTaskManager;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.StrictMode;
-
-/**
- * When a target is chosen from the SystemUI Chooser activity, unpack its arguments and
- * startActivityAsCaller to handle the now-chosen intent.
- */
-public class ChooserHelper {
-
- private static final String TAG = "ChooserHelper";
-
- static void onChoose(Activity activity) {
- final Intent thisIntent = activity.getIntent();
- final Bundle thisExtras = thisIntent.getExtras();
- final Intent chosenIntent = thisIntent.getParcelableExtra(Intent.EXTRA_INTENT);
- final Bundle options = thisIntent.getParcelableExtra(ActivityTaskManager.EXTRA_OPTIONS);
- final IBinder permissionToken =
- thisExtras.getBinder(ActivityTaskManager.EXTRA_PERMISSION_TOKEN);
- final boolean ignoreTargetSecurity =
- thisIntent.getBooleanExtra(ActivityTaskManager.EXTRA_IGNORE_TARGET_SECURITY, false);
- final int userId = thisIntent.getIntExtra(Intent.EXTRA_USER_ID, -1);
-
- // We're dispatching intents that might be coming from legacy apps, so
- // (as in com.android.internal.app.ResolverActivity) exempt ourselves from death.
- StrictMode.disableDeathOnFileUriExposure();
- try {
- activity.startActivityAsCaller(
- chosenIntent, options, permissionToken, ignoreTargetSecurity, userId);
- } finally {
- StrictMode.enableDeathOnFileUriExposure();
- }
- }
-}
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 f87fa96..5c1d8c3 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.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.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 @@
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 @@
},
true /* blockable */
),
- isAuthRequired(cvh)
+ isAuthRequired(cvh, mAllowTrivialControls)
)
}
@@ -100,7 +127,7 @@
},
blockable
),
- isAuthRequired(cvh)
+ isAuthRequired(cvh, mAllowTrivialControls)
)
}
@@ -120,7 +147,7 @@
{ cvh.action(FloatAction(templateId, newValue)) },
false /* blockable */
),
- isAuthRequired(cvh)
+ isAuthRequired(cvh, mAllowTrivialControls)
)
}
@@ -139,7 +166,7 @@
},
false /* blockable */
),
- isAuthRequired(cvh)
+ isAuthRequired(cvh, mAllowTrivialControls)
)
}
@@ -156,7 +183,11 @@
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/FrameworkServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
index bd472a4..71c538d 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
@@ -71,6 +71,7 @@
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.CaptioningManager;
import android.view.inputmethod.InputMethodManager;
import com.android.internal.app.IBatteryStats;
@@ -120,6 +121,12 @@
@Provides
@Singleton
+ static CaptioningManager provideCaptioningManager(Context context) {
+ return context.getSystemService(CaptioningManager.class);
+ }
+
+ @Provides
+ @Singleton
static ColorDisplayManager provideColorDisplayManager(Context context) {
return context.getSystemService(ColorDisplayManager.class);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
index b32f878..2f041ac 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 @@
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 @@
*/
@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 a4da6b4..5d154c3 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.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 @@
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 13067bf..2799301 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.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 @@
WalletModule.class
},
subcomponents = {
- StatusBarComponent.class,
+ CentralSurfacesComponent.class,
NotificationRowComponent.class,
DozeComponent.class,
ExpandableNotificationRowComponent.class,
@@ -175,7 +175,7 @@
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 2beed4c..d89c0be 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 @@
boolean isPowerSaveActive();
boolean isPulsingBlocked();
boolean isProvisioned();
- boolean isBlockingDoze();
/**
* Makes a current pulse last for twice as long.
@@ -80,8 +79,9 @@
*/
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 @@
*/
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 2511520..0a2e69f 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 @@
}
/**
- * 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 @@
}
/**
- * 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 new AOD sreen brightness to logs
+ * 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 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 4ba6b51..f3f6be2 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 @@
})
}
- 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 @@
})
}
- 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 789ad62..ae01f0a 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 @@
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 @@
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 0000000..31d43b5
--- /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 8bff3ba..74044e2 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 @@
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 @@
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 @@
mDozeLog.tracePulseDropped("pulseOnNotificationsDisabled");
return;
}
- if (mDozeHost.isDozeSuppressed()) {
+ if (mDozeHost.isAlwaysOnSuppressed()) {
runIfNotNull(onPulseSuppressedListener);
mDozeLog.tracePulseDropped("dozeSuppressed");
return;
@@ -456,10 +451,9 @@
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 @@
}
}
-
- 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 @@
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 @@
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 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/DreamOverlayContainerViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
index be76e8f..3d3e4a4 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
@@ -18,12 +18,10 @@
import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
-import android.graphics.Rect;
-import android.graphics.Region;
import android.os.Handler;
+import android.util.MathUtils;
import android.view.View;
import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
@@ -59,45 +57,14 @@
// The interval in milliseconds between burn-in protection updates.
private final long mBurnInProtectionUpdateInterval;
+ // Amount of time in milliseconds to linear interpolate toward the final jitter offset. Once
+ // this time is achieved, the normal jitter algorithm applies in full.
+ private final long mMillisUntilFullJitter;
+
// Main thread handler used to schedule periodic tasks (e.g. burn-in protection updates).
private final Handler mHandler;
- // A hook into the internal inset calculation where we declare the overlays as the only
- // touchable regions.
- private final ViewTreeObserver.OnComputeInternalInsetsListener
- mOnComputeInternalInsetsListener =
- new ViewTreeObserver.OnComputeInternalInsetsListener() {
- @Override
- public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo inoutInfo) {
- inoutInfo.setTouchableInsets(
- ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
- final Region region = new Region();
- final Rect rect = new Rect();
- final int childCount = mDreamOverlayContentView.getChildCount();
- for (int i = 0; i < childCount; i++) {
- View child = mDreamOverlayContentView.getChildAt(i);
-
- if (mComplicationHostViewController.getView() == child) {
- region.op(mComplicationHostViewController.getTouchRegions(),
- Region.Op.UNION);
- continue;
- }
-
- if (child.getGlobalVisibleRect(rect)) {
- region.op(rect, Region.Op.UNION);
- }
- }
-
- // Add the notifications drag area to the tap region (otherwise the
- // notifications shade can't be dragged down).
- if (mDreamOverlayContentView.getGlobalVisibleRect(rect)) {
- rect.bottom = rect.top + mDreamOverlayNotificationsDragAreaHeight;
- region.op(rect, Region.Op.UNION);
- }
-
- inoutInfo.touchableRegion.set(region);
- }
- };
+ private long mJitterStartTimeMillis;
@Inject
public DreamOverlayContainerViewController(
@@ -108,7 +75,8 @@
@Main Handler handler,
@Named(DreamOverlayModule.MAX_BURN_IN_OFFSET) int maxBurnInOffset,
@Named(DreamOverlayModule.BURN_IN_PROTECTION_UPDATE_INTERVAL) long
- burnInProtectionUpdateInterval) {
+ burnInProtectionUpdateInterval,
+ @Named(DreamOverlayModule.MILLIS_UNTIL_FULL_JITTER) long millisUntilFullJitter) {
super(containerView);
mDreamOverlayContentView = contentView;
mStatusBarViewController = statusBarViewController;
@@ -126,6 +94,7 @@
mHandler = handler;
mMaxBurnInOffset = maxBurnInOffset;
mBurnInProtectionUpdateInterval = burnInProtectionUpdateInterval;
+ mMillisUntilFullJitter = millisUntilFullJitter;
}
@Override
@@ -136,16 +105,13 @@
@Override
protected void onViewAttached() {
- mView.getViewTreeObserver()
- .addOnComputeInternalInsetsListener(mOnComputeInternalInsetsListener);
+ mJitterStartTimeMillis = System.currentTimeMillis();
mHandler.postDelayed(this::updateBurnInOffsets, mBurnInProtectionUpdateInterval);
}
@Override
protected void onViewDetached() {
mHandler.removeCallbacks(this::updateBurnInOffsets);
- mView.getViewTreeObserver()
- .removeOnComputeInternalInsetsListener(mOnComputeInternalInsetsListener);
}
View getContainerView() {
@@ -158,12 +124,24 @@
}
private void updateBurnInOffsets() {
+ int burnInOffset = mMaxBurnInOffset;
+
+ // Make sure the offset starts at zero, to avoid a big jump in the overlay when it first
+ // appears.
+ long millisSinceStart = System.currentTimeMillis() - mJitterStartTimeMillis;
+ if (millisSinceStart < mMillisUntilFullJitter) {
+ float lerpAmount = (float) millisSinceStart / (float) mMillisUntilFullJitter;
+ burnInOffset = Math.round(MathUtils.lerp(0f, burnInOffset, lerpAmount));
+ }
+
// These translation values change slowly, and the set translation methods are idempotent,
// so no translation occurs when the values don't change.
- mView.setTranslationX(getBurnInOffset(mMaxBurnInOffset * 2, true)
- - mMaxBurnInOffset);
- mView.setTranslationY(getBurnInOffset(mMaxBurnInOffset * 2, false)
- - mMaxBurnInOffset);
+ int burnInOffsetX = getBurnInOffset(burnInOffset * 2, true)
+ - burnInOffset;
+ int burnInOffsetY = getBurnInOffset(burnInOffset * 2, false)
+ - burnInOffset;
+ mView.setTranslationX(burnInOffsetX);
+ mView.setTranslationY(burnInOffsetY);
mHandler.postDelayed(this::updateBurnInOffsets, mBurnInProtectionUpdateInterval);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayDotImageView.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayDotImageView.java
new file mode 100644
index 0000000..02a8b39a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayDotImageView.java
@@ -0,0 +1,128 @@
+/*
+ * 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.dreams;
+
+import android.annotation.ColorInt;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.AlphaOptimizedImageView;
+
+/**
+ * An {@link AlphaOptimizedImageView} that is responsible for rendering a dot. Used by
+ * {@link DreamOverlayStatusBarView}.
+ */
+public class DreamOverlayDotImageView extends AlphaOptimizedImageView {
+ private final @ColorInt int mDotColor;
+
+ public DreamOverlayDotImageView(Context context) {
+ this(context, null);
+ }
+
+ public DreamOverlayDotImageView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public DreamOverlayDotImageView(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public DreamOverlayDotImageView(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ TypedArray a = context.getTheme().obtainStyledAttributes(attrs,
+ R.styleable.DreamOverlayDotImageView, 0, 0);
+
+ try {
+ mDotColor = a.getColor(R.styleable.DreamOverlayDotImageView_dotColor, Color.WHITE);
+ } finally {
+ a.recycle();
+ }
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ setImageDrawable(new DotDrawable(mDotColor));
+ }
+
+ private static class DotDrawable extends Drawable {
+ private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ private Bitmap mDotBitmap;
+ private final Rect mBounds = new Rect();
+ private final @ColorInt int mDotColor;
+
+ DotDrawable(@ColorInt int color) {
+ mDotColor = color;
+ }
+
+ @Override
+ public void draw(@NonNull Canvas canvas) {
+ if (mBounds.isEmpty()) {
+ return;
+ }
+
+ if (mDotBitmap == null) {
+ mDotBitmap = createBitmap(mBounds.width(), mBounds.height());
+ }
+
+ canvas.drawBitmap(mDotBitmap, null, mBounds, mPaint);
+ }
+
+ @Override
+ protected void onBoundsChange(Rect bounds) {
+ super.onBoundsChange(bounds);
+ mBounds.set(bounds.left, bounds.top, bounds.right, bounds.bottom);
+ // Make sure to regenerate the dot bitmap when the bounds change.
+ mDotBitmap = null;
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ }
+
+ @Override
+ public void setColorFilter(@Nullable ColorFilter colorFilter) {
+ }
+
+ @Override
+ public int getOpacity() {
+ return 0;
+ }
+
+ private Bitmap createBitmap(int width, int height) {
+ Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(bitmap);
+ Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ paint.setColor(mDotColor);
+ canvas.drawCircle(width / 2.f, height / 2.f, Math.min(width, height) / 2.f, paint);
+ return bitmap;
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
index 338a8b2..7e1fce2 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
@@ -33,6 +33,7 @@
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dreams.complication.Complication;
+import com.android.systemui.dreams.complication.DreamPreviewComplication;
import com.android.systemui.dreams.dagger.DreamOverlayComponent;
import com.android.systemui.dreams.touch.DreamOverlayTouchMonitor;
@@ -57,6 +58,7 @@
// content area).
private final DreamOverlayContainerViewController mDreamOverlayContainerViewController;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ private final DreamPreviewComplication mPreviewComplication;
// A reference to the {@link Window} used to hold the dream overlay.
private Window mWindow;
@@ -96,12 +98,14 @@
@Main Executor executor,
DreamOverlayComponent.Factory dreamOverlayComponentFactory,
DreamOverlayStateController stateController,
- KeyguardUpdateMonitor keyguardUpdateMonitor) {
+ KeyguardUpdateMonitor keyguardUpdateMonitor,
+ DreamPreviewComplication previewComplication) {
mContext = context;
mExecutor = executor;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mKeyguardUpdateMonitor.registerCallback(mKeyguardCallback);
mStateController = stateController;
+ mPreviewComplication = previewComplication;
final DreamOverlayComponent component =
dreamOverlayComponentFactory.create(mViewModelStore, mHost);
@@ -125,6 +129,9 @@
windowManager.removeView(mWindow.getDecorView());
}
mStateController.setOverlayActive(false);
+ mPreviewComplication.setDreamLabel(null);
+ mStateController.removeComplication(mPreviewComplication);
+ mStateController.setPreviewMode(false);
super.onDestroy();
}
@@ -133,6 +140,11 @@
setCurrentState(Lifecycle.State.STARTED);
mExecutor.execute(() -> {
mStateController.setShouldShowComplications(shouldShowComplications());
+ mStateController.setPreviewMode(isPreviewMode());
+ if (isPreviewMode()) {
+ mPreviewComplication.setDreamLabel(getDreamLabel());
+ mStateController.addComplication(mPreviewComplication);
+ }
addOverlayWindowLocked(layoutParams);
setCurrentState(Lifecycle.State.RESUMED);
mStateController.setOverlayActive(true);
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
index fc71e2f..6860998 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
@@ -50,6 +50,7 @@
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
public static final int STATE_DREAM_OVERLAY_ACTIVE = 1 << 0;
+ public static final int STATE_PREVIEW_MODE = 1 << 1;
private static final int OP_CLEAR_STATE = 1;
private static final int OP_SET_STATE = 2;
@@ -249,4 +250,18 @@
mCallbacks.forEach(Callback::onAvailableComplicationTypesChanged);
});
}
+
+ /**
+ * Sets whether the dream is running in preview mode.
+ */
+ public void setPreviewMode(boolean isPreviewMode) {
+ modifyState(isPreviewMode ? OP_SET_STATE : OP_CLEAR_STATE, STATE_PREVIEW_MODE);
+ }
+
+ /**
+ * Returns whether the dream is running in preview mode.
+ */
+ public boolean isPreviewMode() {
+ return containsState(STATE_PREVIEW_MODE);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java
index 9847ef6..d2ab611 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java
@@ -16,27 +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 com.android.systemui.battery.BatteryMeterView;
-import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
+
+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 includes status icons such as battery and wifi.
+ * dream. The status bar displays conditional status icons such as "priority mode" and "no wifi".
*/
-public class DreamOverlayStatusBarView extends ConstraintLayout implements
- BatteryStateChangeCallback {
+public class DreamOverlayStatusBarView extends ConstraintLayout {
- private BatteryMeterView mBatteryView;
- 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);
@@ -59,28 +76,35 @@
protected void onFinishInflate() {
super.onFinishInflate();
- mBatteryView = Preconditions.checkNotNull(findViewById(R.id.dream_overlay_battery),
- "R.id.dream_overlay_battery must not be null");
- mWifiStatusView = Preconditions.checkNotNull(findViewById(R.id.dream_overlay_wifi_status),
- "R.id.dream_overlay_wifi_status must not be null");
-
- mWifiStatusView.setImageDrawable(getContext().getDrawable(R.drawable.ic_signal_wifi_off));
+ 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));
}
- /**
- * Whether to show the battery percent text next to the battery status icons.
- * @param show True if the battery percent text should be shown.
- */
- void showBatteryPercentText(boolean show) {
- mBatteryView.setForceShowPercent(show);
+ void showIcon(@StatusIconType int iconType, boolean show) {
+ showIcon(iconType, show, null);
}
- /**
- * 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);
+ 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);
+ }
+
+ 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 5674b9f..a25a742 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
@@ -16,57 +16,52 @@
package com.android.systemui.dreams;
-import android.annotation.IntDef;
-import android.content.Context;
+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.battery.BatteryMeterViewController;
+import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dreams.dagger.DreamOverlayComponent;
-import com.android.systemui.dreams.dagger.DreamOverlayModule;
-import com.android.systemui.statusbar.policy.BatteryController;
+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;
-import javax.inject.Named;
/**
* View controller for {@link DreamOverlayStatusBarView}.
*/
@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;
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = { "BATTERY_STATUS_" }, value = {
- BATTERY_STATUS_UNKNOWN,
- BATTERY_STATUS_NOT_CHARGING,
- BATTERY_STATUS_CHARGING
- })
- private @interface BatteryStatus {}
- private static final int BATTERY_STATUS_UNKNOWN = 0;
- private static final int BATTERY_STATUS_NOT_CHARGING = 1;
- private static final int BATTERY_STATUS_CHARGING = 2;
-
- private final BatteryController mBatteryController;
- private final BatteryMeterViewController mBatteryMeterViewController;
private final ConnectivityManager mConnectivityManager;
- private final boolean mShowPercentAvailable;
+ 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()
@@ -76,97 +71,183 @@
@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 final BatteryController.BatteryStateChangeCallback mBatteryStateChangeCallback =
- new BatteryController.BatteryStateChangeCallback() {
- @Override
- public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
- DreamOverlayStatusBarViewController.this.onBatteryLevelChanged(charging);
- }
- };
+ private final IndividualSensorPrivacyController.Callback mSensorCallback =
+ (sensor, blocked) -> updateMicCameraBlockedStatusIcon();
- private @WifiStatus int mWifiStatus = WIFI_STATUS_UNKNOWN;
- private @BatteryStatus int mBatteryStatus = BATTERY_STATUS_UNKNOWN;
+ 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(
- Context context,
DreamOverlayStatusBarView view,
- BatteryController batteryController,
- @Named(DreamOverlayModule.DREAM_OVERLAY_BATTERY_CONTROLLER)
- BatteryMeterViewController batteryMeterViewController,
- ConnectivityManager connectivityManager) {
+ @Main Resources resources,
+ ConnectivityManager connectivityManager,
+ TouchInsetManager.TouchInsetSession touchInsetSession,
+ AlarmManager alarmManager,
+ NextAlarmController nextAlarmController,
+ DateFormatUtil dateFormatUtil,
+ IndividualSensorPrivacyController sensorPrivacyController,
+ NotificationListener notificationListener,
+ ZenModeController zenModeController) {
super(view);
- mBatteryController = batteryController;
- mBatteryMeterViewController = batteryMeterViewController;
+ mResources = resources;
mConnectivityManager = connectivityManager;
+ mTouchInsetSession = touchInsetSession;
+ mAlarmManager = alarmManager;
+ mNextAlarmController = nextAlarmController;
+ mDateFormatUtil = dateFormatUtil;
+ mSensorPrivacyController = sensorPrivacyController;
+ mNotificationListener = notificationListener;
+ mZenModeController = zenModeController;
- mShowPercentAvailable = context.getResources().getBoolean(
- com.android.internal.R.bool.config_battery_percentage_setting_available);
- }
-
- @Override
- protected void onInit() {
- super.onInit();
- mBatteryMeterViewController.init();
+ // 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() {
- mBatteryController.addCallback(mBatteryStateChangeCallback);
- mConnectivityManager.registerNetworkCallback(mNetworkRequest, mNetworkCallback);
+ updateNotificationsStatusIcon();
- NetworkCapabilities capabilities =
- mConnectivityManager.getNetworkCapabilities(
- mConnectivityManager.getActiveNetwork());
- onWifiAvailabilityChanged(
- capabilities != null
- && capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI));
+ mConnectivityManager.registerNetworkCallback(mNetworkRequest, mNetworkCallback);
+ updateWifiUnavailableStatusIcon();
+
+ mNextAlarmController.addCallback(mNextAlarmCallback);
+ updateAlarmStatusIcon();
+
+ mSensorPrivacyController.addCallback(mSensorCallback);
+ updateMicCameraBlockedStatusIcon();
+
+ mZenModeController.addCallback(mZenModeCallback);
+ updatePriorityModeStatusIcon();
+
+ mTouchInsetSession.addViewToTracking(mView);
}
@Override
protected void onViewDetached() {
- mBatteryController.removeCallback(mBatteryStateChangeCallback);
+ 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);
}
- /**
- * The battery level has changed. Update the battery status icon as appropriate.
- * @param charging Whether the battery is currently charging.
- */
- private void onBatteryLevelChanged(boolean charging) {
- final int newBatteryStatus =
- charging ? BATTERY_STATUS_CHARGING : BATTERY_STATUS_NOT_CHARGING;
- if (mBatteryStatus != newBatteryStatus) {
- mBatteryStatus = newBatteryStatus;
- mView.showBatteryPercentText(
- mBatteryStatus == BATTERY_STATUS_CHARGING && mShowPercentAvailable);
+ 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/SmartSpaceComplication.java b/packages/SystemUI/src/com/android/systemui/dreams/SmartSpaceComplication.java
index 240389a..a5dcd39 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/SmartSpaceComplication.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/SmartSpaceComplication.java
@@ -59,7 +59,19 @@
@Override
public void start() {
- if (mSmartSpaceController.isEnabled()) {
+ addOrRemoveOverlay();
+ mDreamOverlayStateController.addCallback(new DreamOverlayStateController.Callback() {
+ @Override
+ public void onStateChanged() {
+ addOrRemoveOverlay();
+ }
+ });
+ }
+
+ private void addOrRemoveOverlay() {
+ if (mDreamOverlayStateController.isPreviewMode()) {
+ mDreamOverlayStateController.removeComplication(mComplication);
+ } else if (mSmartSpaceController.isEnabled()) {
mDreamOverlayStateController.addComplication(mComplication);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutEngine.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutEngine.java
index 0b80d8a..437e799 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutEngine.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutEngine.java
@@ -27,6 +27,7 @@
import androidx.constraintlayout.widget.Constraints;
import com.android.systemui.R;
+import com.android.systemui.touch.TouchInsetManager;
import java.util.ArrayList;
import java.util.Collections;
@@ -52,6 +53,7 @@
private static class ViewEntry implements Comparable<ViewEntry> {
private final View mView;
private final ComplicationLayoutParams mLayoutParams;
+ private final TouchInsetManager.TouchInsetSession mTouchInsetSession;
private final Parent mParent;
@Complication.Category
private final int mCategory;
@@ -61,7 +63,8 @@
* Default constructor. {@link Parent} allows for the {@link ViewEntry}'s surrounding
* view hierarchy to be accessed without traversing the entire view tree.
*/
- ViewEntry(View view, ComplicationLayoutParams layoutParams, int category, Parent parent,
+ ViewEntry(View view, ComplicationLayoutParams layoutParams,
+ TouchInsetManager.TouchInsetSession touchSession, int category, Parent parent,
int margin) {
mView = view;
// Views that are generated programmatically do not have a unique id assigned to them
@@ -70,9 +73,12 @@
// {@link Complication.ViewHolder} should not reference the root container by id.
mView.setId(View.generateViewId());
mLayoutParams = layoutParams;
+ mTouchInsetSession = touchSession;
mCategory = category;
mParent = parent;
mMargin = margin;
+
+ touchSession.addViewToTracking(mView);
}
/**
@@ -217,6 +223,7 @@
mParent.removeEntry(this);
((ViewGroup) mView.getParent()).removeView(mView);
+ mTouchInsetSession.removeViewFromTracking(mView);
}
@Override
@@ -242,15 +249,18 @@
*/
private static class Builder {
private final View mView;
+ private final TouchInsetManager.TouchInsetSession mTouchSession;
private final ComplicationLayoutParams mLayoutParams;
private final int mCategory;
private Parent mParent;
private int mMargin;
- Builder(View view, ComplicationLayoutParams lp, @Complication.Category int category) {
+ Builder(View view, TouchInsetManager.TouchInsetSession touchSession,
+ ComplicationLayoutParams lp, @Complication.Category int category) {
mView = view;
mLayoutParams = lp;
mCategory = category;
+ mTouchSession = touchSession;
}
/**
@@ -291,7 +301,8 @@
* Builds and returns the resulting {@link ViewEntry}.
*/
ViewEntry build() {
- return new ViewEntry(mView, mLayoutParams, mCategory, mParent, mMargin);
+ return new ViewEntry(mView, mLayoutParams, mTouchSession, mCategory, mParent,
+ mMargin);
}
}
@@ -442,13 +453,16 @@
private final int mMargin;
private final HashMap<ComplicationId, ViewEntry> mEntries = new HashMap<>();
private final HashMap<Integer, PositionGroup> mPositions = new HashMap<>();
+ private final TouchInsetManager.TouchInsetSession mSession;
/** */
@Inject
public ComplicationLayoutEngine(@Named(SCOPED_COMPLICATIONS_LAYOUT) ConstraintLayout layout,
- @Named(COMPLICATION_MARGIN) int margin) {
+ @Named(COMPLICATION_MARGIN) int margin,
+ TouchInsetManager.TouchInsetSession session) {
mLayout = layout;
mMargin = margin;
+ mSession = session;
}
/**
@@ -468,7 +482,7 @@
removeComplication(id);
}
- final ViewEntry.Builder entryBuilder = new ViewEntry.Builder(view, lp, category)
+ final ViewEntry.Builder entryBuilder = new ViewEntry.Builder(view, mSession, lp, category)
.setMargin(mMargin);
// Add position group if doesn't already exist
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamPreviewComplication.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamPreviewComplication.java
new file mode 100644
index 0000000..cc2e571
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamPreviewComplication.java
@@ -0,0 +1,137 @@
+/*
+ * 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.dreams.complication;
+
+import static com.android.systemui.dreams.complication.dagger.DreamPreviewComplicationComponent.DREAM_LABEL;
+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;
+
+import androidx.annotation.Nullable;
+
+import com.android.systemui.dreams.complication.dagger.DreamPreviewComplicationComponent;
+import com.android.systemui.util.ViewController;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+/**
+ * Preview complication shown when user is previewing a dream.
+ */
+public class DreamPreviewComplication implements Complication {
+ DreamPreviewComplicationComponent.Factory mComponentFactory;
+ @Nullable
+ private CharSequence mDreamLabel;
+
+ /**
+ * Default constructor for {@link DreamPreviewComplication}.
+ */
+ @Inject
+ public DreamPreviewComplication(
+ DreamPreviewComplicationComponent.Factory componentFactory) {
+ mComponentFactory = componentFactory;
+ }
+
+ /**
+ * Create {@link DreamPreviewViewHolder}.
+ */
+ @Override
+ public ViewHolder createView(ComplicationViewModel model) {
+ return mComponentFactory.create(model, mDreamLabel).getViewHolder();
+ }
+
+ /**
+ * Sets the user-facing label for the current dream.
+ */
+ public void setDreamLabel(@Nullable CharSequence dreamLabel) {
+ mDreamLabel = dreamLabel;
+ }
+
+ /**
+ * ViewHolder to contain value/logic associated with a Preview Complication View.
+ */
+ public static class DreamPreviewViewHolder implements ViewHolder {
+ private final TextView mView;
+ private final ComplicationLayoutParams mLayoutParams;
+ private final DreamPreviewViewController mViewController;
+
+ @Inject
+ DreamPreviewViewHolder(@Named(DREAM_PREVIEW_COMPLICATION_VIEW) TextView view,
+ DreamPreviewViewController controller,
+ @Named(DREAM_PREVIEW_COMPLICATION_LAYOUT_PARAMS)
+ ComplicationLayoutParams layoutParams,
+ @Named(DREAM_LABEL) @Nullable CharSequence dreamLabel) {
+ mView = view;
+ mLayoutParams = layoutParams;
+ mViewController = controller;
+ mViewController.init();
+
+ if (!TextUtils.isEmpty(dreamLabel)) {
+ mView.setText(dreamLabel);
+ }
+ for (Drawable drawable : mView.getCompoundDrawablesRelative()) {
+ if (drawable instanceof BitmapDrawable) {
+ drawable.setAutoMirrored(true);
+ }
+ }
+ }
+
+ @Override
+ public View getView() {
+ return mView;
+ }
+
+ @Override
+ public ComplicationLayoutParams getLayoutParams() {
+ return mLayoutParams;
+ }
+
+ @Override
+ public int getCategory() {
+ return CATEGORY_SYSTEM;
+ }
+ }
+
+ /**
+ * ViewController to contain value/logic associated with a Preview Complication View.
+ */
+ static class DreamPreviewViewController extends ViewController<TextView> {
+ private final ComplicationViewModel mViewModel;
+
+ @Inject
+ DreamPreviewViewController(@Named(DREAM_PREVIEW_COMPLICATION_VIEW) TextView view,
+ ComplicationViewModel viewModel) {
+ super(view);
+ mViewModel = viewModel;
+ }
+
+ @Override
+ protected void onViewAttached() {
+ mView.setOnClickListener(v -> mViewModel.exitDream());
+ }
+
+ @Override
+ protected void onViewDetached() {
+ mView.setOnClickListener(null);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamPreviewComplicationComponent.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamPreviewComplicationComponent.java
new file mode 100644
index 0000000..502e31e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamPreviewComplicationComponent.java
@@ -0,0 +1,117 @@
+/*
+ * 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.dreams.complication.dagger;
+
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import androidx.annotation.Nullable;
+
+import com.android.internal.util.Preconditions;
+import com.android.systemui.R;
+import com.android.systemui.dreams.complication.ComplicationLayoutParams;
+import com.android.systemui.dreams.complication.ComplicationViewModel;
+import com.android.systemui.dreams.complication.DreamPreviewComplication.DreamPreviewViewHolder;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Named;
+import javax.inject.Scope;
+
+import dagger.BindsInstance;
+import dagger.Module;
+import dagger.Provides;
+import dagger.Subcomponent;
+
+/**
+ * {@link DreamPreviewComplicationComponent} is responsible for generating dependencies
+ * surrounding the
+ * Preview {@link com.android.systemui.dreams.complication.Complication}, such as the layout
+ * details.
+ */
+@Subcomponent(modules = {
+ DreamPreviewComplicationComponent.DreamPreviewComplicationModule.class,
+})
+@DreamPreviewComplicationComponent.DreamPreviewComplicationScope
+public interface DreamPreviewComplicationComponent {
+ String DREAM_LABEL = "dream_label";
+
+ /**
+ * Creates {@link DreamPreviewViewHolder}.
+ */
+ DreamPreviewViewHolder getViewHolder();
+
+ @Documented
+ @Retention(RUNTIME)
+ @Scope
+ @interface DreamPreviewComplicationScope {
+ }
+
+ /**
+ * Generates {@link DreamPreviewComplicationComponent}.
+ */
+ @Subcomponent.Factory
+ interface Factory {
+ DreamPreviewComplicationComponent create(
+ @BindsInstance ComplicationViewModel viewModel,
+ @Named(DREAM_LABEL) @BindsInstance @Nullable CharSequence dreamLabel);
+ }
+
+ /**
+ * Scoped values for {@link DreamPreviewComplicationComponent}.
+ */
+ @Module
+ interface DreamPreviewComplicationModule {
+ String DREAM_PREVIEW_COMPLICATION_VIEW = "preview_complication_view";
+ String DREAM_PREVIEW_COMPLICATION_LAYOUT_PARAMS = "preview_complication_layout_params";
+ // Order weight of insert into parent container
+ int INSERT_ORDER_WEIGHT = 1000;
+
+ /**
+ * Provides the complication view.
+ */
+ @Provides
+ @DreamPreviewComplicationScope
+ @Named(DREAM_PREVIEW_COMPLICATION_VIEW)
+ static TextView provideComplicationView(LayoutInflater layoutInflater) {
+ return Preconditions.checkNotNull((TextView)
+ layoutInflater.inflate(R.layout.dream_overlay_complication_preview,
+ null, false),
+ "R.layout.dream_overlay_complication_preview did not properly inflated");
+ }
+
+ /**
+ * Provides the layout parameters for the complication view.
+ */
+ @Provides
+ @DreamPreviewComplicationScope
+ @Named(DREAM_PREVIEW_COMPLICATION_LAYOUT_PARAMS)
+ static ComplicationLayoutParams provideLayoutParams() {
+ return new ComplicationLayoutParams(0,
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ ComplicationLayoutParams.POSITION_TOP
+ | ComplicationLayoutParams.POSITION_START,
+ ComplicationLayoutParams.DIRECTION_DOWN,
+ INSERT_ORDER_WEIGHT, /* snapToGuide= */ true);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java
index c61f796..65f060b 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java
@@ -19,6 +19,7 @@
import android.content.Context;
import com.android.settingslib.dream.DreamBackend;
+import com.android.systemui.dreams.complication.dagger.DreamPreviewComplicationComponent;
import com.android.systemui.dreams.complication.dagger.RegisteredComplicationsModule;
import com.android.systemui.dreams.touch.dagger.DreamTouchModule;
@@ -34,6 +35,7 @@
},
subcomponents = {
DreamOverlayComponent.class,
+ DreamPreviewComplicationComponent.class,
})
public interface DreamModule {
/**
@@ -43,4 +45,4 @@
static DreamBackend providesDreamBackend(Context context) {
return DreamBackend.getInstance(context);
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java
index 4eb5cb9..4fe1622 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java
@@ -16,9 +16,7 @@
package com.android.systemui.dreams.dagger;
-import android.content.ContentResolver;
import android.content.res.Resources;
-import android.os.Handler;
import android.view.LayoutInflater;
import android.view.ViewGroup;
@@ -28,15 +26,12 @@
import com.android.internal.util.Preconditions;
import com.android.systemui.R;
-import com.android.systemui.battery.BatteryMeterView;
-import com.android.systemui.battery.BatteryMeterViewController;
-import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dreams.DreamOverlayContainerView;
import com.android.systemui.dreams.DreamOverlayStatusBarView;
-import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.tuner.TunerService;
+import com.android.systemui.touch.TouchInsetManager;
+
+import java.util.concurrent.Executor;
import javax.inject.Named;
@@ -47,13 +42,11 @@
/** Dagger module for {@link DreamOverlayComponent}. */
@Module
public abstract class DreamOverlayModule {
- private static final String DREAM_OVERLAY_BATTERY_VIEW = "dream_overlay_battery_view";
- public static final String DREAM_OVERLAY_BATTERY_CONTROLLER =
- "dream_overlay_battery_controller";
public static final String DREAM_OVERLAY_CONTENT_VIEW = "dream_overlay_content_view";
public static final String MAX_BURN_IN_OFFSET = "max_burn_in_offset";
public static final String BURN_IN_PROTECTION_UPDATE_INTERVAL =
"burn_in_protection_update_interval";
+ public static final String MILLIS_UNTIL_FULL_JITTER = "millis_until_full_jitter";
/** */
@Provides
@@ -76,6 +69,21 @@
/** */
@Provides
+ public static TouchInsetManager.TouchInsetSession providesTouchInsetSession(
+ TouchInsetManager manager) {
+ return manager.createSession();
+ }
+
+ /** */
+ @Provides
+ @DreamOverlayComponent.DreamOverlayScope
+ public static TouchInsetManager providesTouchInsetManager(@Main Executor executor,
+ DreamOverlayContainerView view) {
+ return new TouchInsetManager(executor, view);
+ }
+
+ /** */
+ @Provides
@DreamOverlayComponent.DreamOverlayScope
public static DreamOverlayStatusBarView providesDreamOverlayStatusBarView(
DreamOverlayContainerView view) {
@@ -86,37 +94,6 @@
/** */
@Provides
@DreamOverlayComponent.DreamOverlayScope
- @Named(DREAM_OVERLAY_BATTERY_VIEW)
- static BatteryMeterView providesBatteryMeterView(DreamOverlayContainerView view) {
- return Preconditions.checkNotNull(view.findViewById(R.id.dream_overlay_battery),
- "R.id.battery must not be null");
- }
-
- /** */
- @Provides
- @DreamOverlayComponent.DreamOverlayScope
- @Named(DREAM_OVERLAY_BATTERY_CONTROLLER)
- static BatteryMeterViewController providesBatteryMeterViewController(
- @Named(DREAM_OVERLAY_BATTERY_VIEW) BatteryMeterView batteryMeterView,
- ConfigurationController configurationController,
- TunerService tunerService,
- BroadcastDispatcher broadcastDispatcher,
- @Main Handler mainHandler,
- ContentResolver contentResolver,
- BatteryController batteryController) {
- return new BatteryMeterViewController(
- batteryMeterView,
- configurationController,
- tunerService,
- broadcastDispatcher,
- mainHandler,
- contentResolver,
- batteryController);
- }
-
- /** */
- @Provides
- @DreamOverlayComponent.DreamOverlayScope
@Named(MAX_BURN_IN_OFFSET)
static int providesMaxBurnInOffset(@Main Resources resources) {
return resources.getDimensionPixelSize(R.dimen.default_burn_in_prevention_offset);
@@ -130,6 +107,13 @@
R.integer.config_dreamOverlayBurnInProtectionUpdateIntervalMillis);
}
+ /** */
+ @Provides
+ @Named(MILLIS_UNTIL_FULL_JITTER)
+ static long providesMillisUntilFullJitter(@Main Resources resources) {
+ return resources.getInteger(R.integer.config_dreamOverlayMillisUntilFullJitter);
+ }
+
@Provides
@DreamOverlayComponent.DreamOverlayScope
static LifecycleOwner providesLifecycleOwner(Lazy<LifecycleRegistry> lifecycleRegistryLazy) {
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 d16c8c8..e140f6b 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_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 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 @@
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 @@
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 @@
// 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 @@
@Inject
public BouncerSwipeTouchHandler(
+ DisplayMetrics displayMetrics,
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
- StatusBar statusBar,
+ CentralSurfaces centralSurfaces,
NotificationShadeWindowController notificationShadeWindowController,
ValueAnimatorCreator valueAnimatorCreator,
VelocityTrackerFactory velocityTrackerFactory,
@@ -165,7 +139,8 @@
@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 @@
}
@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 @@
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 @@
if (expansion == KeyguardBouncer.EXPANSION_HIDDEN) {
mStatusBarKeyguardViewManager.reset(false);
}
- mTouchSession.pop();
break;
default:
mVelocityTracker.addMovement(motionEvent);
@@ -255,7 +246,7 @@
}
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 3e5efb2..695b59a 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.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 @@
});
}
+ 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 @@
return mTouchMonitor.pop(this);
}
+ @Override
+ public int getActiveSessionCount() {
+ return mTouchMonitor.getSessionCount();
+ }
+
/**
* Returns the active listeners to receive touch events.
*/
@@ -229,12 +240,39 @@
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 c73ff73..20008d5 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 @@
* 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/flags/FeatureFlags.kt b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.kt
index 96a90df..9d6e3c2 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.kt
@@ -28,6 +28,9 @@
/** Returns a boolean value for the given flag. */
fun isEnabled(flag: ResourceBooleanFlag): Boolean
+ /** Returns a boolean value for the given flag. */
+ fun isEnabled(flag: SysPropBooleanFlag): Boolean
+
/** Returns a string value for the given flag. */
fun getString(flag: StringFlag): String
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java
index df60599..0c5f7eb 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java
@@ -49,6 +49,7 @@
import java.util.Map;
import java.util.Objects;
import java.util.TreeMap;
+import java.util.function.Consumer;
import java.util.function.Supplier;
import javax.inject.Inject;
@@ -69,6 +70,7 @@
private final FlagManager mFlagManager;
private final SecureSettings mSecureSettings;
private final Resources mResources;
+ private final SystemPropertiesHelper mSystemProperties;
private final Supplier<Map<Integer, Flag<?>>> mFlagsCollector;
private final Map<Integer, Boolean> mBooleanFlagCache = new TreeMap<>();
private final Map<Integer, String> mStringFlagCache = new TreeMap<>();
@@ -79,6 +81,7 @@
FlagManager flagManager,
Context context,
SecureSettings secureSettings,
+ SystemPropertiesHelper systemProperties,
@Main Resources resources,
DumpManager dumpManager,
@Nullable Supplier<Map<Integer, Flag<?>>> flagsCollector,
@@ -86,11 +89,12 @@
mFlagManager = flagManager;
mSecureSettings = secureSettings;
mResources = resources;
+ mSystemProperties = systemProperties;
mFlagsCollector = flagsCollector != null ? flagsCollector : Flags::collectFlags;
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_SET_FLAG);
filter.addAction(ACTION_GET_FLAGS);
- flagManager.setRestartAction(this::restartSystemUI);
+ flagManager.setOnSettingsChangedAction(this::restartSystemUI);
flagManager.setClearCacheAction(this::removeFromCache);
context.registerReceiver(mReceiver, filter, null, null,
Context.RECEIVER_EXPORTED_UNAUDITED);
@@ -121,6 +125,17 @@
return mBooleanFlagCache.get(id);
}
+ @Override
+ public boolean isEnabled(@NonNull SysPropBooleanFlag flag) {
+ int id = flag.getId();
+ if (!mBooleanFlagCache.containsKey(id)) {
+ mBooleanFlagCache.put(
+ id, mSystemProperties.getBoolean(flag.getName(), flag.getDefault()));
+ }
+
+ return mBooleanFlagCache.get(id);
+ }
+
@NonNull
@Override
public String getString(@NonNull StringFlag flag) {
@@ -180,16 +195,28 @@
mSecureSettings.putString(mFlagManager.idToSettingsKey(id), data);
Log.i(TAG, "Set id " + id + " to " + value);
removeFromCache(id);
- mFlagManager.dispatchListenersAndMaybeRestart(id);
+ mFlagManager.dispatchListenersAndMaybeRestart(id, this::restartSystemUI);
+ }
+
+ private <T> void eraseFlag(Flag<T> flag) {
+ if (flag instanceof SysPropFlag) {
+ mSystemProperties.erase(((SysPropFlag<T>) flag).getName());
+ dispatchListenersAndMaybeRestart(flag.getId(), this::restartAndroid);
+ } else {
+ eraseFlag(flag.getId());
+ }
}
/** Erase a flag's overridden value if there is one. */
- public void eraseFlag(int id) {
+ private void eraseFlag(int id) {
eraseInternal(id);
removeFromCache(id);
- mFlagManager.dispatchListenersAndMaybeRestart(id);
+ dispatchListenersAndMaybeRestart(id, this::restartSystemUI);
}
+ private void dispatchListenersAndMaybeRestart(int id, Consumer<Boolean> restartAction) {
+ mFlagManager.dispatchListenersAndMaybeRestart(id, restartAction);
+ }
/** Works just like {@link #eraseFlag(int)} except that it doesn't restart SystemUI. */
private void eraseInternal(int id) {
// We can't actually "erase" things from sysprops, but we can set them to empty!
@@ -217,7 +244,11 @@
System.exit(0);
}
- private void restartAndroid() {
+ private void restartAndroid(boolean requestSuppress) {
+ if (requestSuppress) {
+ Log.i(TAG, "Android Restart Suppressed");
+ return;
+ }
Log.i(TAG, "Restarting Android");
try {
mBarService.restart();
@@ -273,7 +304,7 @@
Flag<?> flag = flagMap.get(id);
if (!extras.containsKey(EXTRA_VALUE)) {
- eraseFlag(id);
+ eraseFlag(flag);
return;
}
@@ -282,6 +313,12 @@
setFlagValue(id, (Boolean) value, BooleanFlagSerializer.INSTANCE);
} else if (flag instanceof ResourceBooleanFlag && value instanceof Boolean) {
setFlagValue(id, (Boolean) value, BooleanFlagSerializer.INSTANCE);
+ } else if (flag instanceof SysPropBooleanFlag && value instanceof Boolean) {
+ // Store SysProp flags in SystemProperties where they can read by outside parties.
+ mSystemProperties.setBoolean(
+ ((SysPropBooleanFlag) flag).getName(), (Boolean) value);
+ dispatchListenersAndMaybeRestart(flag.getId(),
+ FeatureFlagsDebug.this::restartAndroid);
} else if (flag instanceof StringFlag && value instanceof String) {
setFlagValue(id, (String) value, StringFlagSerializer.INSTANCE);
} else if (flag instanceof ResourceStringFlag && value instanceof String) {
@@ -306,6 +343,9 @@
if (f instanceof ResourceBooleanFlag) {
return new BooleanFlag(f.getId(), isEnabled((ResourceBooleanFlag) f));
}
+ if (f instanceof SysPropBooleanFlag) {
+ return new BooleanFlag(f.getId(), isEnabled((SysPropBooleanFlag) f));
+ }
// TODO: add support for other flag types.
Log.w(TAG, "Unsupported Flag Type. Please file a bug.");
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsRelease.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsRelease.java
index 348a8e2..1fb1acfa 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsRelease.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsRelease.java
@@ -43,11 +43,17 @@
@SysUISingleton
public class FeatureFlagsRelease implements FeatureFlags, Dumpable {
private final Resources mResources;
+ private final SystemPropertiesHelper mSystemProperties;
SparseBooleanArray mBooleanCache = new SparseBooleanArray();
SparseArray<String> mStringCache = new SparseArray<>();
+
@Inject
- public FeatureFlagsRelease(@Main Resources resources, DumpManager dumpManager) {
+ public FeatureFlagsRelease(
+ @Main Resources resources,
+ SystemPropertiesHelper systemProperties,
+ DumpManager dumpManager) {
mResources = resources;
+ mSystemProperties = systemProperties;
dumpManager.registerDumpable("SysUIFlags", this);
}
@@ -72,6 +78,17 @@
return mBooleanCache.valueAt(cacheIndex);
}
+ @Override
+ public boolean isEnabled(SysPropBooleanFlag flag) {
+ int cacheIndex = mBooleanCache.indexOfKey(flag.getId());
+ if (cacheIndex < 0) {
+ return isEnabled(
+ flag.getId(), mSystemProperties.getBoolean(flag.getName(), flag.getDefault()));
+ }
+
+ return mBooleanCache.valueAt(cacheIndex);
+ }
+
private boolean isEnabled(int key, boolean defaultValue) {
mBooleanCache.append(key, defaultValue);
return defaultValue;
diff --git a/packages/SystemUI/src/com/android/systemui/flags/SystemPropertiesHelper.kt b/packages/SystemUI/src/com/android/systemui/flags/SystemPropertiesHelper.kt
index 1dc5a9f..6c16097 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/SystemPropertiesHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/SystemPropertiesHelper.kt
@@ -34,6 +34,10 @@
return SystemProperties.getBoolean(name, default)
}
+ fun setBoolean(name: String, value: Boolean) {
+ SystemProperties.set(name, if (value) "1" else "0")
+ }
+
fun set(name: String, value: String) {
SystemProperties.set(name, value)
}
@@ -41,4 +45,8 @@
fun set(name: String, value: Int) {
set(name, value.toString())
}
+
+ fun erase(name: String) {
+ set(name, "")
+ }
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsComponent.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsComponent.java
index e746caf..74d5bd5 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.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 84fa6a6..7a278f7 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
@@ -27,7 +27,6 @@
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_GLOBAL_ACTIONS_SHOWING;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -117,15 +116,13 @@
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.model.SysUiState;
import com.android.systemui.plugins.GlobalActions.GlobalActionsManager;
import com.android.systemui.plugins.GlobalActionsPanelPlugin;
import com.android.systemui.scrim.ScrimDrawable;
import com.android.systemui.statusbar.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.phone.SystemUIDialogManager;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.telephony.TelephonyListenerManager;
@@ -200,7 +197,6 @@
private final TelecomManager mTelecomManager;
private final MetricsLogger mMetricsLogger;
private final UiEventLogger mUiEventLogger;
- private final SysUiState mSysUiState;
// Used for RingerModeTracker
private final LifecycleRegistry mLifecycle = new LifecycleRegistry(this);
@@ -240,8 +236,7 @@
private int mDialogPressDelay = DIALOG_PRESS_DELAY; // ms
protected Handler mMainHandler;
private int mSmallestScreenWidthDp;
- private final Optional<StatusBar> mStatusBarOptional;
- private final SystemUIDialogManager mDialogManager;
+ private final Optional<CentralSurfaces> mCentralSurfacesOptional;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final DialogLaunchAnimator mDialogLaunchAnimator;
@@ -347,13 +342,11 @@
@Background Executor backgroundExecutor,
UiEventLogger uiEventLogger,
RingerModeTracker ringerModeTracker,
- SysUiState sysUiState,
@Main Handler handler,
PackageManager packageManager,
- Optional<StatusBar> statusBarOptional,
+ Optional<CentralSurfaces> centralSurfacesOptional,
KeyguardUpdateMonitor keyguardUpdateMonitor,
- DialogLaunchAnimator dialogLaunchAnimator,
- SystemUIDialogManager dialogManager) {
+ DialogLaunchAnimator dialogLaunchAnimator) {
mContext = context;
mWindowManagerFuncs = windowManagerFuncs;
mAudioManager = audioManager;
@@ -379,13 +372,11 @@
mIWindowManager = iWindowManager;
mBackgroundExecutor = backgroundExecutor;
mRingerModeTracker = ringerModeTracker;
- mSysUiState = sysUiState;
mMainHandler = handler;
mSmallestScreenWidthDp = resources.getConfiguration().smallestScreenWidthDp;
- mStatusBarOptional = statusBarOptional;
+ mCentralSurfacesOptional = centralSurfacesOptional;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mDialogLaunchAnimator = dialogLaunchAnimator;
- mDialogManager = dialogManager;
// receive broadcasts
IntentFilter filter = new IntentFilter();
@@ -435,8 +426,8 @@
return mUiEventLogger;
}
- protected Optional<StatusBar> getStatusBar() {
- return mStatusBarOptional;
+ protected Optional<CentralSurfaces> getCentralSurfaces() {
+ return mCentralSurfacesOptional;
}
protected KeyguardUpdateMonitor getKeyguardUpdateMonitor() {
@@ -682,11 +673,10 @@
ActionsDialogLite dialog = new ActionsDialogLite(mContext,
com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActionsLite,
- mAdapter, mOverflowAdapter, mSysuiColorExtractor,
- mStatusBarService, mNotificationShadeWindowController,
- mSysUiState, this::onRefresh, mKeyguardShowing, mPowerAdapter, mUiEventLogger,
- mStatusBarOptional, mKeyguardUpdateMonitor, mLockPatternUtils,
- mDialogManager);
+ mAdapter, mOverflowAdapter, mSysuiColorExtractor, mStatusBarService,
+ mNotificationShadeWindowController, this::onRefresh, mKeyguardShowing,
+ mPowerAdapter, mUiEventLogger, mCentralSurfacesOptional, mKeyguardUpdateMonitor,
+ mLockPatternUtils);
dialog.setOnDismissListener(this);
dialog.setOnShowListener(this);
@@ -876,7 +866,7 @@
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
@@ -1008,7 +998,7 @@
mIActivityManager.requestInteractiveBugReport();
}
// Close shade so user sees the activity
- mStatusBarOptional.ifPresent(StatusBar::collapseShade);
+ mCentralSurfacesOptional.ifPresent(CentralSurfaces::collapseShade);
} catch (RemoteException e) {
}
}
@@ -1028,7 +1018,7 @@
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;
@@ -2165,13 +2155,12 @@
private boolean mKeyguardShowing;
protected float mScrimAlpha;
protected final NotificationShadeWindowController mNotificationShadeWindowController;
- protected final SysUiState mSysUiState;
private ListPopupWindow mOverflowPopup;
private Dialog mPowerOptionsDialog;
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;
@@ -2199,8 +2188,8 @@
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;
@@ -2212,8 +2201,8 @@
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;
@@ -2226,15 +2215,14 @@
MyOverflowAdapter overflowAdapter,
SysuiColorExtractor sysuiColorExtractor, IStatusBarService statusBarService,
NotificationShadeWindowController notificationShadeWindowController,
- SysUiState sysuiState, Runnable onRefreshCallback, boolean keyguardShowing,
+ Runnable onRefreshCallback, boolean keyguardShowing,
MyPowerOptionsAdapter powerAdapter, UiEventLogger uiEventLogger,
- Optional<StatusBar> statusBarOptional,
- KeyguardUpdateMonitor keyguardUpdateMonitor, LockPatternUtils lockPatternUtils,
- SystemUIDialogManager systemUiDialogManager) {
+ 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.
- super(context, themeRes, false /* dismissOnDeviceLock */,
- systemUiDialogManager);
+ super(context, themeRes, false /* dismissOnDeviceLock */);
mContext = context;
mAdapter = adapter;
mOverflowAdapter = overflowAdapter;
@@ -2242,11 +2230,10 @@
mColorExtractor = sysuiColorExtractor;
mStatusBarService = statusBarService;
mNotificationShadeWindowController = notificationShadeWindowController;
- mSysUiState = sysuiState;
mOnRefreshCallback = onRefreshCallback;
mKeyguardShowing = keyguardShowing;
mUiEventLogger = uiEventLogger;
- mStatusBarOptional = statusBarOptional;
+ mCentralSurfacesOptional = centralSurfacesOptional;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mLockPatternUtils = lockPatternUtils;
mGestureDetector = new GestureDetector(mContext, mGestureListener);
@@ -2276,14 +2263,14 @@
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();
}
@@ -2463,8 +2450,6 @@
public void show() {
super.show();
mNotificationShadeWindowController.setRequestTopUi(true, TAG);
- mSysUiState.setFlag(SYSUI_STATE_GLOBAL_ACTIONS_SHOWING, true)
- .commitUpdate(mContext.getDisplayId());
// By default this dialog windowAnimationStyle is null, and therefore windowAnimations
// should be equal to 0 which means we need to animate the dialog in-window. If it's not
@@ -2563,9 +2548,6 @@
dismissPowerOptions();
mNotificationShadeWindowController.setRequestTopUi(false, TAG);
- mSysUiState.setFlag(SYSUI_STATE_GLOBAL_ACTIONS_SHOWING, false)
- .commitUpdate(mContext.getDisplayId());
-
super.dismiss();
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardLifecyclesDispatcher.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardLifecyclesDispatcher.java
index 32b58c2..822b1cf 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardLifecyclesDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardLifecyclesDispatcher.java
@@ -18,8 +18,8 @@
import android.os.Handler;
import android.os.Message;
-import android.os.PowerManager;
import android.os.RemoteException;
+import android.os.Trace;
import android.util.Log;
import com.android.internal.policy.IKeyguardDrawnCallback;
@@ -83,6 +83,11 @@
final Object obj = msg.obj;
switch (msg.what) {
case SCREEN_TURNING_ON:
+ Trace.beginSection("KeyguardLifecyclesDispatcher#SCREEN_TURNING_ON");
+ final String onDrawWaitingTraceTag =
+ "Waiting for KeyguardDrawnCallback#onDrawn";
+ int traceCookie = System.identityHashCode(msg);
+ Trace.beginAsyncSection(onDrawWaitingTraceTag, traceCookie);
// Ensure the drawn callback is only ever called once
mScreenLifecycle.dispatchScreenTurningOn(new Runnable() {
boolean mInvoked;
@@ -92,6 +97,7 @@
if (!mInvoked) {
mInvoked = true;
try {
+ Trace.endAsyncSection(onDrawWaitingTraceTag, traceCookie);
((IKeyguardDrawnCallback) obj).onDrawn();
} catch (RemoteException e) {
Log.w(TAG, "Exception calling onDrawn():", e);
@@ -101,6 +107,7 @@
}
}
});
+ Trace.endSection();
break;
case SCREEN_TURNED_ON:
mScreenLifecycle.dispatchScreenTurnedOn();
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index ae7147e..07dfa33 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.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;
@@ -2717,22 +2717,22 @@
}
/**
- * 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 195ef1a..c69f947 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.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.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 7b85050..fab06c2 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -550,13 +550,13 @@
// 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_ART)
+ }
if (artworkBitmap == null) {
artworkBitmap = metadata?.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART)
}
- if (artworkBitmap == null && metadata != null) {
- artworkBitmap = loadBitmapFromUri(metadata)
- }
val artWorkIcon = if (artworkBitmap == null) {
notif.getLargeIcon()
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
index eee3955..c6f716c 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 @@
* @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 @@
@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 @@
(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 @@
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 @@
if (!isTransitioningToFullShade) {
return false
}
+ if (inSplitShade) {
+ // Split shade doesn't use QQS.
+ return false
+ }
return fullShadeTransitionProgress > 0.5f
}
@@ -1000,6 +1016,10 @@
* 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 e2716e9..77873e8 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.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 @@
private int mUid;
private IMediaProjectionManager mService;
- private AlertDialog mDialog;
+ private SystemUIDialog mDialog;
@Override
public void onCreate(Bundle icicle) {
@@ -143,25 +141,18 @@
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/dialog/MediaOutputBaseDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
index 7bb5454..04a324b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
@@ -56,7 +56,6 @@
import com.android.systemui.R;
import com.android.systemui.statusbar.phone.SystemUIDialog;
-import com.android.systemui.statusbar.phone.SystemUIDialogManager;
/**
* Base dialog for media output UI
@@ -99,9 +98,8 @@
}
};
- public MediaOutputBaseDialog(Context context, MediaOutputController mediaOutputController,
- SystemUIDialogManager dialogManager) {
- super(context, R.style.Theme_SystemUI_Dialog_Media, dialogManager);
+ public MediaOutputBaseDialog(Context context, MediaOutputController mediaOutputController) {
+ super(context, R.style.Theme_SystemUI_Dialog_Media);
// Save the context that is wrapped with our theme.
mContext = getContext();
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index 7bc0f52..e929b5e 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -66,7 +66,6 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
import com.android.systemui.statusbar.phone.ShadeController;
-import com.android.systemui.statusbar.phone.SystemUIDialogManager;
import java.util.ArrayList;
import java.util.Collection;
@@ -91,7 +90,6 @@
private final ShadeController mShadeController;
private final ActivityStarter mActivityStarter;
private final DialogLaunchAnimator mDialogLaunchAnimator;
- private final SystemUIDialogManager mDialogManager;
private final List<MediaDevice> mGroupMediaDevices = new CopyOnWriteArrayList<>();
private final boolean mAboveStatusbar;
private final boolean mVolumeAdjustmentForRemoteGroupSessions;
@@ -119,7 +117,7 @@
boolean aboveStatusbar, MediaSessionManager mediaSessionManager, LocalBluetoothManager
lbm, ShadeController shadeController, ActivityStarter starter,
CommonNotifCollection notifCollection, UiEventLogger uiEventLogger,
- DialogLaunchAnimator dialogLaunchAnimator, SystemUIDialogManager dialogManager) {
+ DialogLaunchAnimator dialogLaunchAnimator) {
mContext = context;
mPackageName = packageName;
mMediaSessionManager = mediaSessionManager;
@@ -135,7 +133,6 @@
mDialogLaunchAnimator = dialogLaunchAnimator;
mVolumeAdjustmentForRemoteGroupSessions = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_volumeAdjustmentForRemoteGroupSessions);
- mDialogManager = dialogManager;
mColorActiveItem = Utils.getColorStateListDefaultColor(mContext,
R.color.media_dialog_active_item_main_content);
mColorInactiveItem = Utils.getColorStateListDefaultColor(mContext,
@@ -610,10 +607,9 @@
// We show the output group dialog from the output dialog.
MediaOutputController controller = new MediaOutputController(mContext, mPackageName,
mAboveStatusbar, mMediaSessionManager, mLocalBluetoothManager, mShadeController,
- mActivityStarter, mNotifCollection, mUiEventLogger, mDialogLaunchAnimator,
- mDialogManager);
+ mActivityStarter, mNotifCollection, mUiEventLogger, mDialogLaunchAnimator);
MediaOutputGroupDialog dialog = new MediaOutputGroupDialog(mContext, mAboveStatusbar,
- controller, mDialogManager);
+ controller);
mDialogLaunchAnimator.showFromView(dialog, mediaOutputDialog);
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
index 4e9da55..7696a1f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
@@ -29,7 +29,6 @@
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.statusbar.phone.SystemUIDialogManager;
/**
* Dialog for media output transferring.
@@ -39,9 +38,8 @@
final UiEventLogger mUiEventLogger;
MediaOutputDialog(Context context, boolean aboveStatusbar, MediaOutputController
- mediaOutputController, UiEventLogger uiEventLogger,
- SystemUIDialogManager dialogManager) {
- super(context, mediaOutputController, dialogManager);
+ mediaOutputController, UiEventLogger uiEventLogger) {
+ super(context, mediaOutputController);
mUiEventLogger = uiEventLogger;
mAdapter = new MediaOutputAdapter(mMediaOutputController, this);
if (!aboveStatusbar) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
index e1e7fa3..9e252ea 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
@@ -25,7 +25,6 @@
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
import com.android.systemui.statusbar.phone.ShadeController
-import com.android.systemui.statusbar.phone.SystemUIDialogManager
import javax.inject.Inject
/**
@@ -39,8 +38,7 @@
private val starter: ActivityStarter,
private val notifCollection: CommonNotifCollection,
private val uiEventLogger: UiEventLogger,
- private val dialogLaunchAnimator: DialogLaunchAnimator,
- private val dialogManager: SystemUIDialogManager
+ private val dialogLaunchAnimator: DialogLaunchAnimator
) {
companion object {
var mediaOutputDialog: MediaOutputDialog? = null
@@ -53,9 +51,8 @@
val controller = MediaOutputController(context, packageName, aboveStatusBar,
mediaSessionManager, lbm, shadeController, starter, notifCollection,
- uiEventLogger, dialogLaunchAnimator, dialogManager)
- val dialog = MediaOutputDialog(context, aboveStatusBar, controller, uiEventLogger,
- dialogManager)
+ uiEventLogger, dialogLaunchAnimator)
+ val dialog = MediaOutputDialog(context, aboveStatusBar, controller, uiEventLogger)
mediaOutputDialog = dialog
// Show the dialog.
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupDialog.java
index 9f752b9..f1c6601 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupDialog.java
@@ -25,7 +25,6 @@
import androidx.core.graphics.drawable.IconCompat;
import com.android.systemui.R;
-import com.android.systemui.statusbar.phone.SystemUIDialogManager;
/**
* Dialog for media output group.
@@ -34,8 +33,8 @@
public class MediaOutputGroupDialog extends MediaOutputBaseDialog {
MediaOutputGroupDialog(Context context, boolean aboveStatusbar, MediaOutputController
- mediaOutputController, SystemUIDialogManager dialogManager) {
- super(context, mediaOutputController, dialogManager);
+ mediaOutputController) {
+ super(context, mediaOutputController);
mMediaOutputController.resetGroupMediaDevices();
mAdapter = new MediaOutputGroupAdapter(mMediaOutputController);
if (!aboveStatusbar) {
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 ee2fba0..15b8f13 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.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
@@ -29,7 +30,9 @@
import com.android.internal.widget.CachingIconView
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
@@ -41,7 +44,9 @@
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
) {
/** The window layout parameters we'll use when attaching the view to a window. */
@@ -82,6 +87,7 @@
// Add view if necessary
if (oldChipView == null) {
+ tapGestureDetector.addOnGestureDetectedCallback(TAG, this::onScreenTapped)
windowManager.addView(chipView, windowLayoutParams)
}
@@ -96,6 +102,7 @@
// TransferTriggered state: Once the user has initiated the transfer, they should be able
// to move away from the receiver device but still see the status of the transfer.
if (chipView == null) { return }
+ tapGestureDetector.removeOnGestureDetectedCallback(TAG)
windowManager.removeView(chipView)
chipView = null
}
@@ -123,10 +130,20 @@
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
// UpdateMediaTapToTransferReceiverDisplayTest
private const val WINDOW_TITLE = "Media Transfer Chip View"
+private val TAG = MediaTttChipControllerCommon::class.simpleName!!
@VisibleForTesting
const val TIMEOUT_MILLIS = 3000L
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 214a888..3d43ebe 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
@@ -29,7 +29,9 @@
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.media.taptotransfer.common.MediaTttChipControllerCommon
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
/**
@@ -42,10 +44,17 @@
commandQueue: CommandQueue,
context: Context,
windowManager: WindowManager,
+ viewUtil: ViewUtil,
mainExecutor: DelayableExecutor,
+ tapGestureDetector: TapGestureDetector,
@Main private val mainHandler: Handler,
) : MediaTttChipControllerCommon<ChipStateReceiver>(
- context, windowManager, mainExecutor, 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 482e604..180e4ee 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
@@ -30,7 +30,9 @@
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.media.taptotransfer.common.MediaTttChipControllerCommon
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
/**
@@ -42,9 +44,11 @@
commandQueue: CommandQueue,
context: Context,
windowManager: WindowManager,
- @Main private val mainExecutor: DelayableExecutor,
+ viewUtil: ViewUtil,
+ @Main mainExecutor: DelayableExecutor,
+ tapGestureDetector: TapGestureDetector,
) : MediaTttChipControllerCommon<ChipStateSender>(
- context, windowManager, mainExecutor, 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 5e9edb7..a1a3198 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.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 @@
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 @@
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 @@
mContentResolver = mContext.getContentResolver();
mAccessibilityManager = accessibilityManager;
mAssistManagerLazy = assistManagerLazy;
- mStatusBarOptionalLazy = statusBarOptionalLazy;
+ mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy;
mUserTracker = userTracker;
mSystemActions = systemActions;
accessibilityManager.addAccessibilityServicesStateChangeListener(
@@ -295,8 +294,8 @@
* {@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 8b39e5c..3ab1216 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -53,11 +53,10 @@
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.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.IActivityTaskManager;
import android.app.StatusBarManager;
@@ -135,12 +134,11 @@
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.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.pip.Pip;
import java.io.PrintWriter;
@@ -178,7 +176,7 @@
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;
@@ -187,7 +185,6 @@
private final BroadcastDispatcher mBroadcastDispatcher;
private final CommandQueue mCommandQueue;
private final Optional<Pip> mPipOptional;
- private final Optional<LegacySplitScreen> mSplitScreenOptional;
private final Optional<Recents> mRecentsOptional;
private final Optional<BackAnimation> mBackAnimation;
private final Handler mHandler;
@@ -440,7 +437,9 @@
mHomeButtonLongPressDurationMs = Optional.of(
properties.getLong(HOME_BUTTON_LONG_PRESS_DURATION_MS, 0)
).filter(duration -> duration != 0);
- reconfigureHomeLongClick();
+ if (mNavigationBarView != null) {
+ reconfigureHomeLongClick();
+ }
}
}
};
@@ -486,9 +485,8 @@
BroadcastDispatcher broadcastDispatcher,
CommandQueue commandQueue,
Optional<Pip> pipOptional,
- Optional<LegacySplitScreen> splitScreenOptional,
Optional<Recents> recentsOptional,
- Lazy<Optional<StatusBar>> statusBarOptionalLazy,
+ Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy,
ShadeController shadeController,
NotificationRemoteInputManager notificationRemoteInputManager,
NotificationShadeDepthController notificationShadeDepthController,
@@ -511,7 +509,7 @@
mMetricsLogger = metricsLogger;
mAssistManagerLazy = assistManagerLazy;
mSysUiFlagsContainer = sysUiFlagsContainer;
- mStatusBarOptionalLazy = statusBarOptionalLazy;
+ mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy;
mShadeController = shadeController;
mNotificationRemoteInputManager = notificationRemoteInputManager;
mOverviewProxyService = overviewProxyService;
@@ -520,7 +518,6 @@
mBroadcastDispatcher = broadcastDispatcher;
mCommandQueue = commandQueue;
mPipOptional = pipOptional;
- mSplitScreenOptional = splitScreenOptional;
mRecentsOptional = recentsOptional;
mBackAnimation = backAnimation;
mHandler = mainHandler;
@@ -614,7 +611,7 @@
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);
@@ -627,7 +624,6 @@
mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
- mSplitScreenOptional.ifPresent(mNavigationBarView::registerDockedListener);
mPipOptional.ifPresent(mNavigationBarView::addPipExclusionBoundsChangeListener);
mBackAnimation.ifPresent(mNavigationBarView::registerBackAnimation);
@@ -786,10 +782,7 @@
return;
}
- if (mStartingQuickSwitchRotation == -1 || mSplitScreenOptional
- .map(LegacySplitScreen::isDividerVisible).orElse(false)) {
- // Hide the secondary home handle if we are in multiwindow since apps in multiwindow
- // aren't allowed to set the display orientation
+ if (mStartingQuickSwitchRotation == -1) {
resetSecondaryHandle();
} else {
int deltaRotation = deltaRotation(mCurrentRotation, mStartingQuickSwitchRotation);
@@ -1172,13 +1165,14 @@
// 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;
@@ -1194,14 +1188,14 @@
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));
}
@@ -1228,7 +1222,7 @@
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;
}
@@ -1254,7 +1248,7 @@
LatencyTracker.getInstance(mContext).onActionStart(
LatencyTracker.ACTION_TOGGLE_RECENTS);
}
- mStatusBarOptionalLazy.get().ifPresent(StatusBar::awakenDreams);
+ mCentralSurfacesOptionalLazy.get().ifPresent(CentralSurfaces::awakenDreams);
mCommandQueue.toggleRecentApps();
}
@@ -1324,7 +1318,7 @@
return true;
} else if (v.getId() == btnId2) {
return btnId2 == R.id.recent_apps
- ? onLongPressRecents()
+ ? false
: onHomeLongClick(
mNavigationBarView.getHomeButton().getCurrentView());
}
@@ -1349,24 +1343,6 @@
return false;
}
- private boolean onLongPressRecents() {
- if (mRecentsOptional.isPresent() || !ActivityTaskManager.supportsMultiWindow(mContext)
- || ActivityManager.isLowRamDeviceStatic()
- // If we are connected to the overview service, then disable the recents button
- || mOverviewProxyService.getProxy() != null
- || !mSplitScreenOptional.map(splitScreen ->
- splitScreen.getDividerView().getSnapAlgorithm().isSplitScreenFeasible())
- .orElse(false)) {
- return false;
- }
-
- return mStatusBarOptionalLazy.get().map(
- statusBar -> statusBar.toggleSplitScreenMode(
- MetricsEvent.ACTION_WINDOW_DOCK_LONGPRESS,
- MetricsEvent.ACTION_WINDOW_UNDOCK_LONGPRESS))
- .orElse(false);
- }
-
private void onAccessibilityClick(View v) {
final Display display = v.getDisplay();
mAccessibilityManager.notifyAccessibilityButtonClicked(
@@ -1456,7 +1432,7 @@
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();
}
@@ -1475,7 +1451,8 @@
*/
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);
}
@@ -1650,9 +1627,8 @@
private final BroadcastDispatcher mBroadcastDispatcher;
private final CommandQueue mCommandQueue;
private final Optional<Pip> mPipOptional;
- private final Optional<LegacySplitScreen> mSplitScreenOptional;
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;
@@ -1682,9 +1658,8 @@
BroadcastDispatcher broadcastDispatcher,
CommandQueue commandQueue,
Optional<Pip> pipOptional,
- Optional<LegacySplitScreen> splitScreenOptional,
Optional<Recents> recentsOptional,
- Lazy<Optional<StatusBar>> statusBarOptionalLazy,
+ Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy,
ShadeController shadeController,
NotificationRemoteInputManager notificationRemoteInputManager,
NotificationShadeDepthController notificationShadeDepthController,
@@ -1711,9 +1686,8 @@
mBroadcastDispatcher = broadcastDispatcher;
mCommandQueue = commandQueue;
mPipOptional = pipOptional;
- mSplitScreenOptional = splitScreenOptional;
mRecentsOptional = recentsOptional;
- mStatusBarOptionalLazy = statusBarOptionalLazy;
+ mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy;
mShadeController = shadeController;
mNotificationRemoteInputManager = notificationRemoteInputManager;
mNotificationShadeDepthController = notificationShadeDepthController;
@@ -1738,7 +1712,7 @@
mOverviewProxyService, mNavigationModeController,
mAccessibilityButtonModeObserver, mStatusBarStateController,
mSysUiFlagsContainer, mBroadcastDispatcher, mCommandQueue, mPipOptional,
- mSplitScreenOptional, 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 80a7a4ae..017bbdf 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -90,9 +90,8 @@
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.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.pip.Pip;
import java.io.PrintWriter;
@@ -1363,7 +1362,7 @@
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);
@@ -1425,10 +1424,6 @@
return super.onApplyWindowInsets(insets);
}
- void registerDockedListener(LegacySplitScreen legacySplitScreen) {
- legacySplitScreen.registerInSplitScreenListener(mDockedListener);
- }
-
void addPipExclusionBoundsChangeListener(Pip pip) {
pip.addPipExclusionBoundsChangeListener(mPipListener);
}
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index 642af59..a7ed871 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.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;
@@ -108,17 +108,17 @@
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;
@@ -712,8 +712,10 @@
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 89735c3..5d9361d 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 @@
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/FooterActionsController.kt b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt
index a262b8a..27da6f3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt
@@ -50,6 +50,7 @@
import com.android.systemui.util.settings.GlobalSettings
import javax.inject.Inject
import javax.inject.Named
+import javax.inject.Provider
/**
* Manages [FooterActionsView] behaviour, both when it's placed in QS or QQS (split shade).
@@ -69,7 +70,7 @@
private val fgsManagerFooterController: QSFgsManagerFooter,
private val falsingManager: FalsingManager,
private val metricsLogger: MetricsLogger,
- private val globalActionsDialog: GlobalActionsDialogLite,
+ private val globalActionsDialogProvider: Provider<GlobalActionsDialogLite>,
private val uiEventLogger: UiEventLogger,
@Named(PM_LITE_ENABLED) private val showPMLiteButton: Boolean,
private val globalSetting: GlobalSettings,
@@ -77,6 +78,8 @@
private val featureFlags: FeatureFlags
) : ViewController<FooterActionsView>(view) {
+ private var globalActionsDialog: GlobalActionsDialogLite? = null
+
private var lastExpansion = -1f
private var listening: Boolean = false
@@ -131,7 +134,7 @@
startSettingsActivity()
} else if (v === powerMenuLite) {
uiEventLogger.log(GlobalActionsDialogLite.GlobalActionsEvent.GA_OPEN_QS)
- globalActionsDialog.showOrHideDialog(false, true, v)
+ globalActionsDialog?.showOrHideDialog(false, true, v)
}
}
@@ -158,6 +161,7 @@
@VisibleForTesting
public override fun onViewAttached() {
+ globalActionsDialog = globalActionsDialogProvider.get()
if (showPMLiteButton) {
powerMenuLite.visibility = View.VISIBLE
powerMenuLite.setOnClickListener(onClickListener)
@@ -165,6 +169,7 @@
powerMenuLite.visibility = View.GONE
}
settingsButton.setOnClickListener(onClickListener)
+ multiUserSetting.isListening = true
if (featureFlags.isEnabled(Flags.NEW_FOOTER)) {
val securityFooter = securityFooterController.view as DualHeightHorizontalLinearLayout
securityFootersContainer?.addView(securityFooter)
@@ -214,7 +219,10 @@
}
override fun onViewDetached() {
+ globalActionsDialog?.destroy()
+ globalActionsDialog = null
setListening(false)
+ multiUserSetting.isListening = false
}
fun setListening(listening: Boolean) {
@@ -222,7 +230,6 @@
return
}
this.listening = listening
- multiUserSetting.isListening = listening
if (this.listening) {
userInfoController.addCallback(onUserInfoChangedListener)
updateView()
diff --git a/packages/SystemUI/src/com/android/systemui/qs/HeaderPrivacyIconsController.kt b/packages/SystemUI/src/com/android/systemui/qs/HeaderPrivacyIconsController.kt
index 8afb793..95b4b72 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 @@
// 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 @@
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 3c7933f..3ef7220 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 @@
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 @@
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 5126fcb..b04d752 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 @@
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 @@
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 @@
if (!mUsingMediaPlayer) {
return;
}
+ mMediaHostView = hostView;
ViewGroup newParent = horizontal ? mHorizontalLinearLayout : this;
ViewGroup currentParent = (ViewGroup) hostView.getParent();
if (currentParent != newParent) {
@@ -656,6 +665,19 @@
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/QSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
index 9834129..0014279 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
@@ -33,8 +33,10 @@
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
+import com.android.systemui.media.MediaFlags;
import com.android.systemui.media.MediaHierarchyManager;
import com.android.systemui.media.MediaHost;
+import com.android.systemui.media.MediaHostState;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.qs.customize.QSCustomizerController;
import com.android.systemui.qs.dagger.QSScope;
@@ -63,6 +65,7 @@
private final FalsingManager mFalsingManager;
private final BrightnessController mBrightnessController;
private final BrightnessSliderController mBrightnessSliderController;
+ private final MediaFlags mMediaFlags;
private final BrightnessMirrorHandler mBrightnessMirrorHandler;
private final FeatureFlags mFeatureFlags;
@@ -102,7 +105,8 @@
DumpManager dumpManager, MetricsLogger metricsLogger, UiEventLogger uiEventLogger,
QSLogger qsLogger, BrightnessController.Factory brightnessControllerFactory,
BrightnessSliderController.Factory brightnessSliderFactory,
- FalsingManager falsingManager, FeatureFlags featureFlags) {
+ FalsingManager falsingManager, FeatureFlags featureFlags,
+ MediaFlags mediaFlags) {
super(view, qstileHost, qsCustomizerController, usingMediaPlayer, mediaHost,
metricsLogger, uiEventLogger, qsLogger, dumpManager);
mQSFgsManagerFooter = qsFgsManagerFooter;
@@ -113,6 +117,7 @@
mFalsingManager = falsingManager;
mBrightnessSliderController = brightnessSliderFactory.create(getContext(), mView);
+ mMediaFlags = mediaFlags;
mView.setBrightnessView(mBrightnessSliderController.getRootView());
mBrightnessController = brightnessControllerFactory.create(mBrightnessSliderController);
@@ -133,7 +138,14 @@
}
private void updateMediaExpansion() {
- mMediaHost.setExpansion(Utils.shouldUseSplitNotificationShade(getResources()) ? 0 : 1);
+ boolean inSplitShade = Utils.shouldUseSplitNotificationShade(getResources());
+ float expansion;
+ if (inSplitShade && !mMediaFlags.useMediaSessionLayout()) {
+ expansion = MediaHostState.COLLAPSED;
+ } else {
+ expansion = MediaHostState.EXPANDED;
+ }
+ mMediaHost.setExpansion(expansion);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
index 3172aa9..6572daa 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 @@
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 c693075..47af7de 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.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 @@
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 @@
Provider<AutoTileManager> autoTiles,
DumpManager dumpManager,
BroadcastDispatcher broadcastDispatcher,
- Optional<StatusBar> statusBarOptional,
+ Optional<CentralSurfaces> centralSurfacesOptional,
QSLogger qsLogger,
UiEventLogger uiEventLogger,
UserTracker userTracker,
@@ -143,7 +143,7 @@
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 @@
@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/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index 131589f..999818f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -116,7 +116,8 @@
private String mTileSpec;
@Nullable
- private EnforcedAdmin mEnforcedAdmin;
+ @VisibleForTesting
+ protected EnforcedAdmin mEnforcedAdmin;
private boolean mShowingDetail;
private int mIsFullQs;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index c61c18a..f736231 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -24,6 +24,7 @@
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Looper;
+import android.os.UserManager;
import android.provider.Settings;
import android.service.quicksettings.Tile;
import android.text.TextUtils;
@@ -114,6 +115,7 @@
@Override
protected void handleUpdateState(BooleanState state, Object arg) {
+ checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_BLUETOOTH);
final boolean transientEnabling = arg == ARG_SHOW_TRANSIENT_ENABLING;
final boolean enabled = transientEnabling || mController.isBluetoothEnabled();
final boolean connected = mController.isBluetoothConnected();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index e088f54..5d6bbae 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -202,11 +202,12 @@
mActivityStarter
.postStartActivityDismissingKeyguard(getLongClickIntent(), 0,
controller);
- });
+ }, R.style.Theme_SystemUI_Dialog, false /* showProgressBarWhenEmpty */);
holder.init(dialog);
SystemUIDialog.setShowForAllUsers(dialog, true);
SystemUIDialog.registerDismissListener(dialog);
SystemUIDialog.setWindowOnTop(dialog, mKeyguard.isShowing());
+ SystemUIDialog.setDialogSize(dialog);
mUiHandler.post(() -> {
if (view != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
index 597f7b7..f389df0 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 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 @@
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 @@
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
@Inject
- public OverviewProxyRecentsImpl(Lazy<Optional<StatusBar>> statusBarOptionalLazy) {
- mStatusBarOptionalLazy = statusBarOptionalLazy;
+ public OverviewProxyRecentsImpl(Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy) {
+ mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy;
}
@Override
@@ -109,9 +109,10 @@
}
};
// 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 6b251b0..a3dea1c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -102,11 +102,10 @@
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;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.pip.PipAnimationController;
@@ -147,8 +146,7 @@
private final Context mContext;
private final Optional<Pip> mPipOptional;
- private final Lazy<Optional<StatusBar>> mStatusBarOptionalLazy;
- private final Optional<LegacySplitScreen> mLegacySplitScreenOptional;
+ private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy;
private final Optional<SplitScreen> mSplitScreenOptional;
private SysUiState mSysUiState;
private final Handler mHandler;
@@ -188,7 +186,7 @@
@Override
public void startScreenPinning(int taskId) {
verifyCallerAndClearCallingIdentityPostMain("startScreenPinning", () ->
- mStatusBarOptionalLazy.get().ifPresent(
+ mCentralSurfacesOptionalLazy.get().ifPresent(
statusBar -> statusBar.showScreenPinningRequest(taskId,
false /* allowCancel */)));
}
@@ -209,9 +207,9 @@
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();
@@ -219,7 +217,7 @@
mInputFocusTransferStarted = true;
mInputFocusTransferStartY = event.getY();
mInputFocusTransferStartMillis = event.getEventTime();
- statusBar.onInputFocusTransfer(
+ centralSurfaces.onInputFocusTransfer(
mInputFocusTransferStarted, false /* cancel */,
0 /* velocity */);
}
@@ -227,7 +225,7 @@
mInputFocusTransferStarted = false;
float velocity = (event.getY() - mInputFocusTransferStartY)
/ (event.getEventTime() - mInputFocusTransferStartMillis);
- statusBar.onInputFocusTransfer(mInputFocusTransferStarted,
+ centralSurfaces.onInputFocusTransfer(mInputFocusTransferStarted,
action == ACTION_CANCEL,
velocity);
}
@@ -298,14 +296,8 @@
@Override
public Rect getNonMinimizedSplitScreenSecondaryBounds() {
- return verifyCallerAndClearCallingIdentity(
- "getNonMinimizedSplitScreenSecondaryBounds",
- () -> mLegacySplitScreenOptional.map(splitScreen ->
- splitScreen
- .getDividerView()
- .getNonMinimizedSplitScreenSecondaryBounds())
- .orElse(null)
- );
+ // Deprecated
+ return null;
}
@Override
@@ -362,8 +354,7 @@
@Override
public void setSplitScreenMinimized(boolean minimized) {
- mLegacySplitScreenOptional.ifPresent(
- splitScreen -> splitScreen.setMinimized(minimized));
+ // Deprecated
}
@Override
@@ -410,7 +401,7 @@
@Override
public void toggleNotificationPanel() {
verifyCallerAndClearCallingIdentityPostMain("toggleNotificationPanel", () ->
- mStatusBarOptionalLazy.get().ifPresent(StatusBar::togglePanel));
+ mCentralSurfacesOptionalLazy.get().ifPresent(CentralSurfaces::togglePanel));
}
@@ -564,11 +555,10 @@
@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,
- Optional<LegacySplitScreen> legacySplitScreenOptional,
Optional<SplitScreen> splitScreenOptional,
Optional<OneHanded> oneHandedOptional,
Optional<RecentTasks> recentTasks,
@@ -583,7 +573,7 @@
super(broadcastDispatcher);
mContext = context;
mPipOptional = pipOptional;
- mStatusBarOptionalLazy = statusBarOptionalLazy;
+ mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy;
mHandler = new Handler();
mNavBarControllerLazy = navBarControllerLazy;
mStatusBarWinController = statusBarWinController;
@@ -634,9 +624,6 @@
mCommandQueue = commandQueue;
mSplitScreenOptional = splitScreenOptional;
- legacySplitScreenOptional.ifPresent(splitScreen ->
- splitScreen.registerBoundsChangeListener(mSplitScreenBoundsChangeListener));
- mLegacySplitScreenOptional = legacySplitScreenOptional;
// Listen for user setup
startTracking();
@@ -678,7 +665,7 @@
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);
@@ -744,17 +731,13 @@
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 */);
});
});
}
startConnectionToCurrentUser();
-
- // Clean up the minimized state if launcher dies
- mLegacySplitScreenOptional.ifPresent(
- splitScreen -> splitScreen.setMinimized(false));
}
public void startConnectionToCurrentUser() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
index 7f130cb..15ad779 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.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 @@
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 @@
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 @@
.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 f140446..daaa897 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_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.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 @@
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 @@
};
- 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 991a68f..7801c68 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 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/shortcut/ShortcutKeyDispatcher.java b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
index 10aa12b..6abf339 100644
--- a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
@@ -23,13 +23,8 @@
import android.view.KeyEvent;
import android.view.WindowManagerGlobal;
-import com.android.internal.policy.DividerSnapAlgorithm;
import com.android.systemui.CoreStartable;
import com.android.systemui.dagger.SysUISingleton;
-import com.android.wm.shell.legacysplitscreen.DividerView;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
-
-import java.util.Optional;
import javax.inject.Inject;
@@ -41,7 +36,6 @@
implements ShortcutKeyServiceProxy.Callbacks {
private static final String TAG = "ShortcutKeyDispatcher";
- private final Optional<LegacySplitScreen> mSplitScreenOptional;
private ShortcutKeyServiceProxy mShortcutKeyServiceProxy = new ShortcutKeyServiceProxy(this);
private IWindowManager mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
@@ -55,9 +49,8 @@
protected final long SC_DOCK_RIGHT = META_MASK | KeyEvent.KEYCODE_RIGHT_BRACKET;
@Inject
- public ShortcutKeyDispatcher(Context context, Optional<LegacySplitScreen> splitScreenOptional) {
+ public ShortcutKeyDispatcher(Context context) {
super(context);
- mSplitScreenOptional = splitScreenOptional;
}
/**
@@ -89,24 +82,6 @@
}
private void handleDockKey(long shortcutCode) {
- mSplitScreenOptional.ifPresent(splitScreen -> {
- if (splitScreen.isDividerVisible()) {
- // If there is already a docked window, we respond by resizing the docking pane.
- DividerView dividerView = splitScreen.getDividerView();
- DividerSnapAlgorithm snapAlgorithm = dividerView.getSnapAlgorithm();
- int dividerPosition = dividerView.getCurrentPosition();
- DividerSnapAlgorithm.SnapTarget currentTarget =
- snapAlgorithm.calculateNonDismissingSnapTarget(dividerPosition);
- DividerSnapAlgorithm.SnapTarget target = (shortcutCode == SC_DOCK_LEFT)
- ? snapAlgorithm.getPreviousTarget(currentTarget)
- : snapAlgorithm.getNextTarget(currentTarget);
- dividerView.startDragging(true /* animate */, false /* touching */);
- dividerView.stopDragging(target.position, 0f, false /* avoidDismissStart */,
- true /* logMetrics */);
- return;
- } else {
- splitScreen.splitPrimaryTask();
- }
- });
+ // TODO(b/220262470) : implement it with new split screen.
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 645c5ac..8a02e59 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.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 8366bdd..17f42b1 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.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 @@
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 @@
// 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 @@
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 @@
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 @@
notificationPanelController.setKeyguardOnlyContentAlpha(1.0f - scrimProgress)
depthController.transitionToFullShadeProgress = scrimProgress
udfpsKeyguardViewController?.setTransitionToFullShadeProgress(scrimProgress)
- statusbar.setTransitionToFullShadeProgress(scrimProgress)
+ centralSurfaces.setTransitionToFullShadeProgress(scrimProgress)
}
private fun setDragDownAmountAnimated(
@@ -463,7 +461,7 @@
animationHandler: ((Long) -> Unit)? = null,
cancelAction: Runnable? = null
) {
- if (statusbar.isShadeDisabled) {
+ if (centralSurfaces.isShadeDisabled) {
cancelAction?.run()
logger.logShadeDisabledOnGoToLockedShade()
return
@@ -505,7 +503,7 @@
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 01bdb40..68d35f9 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 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 @@
@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 @@
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 3730d12..052c57e 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.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.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 @@
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 @@
};
/**
- * 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 @@
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 @@
* 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 @@
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 17bf346..3b3b5a2 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.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 2b5453a..94a6d3e 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.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.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 @@
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 @@
@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 @@
};
/**
- * Injected constructor. See {@link StatusBarDependenciesModule}.
+ * Injected constructor. See {@link CentralSurfacesDependenciesModule}.
*/
public NotificationRemoteInputManager(
Context context,
@@ -263,7 +263,7 @@
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 @@
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 4f70fdb..3b1fa17 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 @@
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.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 @@
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 092e86d..054543c 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.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.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 @@
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 @@
private boolean mIsHandleDynamicPrivacyChangeScheduled;
/**
- * Injected constructor. See {@link StatusBarModule}.
+ * Injected constructor. See {@link CentralSurfacesModule}.
*/
public NotificationViewHierarchyManager(
Context context,
@@ -129,7 +127,6 @@
KeyguardBypassController bypassController,
Optional<Bubbles> bubblesOptional,
DynamicPrivacyController privacyController,
- ForegroundServiceSectionController fgsSectionController,
DynamicChildBindController dynamicChildBindController,
LowPriorityInflationHelper lowPriorityInflationHelper,
AssistantFeedbackController assistantFeedbackController,
@@ -145,7 +142,6 @@
mVisualStabilityManager = visualStabilityManager;
mStatusBarStateController = (SysuiStatusBarStateController) statusBarStateController;
mEntryManager = notificationEntryManager;
- mFgsSectionController = fgsSectionController;
mNotifPipelineFlags = notifPipelineFlags;
Resources res = context.getResources();
mAlwaysExpandNonGroupedNotification =
@@ -417,8 +413,7 @@
&& 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 2e1762a..7807738 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 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 c156797..33e2245 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 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 @@
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 4ad01aa..058edda 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.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 @@
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 02870a3..2763bd7 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 @@
* 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 f0b2c2d..2b31901 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.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 @@
* 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 @@
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 @@
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/charging/WiredChargingRippleController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt
index 48717e2..5df593b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt
@@ -175,7 +175,7 @@
val width = displayMetrics.widthPixels
val height = displayMetrics.heightPixels
rippleView.radius = Integer.max(width, height).toFloat()
- rippleView.origin = when (RotationUtils.getRotation(context)) {
+ rippleView.origin = when (RotationUtils.getExactRotation(context)) {
RotationUtils.ROTATION_LANDSCAPE -> {
PointF(width * normalizedPortPosY, height * (1 - normalizedPortPosX))
}
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 fe5a699..41d2b65 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 @@
}
}
- /** 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 d65fa3a..a62a152 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.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 @@
* 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 @@
}).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
similarity index 94%
rename from packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
index c687e82..83290af 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.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.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 @@
NotificationVisibilityProvider visibilityProvider,
NotificationEntryManager notificationEntryManager,
RemoteInputNotificationRebuilder rebuilder,
- Lazy<Optional<StatusBar>> statusBarOptionalLazy,
+ Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy,
StatusBarStateController statusBarStateController,
Handler mainHandler,
RemoteInputUriController remoteInputUriController,
@@ -120,7 +120,7 @@
visibilityProvider,
notificationEntryManager,
rebuilder,
- statusBarOptionalLazy,
+ centralSurfacesOptionalLazy,
statusBarStateController,
mainHandler,
remoteInputUriController,
@@ -134,7 +134,7 @@
@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 @@
DumpManager dumpManager) {
return new NotificationMediaManager(
context,
- statusBarOptionalLazy,
+ centralSurfacesOptionalLazy,
notificationShadeWindowController,
visibilityProvider,
notificationEntryManager,
@@ -198,7 +198,6 @@
KeyguardBypassController bypassController,
Optional<Bubbles> bubblesOptional,
DynamicPrivacyController privacyController,
- ForegroundServiceSectionController fgsSectionController,
DynamicChildBindController dynamicChildBindController,
LowPriorityInflationHelper lowPriorityInflationHelper,
AssistantFeedbackController assistantFeedbackController,
@@ -217,7 +216,6 @@
bypassController,
bubblesOptional,
privacyController,
- fgsSectionController,
dynamicChildBindController,
lowPriorityInflationHelper,
assistantFeedbackController,
@@ -261,6 +259,7 @@
@Provides
@SysUISingleton
static OngoingCallController provideOngoingCallController(
+ Context context,
CommonNotifCollection notifCollection,
SystemClock systemClock,
ActivityStarter activityStarter,
@@ -284,6 +283,7 @@
: 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
similarity index 88%
rename from packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesModule.java
index ad5ef20..99d4b2e 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 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
similarity index 76%
rename from packages/SystemUI/src/com/android/systemui/statusbar/dagger/StartStatusBarModule.kt
rename to packages/SystemUI/src/com/android/systemui/statusbar/dagger/StartCentralSurfacesModule.kt
index 46c1abb..fe55dea7 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
new file mode 100644
index 0000000..3a4731a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/gesture/GenericGestureDetector.kt
@@ -0,0 +1,110 @@
+/*
+ * 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.gesture
+
+import android.annotation.CallSuper
+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
+
+/**
+ * An abstract class to help detect gestures that occur anywhere on the display (not specific to a
+ * certain view).
+ *
+ * This class handles starting/stopping the gesture detection system as well as
+ * registering/unregistering callbacks for when gestures occur. Note that the class will only listen
+ * for gestures when there's at least one callback registered.
+ *
+ * Subclasses should implement [onInputEvent] to detect their specific gesture. Once a specific
+ * gesture is detected, they should call [onGestureDetected] (which will notify the callbacks).
+ */
+abstract class GenericGestureDetector(
+ private val tag: String
+) {
+ /**
+ * Active callbacks, each associated with a tag. Gestures will only be monitored if
+ * [callbacks.size] > 0.
+ */
+ 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.
+ *
+ * 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) {
+ startGestureListening()
+ }
+ }
+
+ /** Removes the callback. */
+ fun removeOnGestureDetectedCallback(tag: String) {
+ callbacks.remove(tag)
+ if (callbacks.isEmpty()) {
+ stopGestureListening()
+ }
+ }
+
+ /** 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 with the last motion
+ * event in the gesture.
+ */
+ internal fun onGestureDetected(e: MotionEvent) {
+ callbacks.values.forEach { it.invoke(e) }
+ }
+
+ /** Start listening to touch events. */
+ @CallSuper
+ internal open fun startGestureListening() {
+ stopGestureListening()
+
+ inputMonitor = InputMonitorCompat(tag, Display.DEFAULT_DISPLAY).also {
+ inputReceiver = it.getInputReceiver(
+ Looper.getMainLooper(),
+ Choreographer.getInstance(),
+ this::onInputEvent
+ )
+ }
+ }
+
+ /** Stop listening to touch events. */
+ @CallSuper
+ internal open fun stopGestureListening() {
+ inputMonitor?.let {
+ inputMonitor = null
+ it.dispose()
+ }
+ inputReceiver?.let {
+ inputReceiver = null
+ it.dispose()
+ }
+ }
+}
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 7cdf69d..6115819 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureHandler.kt
@@ -17,15 +17,13 @@
package com.android.systemui.statusbar.gesture
import android.content.Context
-import android.os.Looper
-import android.view.Choreographer
-import android.view.Display
import android.view.InputEvent
import android.view.MotionEvent
-import android.view.MotionEvent.*
+import android.view.MotionEvent.ACTION_CANCEL
+import android.view.MotionEvent.ACTION_DOWN
+import android.view.MotionEvent.ACTION_MOVE
+import android.view.MotionEvent.ACTION_UP
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.shared.system.InputChannelCompat
-import com.android.systemui.shared.system.InputMonitorCompat
import com.android.systemui.statusbar.window.StatusBarWindowController
import javax.inject.Inject
@@ -38,43 +36,17 @@
context: Context,
private val statusBarWindowController: StatusBarWindowController,
private val logger: SwipeStatusBarAwayGestureLogger
-) {
-
- /**
- * Active callbacks, each associated with a tag. Gestures will only be monitored if
- * [callbacks.size] > 0.
- */
- private val callbacks: MutableMap<String, () -> Unit> = mutableMapOf()
+) : GenericGestureDetector(SwipeStatusBarAwayGestureHandler::class.simpleName!!) {
private var startY: Float = 0f
private var startTime: Long = 0L
private var monitoringCurrentTouch: Boolean = false
- private var inputMonitor: InputMonitorCompat? = null
- private var inputReceiver: InputChannelCompat.InputEventReceiver? = null
-
private var swipeDistanceThreshold: Int = context.resources.getDimensionPixelSize(
com.android.internal.R.dimen.system_gestures_start_threshold
)
- /** Adds a callback that will be triggered when the swipe away gesture is detected. */
- fun addOnGestureDetectedCallback(tag: String, callback: () -> Unit) {
- val callbacksWasEmpty = callbacks.isEmpty()
- callbacks[tag] = callback
- if (callbacksWasEmpty) {
- startGestureListening()
- }
- }
-
- /** Removes the callback. */
- fun removeOnGestureDetectedCallback(tag: String) {
- callbacks.remove(tag)
- if (callbacks.isEmpty()) {
- stopGestureListening()
- }
- }
-
- private fun onInputEvent(ev: InputEvent) {
+ override fun onInputEvent(ev: InputEvent) {
if (ev !is MotionEvent) {
return
}
@@ -108,7 +80,7 @@
) {
monitoringCurrentTouch = false
logger.logGestureDetected(ev.y.toInt())
- callbacks.values.forEach { it.invoke() }
+ onGestureDetected(ev)
}
}
ACTION_CANCEL, ACTION_UP -> {
@@ -120,33 +92,15 @@
}
}
- /** Start listening for the swipe gesture. */
- private fun startGestureListening() {
- stopGestureListening()
-
+ override fun startGestureListening() {
+ super.startGestureListening()
logger.logInputListeningStarted()
- inputMonitor = InputMonitorCompat(TAG, Display.DEFAULT_DISPLAY).also {
- inputReceiver = it.getInputReceiver(
- Looper.getMainLooper(),
- Choreographer.getInstance(),
- this::onInputEvent
- )
- }
}
- /** Stop listening for the swipe gesture. */
- private fun stopGestureListening() {
- inputMonitor?.let {
- logger.logInputListeningStopped()
- inputMonitor = null
- it.dispose()
- }
- inputReceiver?.let {
- inputReceiver = null
- it.dispose()
- }
+ override fun stopGestureListening() {
+ super.stopGestureListening()
+ logger.logInputListeningStopped()
}
}
private const val SWIPE_TIMEOUT_MS: Long = 500
-private val TAG = SwipeStatusBarAwayGestureHandler::class.simpleName
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/gesture/TapGestureDetector.kt b/packages/SystemUI/src/com/android/systemui/statusbar/gesture/TapGestureDetector.kt
new file mode 100644
index 0000000..7ffb07a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/gesture/TapGestureDetector.kt
@@ -0,0 +1,64 @@
+/*
+ * 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.gesture
+
+import android.content.Context
+import android.view.GestureDetector
+import android.view.InputEvent
+import android.view.MotionEvent
+import com.android.systemui.dagger.SysUISingleton
+import javax.inject.Inject
+
+/**
+ * A class to detect when a user taps the screen. To be notified when the tap is detected, add a
+ * callback via [addOnGestureDetectedCallback].
+ */
+@SysUISingleton
+class TapGestureDetector @Inject constructor(
+ private val context: Context
+) : GenericGestureDetector(TapGestureDetector::class.simpleName!!) {
+
+ private val gestureListener = object : GestureDetector.SimpleOnGestureListener() {
+ override fun onSingleTapUp(e: MotionEvent): Boolean {
+ onGestureDetected(e)
+ return true
+ }
+ }
+
+ private var gestureDetector: GestureDetector? = null
+
+ override fun onInputEvent(ev: InputEvent) {
+ if (ev !is MotionEvent) {
+ return
+ }
+ // Pass all events to [gestureDetector], which will then notify [gestureListener] when a tap
+ // is detected.
+ gestureDetector!!.onTouchEvent(ev)
+ }
+
+ /** Start listening for the tap gesture. */
+ override fun startGestureListening() {
+ super.startGestureListening()
+ gestureDetector = GestureDetector(context, gestureListener)
+ }
+
+ /** Stop listening for the swipe gesture. */
+ override fun stopGestureListening() {
+ super.stopGestureListening()
+ gestureDetector = null
+ }
+}
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 314051c..0000000
--- 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/InstantAppNotifier.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
index 82b56cd..5b7d90b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
@@ -19,8 +19,8 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -59,10 +59,8 @@
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.NotificationChannels;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import java.util.List;
-import java.util.Optional;
import java.util.concurrent.Executor;
import javax.inject.Inject;
@@ -80,15 +78,12 @@
private final Executor mUiBgExecutor;
private final ArraySet<Pair<String, Integer>> mCurrentNotifs = new ArraySet<>();
private final CommandQueue mCommandQueue;
- private boolean mDockedStackExists;
private KeyguardStateController mKeyguardStateController;
- private final Optional<LegacySplitScreen> mSplitScreenOptional;
@Inject
public InstantAppNotifier(Context context, CommandQueue commandQueue,
- @UiBackground Executor uiBgExecutor, Optional<LegacySplitScreen> splitScreenOptional) {
+ @UiBackground Executor uiBgExecutor) {
super(context);
- mSplitScreenOptional = splitScreenOptional;
mCommandQueue = commandQueue;
mUiBgExecutor = uiBgExecutor;
}
@@ -107,12 +102,6 @@
mCommandQueue.addCallback(this);
mKeyguardStateController.addCallback(this);
- mSplitScreenOptional.ifPresent(splitScreen ->
- splitScreen.registerInSplitScreenListener(exists -> {
- mDockedStackExists = exists;
- updateForegroundInstantApps();
- }));
-
// Clear out all old notifications on startup (only present in the case where sysui dies)
NotificationManager noMan = mContext.getSystemService(NotificationManager.class);
for (StatusBarNotification notification : noMan.getActiveNotifications()) {
@@ -169,14 +158,11 @@
focusedTask.configuration.windowConfiguration
.getWindowingMode();
if (windowingMode == WINDOWING_MODE_FULLSCREEN
- || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
+ || windowingMode == WINDOWING_MODE_MULTI_WINDOW
|| windowingMode == WINDOWING_MODE_FREEFORM) {
checkAndPostForStack(focusedTask, notifs, noMan, pm);
}
}
- if (mDockedStackExists) {
- checkAndPostForPrimaryScreen(notifs, noMan, pm);
- }
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
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 da70621..392145a 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 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 @@
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 @@
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 @@
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 @@
/** 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 f97b936..ac5beec 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 @@
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 @@
Lazy<NotificationRowBinder> notificationRowBinderLazy,
Lazy<NotificationRemoteInputManager> notificationRemoteInputManagerLazy,
LeakDetector leakDetector,
- ForegroundServiceDismissalFeatureController fgsFeatureController,
IStatusBarService statusBarService,
NotifLiveDataStoreImpl notifLiveDataStore,
DumpManager dumpManager
@@ -170,7 +168,6 @@
mNotificationRowBinderLazy = notificationRowBinderLazy;
mRemoteInputManagerLazy = notificationRemoteInputManagerLazy;
mLeakDetector = leakDetector;
- mFgsFeatureController = fgsFeatureController;
mStatusBarService = statusBarService;
mNotifLiveDataStore = notifLiveDataStore;
mDumpManager = dumpManager;
@@ -958,7 +955,7 @@
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 9da7d21..2c1296f 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.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 5dc0dcc..c71eade 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 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 @@
}
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 4ee08ed..bdbb0eb 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 920d3c4..470737e 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 @@
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 @@
@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 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 e3ebef9..51bbf1c 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.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.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 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 @@
Lazy<NotificationRowBinder> notificationRowBinderLazy,
Lazy<NotificationRemoteInputManager> notificationRemoteInputManagerLazy,
LeakDetector leakDetector,
- ForegroundServiceDismissalFeatureController fgsFeatureController,
IStatusBarService statusBarService,
NotifLiveDataStoreImpl notifLiveDataStore,
DumpManager dumpManager) {
@@ -139,7 +139,6 @@
notificationRowBinderLazy,
notificationRemoteInputManagerLazy,
leakDetector,
- fgsFeatureController,
statusBarService,
notifLiveDataStore,
dumpManager);
@@ -150,7 +149,7 @@
@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 @@
DumpManager dumpManager) {
return new NotificationGutsManager(
context,
- statusBarOptionalLazy,
+ centralSurfacesOptionalLazy,
mainHandler,
bgHandler,
accessibilityManager,
@@ -279,8 +278,8 @@
@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 a59d421..18abfca 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.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 @@
*/
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 48f2daf..98f45fa 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.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 @@
*/
@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 @@
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 @@
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 1c9af11..66701d1 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.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 @@
) : NotificationsController {
override fun initialize(
- statusBar: StatusBar,
- bubblesOptional: Optional<Bubbles>,
presenter: NotificationPresenter,
listContainer: NotificationListContainer,
stackController: NotifStackController,
@@ -75,4 +70,4 @@
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 dc39413..9fbd5c3 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 @@
}
/**
- * 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 dbfa27f..0000000
--- 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 1f7d930..c237e1d 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.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 @@
}
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 17396ad..0000000
--- 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 1530e523..4c69304 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.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 @@
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 6d13024..ebe6f03 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.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 @@
@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 @@
* 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 @@
ShadeController shadeController,
DumpManager dumpManager) {
mContext = context;
- mStatusBarOptionalLazy = statusBarOptionalLazy;
+ mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy;
mMainHandler = mainHandler;
mBgHandler = bgHandler;
mAccessibilityManager = accessibilityManager;
@@ -342,7 +342,7 @@
}
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 @@
// 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 @@
// 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 @@
// 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 @@
.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 @@
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 a12d0073..1a7417a 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.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 @@
// 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 4555b83..fa14123 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 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 75ca337..0000000
--- 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 2c4db77..efe559a 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.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 @@
}
};
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 @@
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 @@
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 @@
mAmbientState.setExpansionChanging(false);
if (!mIsExpanded) {
resetScrollPosition();
- mStatusBar.resetUserExpandedStates();
+ mCentralSurfaces.resetUserExpandedStates();
clearTemporaryViews();
clearUserLockedViews();
if (mSwipeHelper.isSwiping()) {
@@ -4601,8 +4591,8 @@
}
@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 @@
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 @@
// 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 d1c63e3..df6b8f5 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.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.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.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 @@
/**
* 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 @@
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 @@
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 @@
mView.updateSensitiveness(mStatusBarStateController.goingToFullShade(),
mLockscreenUserManager.isAnyProfilePublicMode());
mView.onStatePostChange(mStatusBarStateController.fromShadeLocked());
- mNotificationEntryManager.updateNotifications("StatusBar state changed");
+ mNotificationEntryManager.updateNotifications("CentralSurfaces state changed");
}
};
@@ -435,7 +431,7 @@
@Override
public void onSnooze(StatusBarNotification sbn,
NotificationSwipeActionHelper.SnoozeOption snoozeOption) {
- mStatusBar.setNotificationSnoozed(sbn, snoozeOption);
+ mCentralSurfaces.setNotificationSnoozed(sbn, snoozeOption);
}
@Override
@@ -488,7 +484,7 @@
mView.addSwipedOutView(view);
mFalsingCollector.onNotificationDismissed();
if (mFalsingCollector.shouldEnforceBouncer()) {
- mStatusBar.executeRunnableDismissingKeyguard(
+ mCentralSurfaces.executeRunnableDismissingKeyguard(
null,
null /* cancelAction */,
false /* dismissShade */,
@@ -561,7 +557,7 @@
@Override
public float getFalsingThresholdFactor() {
- return mStatusBar.isWakeUpComingFromTouch() ? 1.5f : 1.0f;
+ return mCentralSurfaces.isWakeUpComingFromTouch() ? 1.5f : 1.0f;
}
@Override
@@ -648,7 +644,7 @@
FalsingManager falsingManager,
@Main Resources resources,
NotificationSwipeHelper.Builder notificationSwipeHelperBuilder,
- StatusBar statusBar,
+ CentralSurfaces centralSurfaces,
ScrimController scrimController,
NotificationGroupManagerLegacy legacyGroupManager,
GroupExpansionManager groupManager,
@@ -660,8 +656,6 @@
LockscreenShadeTransitionController lockscreenShadeTransitionController,
IStatusBarService iStatusBarService,
UiEventLogger uiEventLogger,
- ForegroundServiceDismissalFeatureController fgFeatureController,
- ForegroundServiceSectionController fgServicesSectionController,
LayoutInflater layoutInflater,
NotificationRemoteInputManager remoteInputManager,
VisualStabilityManager visualStabilityManager,
@@ -691,7 +685,7 @@
mFalsingManager = falsingManager;
mResources = resources;
mNotificationSwipeHelperBuilder = notificationSwipeHelperBuilder;
- mStatusBar = statusBar;
+ mCentralSurfaces = centralSurfaces;
mScrimController = scrimController;
mJankMonitor = jankMonitor;
groupManager.registerGroupExpansionChangeListener(
@@ -699,7 +693,7 @@
legacyGroupManager.registerGroupChangeListener(new OnGroupChangeListener() {
@Override
public void onGroupsChanged() {
- mStatusBar.requestNotificationUpdate("onGroupsChanged");
+ mCentralSurfaces.requestNotificationUpdate("onGroupsChanged");
}
});
mNotifPipelineFlags = notifPipelineFlags;
@@ -709,8 +703,6 @@
mNotificationEntryManager = notificationEntryManager;
mIStatusBarService = iStatusBarService;
mUiEventLogger = uiEventLogger;
- mFgFeatureController = fgFeatureController;
- mFgServicesSectionController = fgServicesSectionController;
mLayoutInflater = layoutInflater;
mRemoteInputManager = remoteInputManager;
mVisualStabilityManager = visualStabilityManager;
@@ -724,7 +716,7 @@
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 @@
mNotificationRoundnessManager.setShouldRoundPulsingViews(
!mKeyguardBypassController.getBypassEnabled());
- if (mFgFeatureController.isForegroundServiceDismissalEnabled()) {
- mView.initializeForegroundServiceSection(
- (ForegroundServiceDungeonView) mFgServicesSectionController.createView(
- mLayoutInflater));
- }
-
mSwipeHelper = mNotificationSwipeHelperBuilder
.setSwipeDirection(SwipeHelper.X)
.setNotificationCallback(mNotificationCallback)
@@ -1420,7 +1406,7 @@
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 0000000..3dcaae2
--- /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/AutoTileManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
index 244103c..ccb37ae 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
@@ -68,6 +68,7 @@
private UserHandle mCurrentUser;
private boolean mInitialized;
+ private final String mSafetySpec;
protected final Context mContext;
protected final QSTileHost mHost;
@@ -113,6 +114,13 @@
mIsReduceBrightColorsAvailable = isReduceBrightColorsAvailable;
mDeviceControlsController = deviceControlsController;
mWalletController = walletController;
+ String safetySpecRes;
+ try {
+ safetySpecRes = context.getResources().getString(R.string.safety_quick_settings_tile);
+ } catch (Resources.NotFoundException | NullPointerException e) {
+ safetySpecRes = null;
+ }
+ mSafetySpec = safetySpecRes;
}
/**
@@ -155,6 +163,9 @@
if (!mAutoTracker.isAdded(WALLET)) {
initWalletController();
}
+ if (mSafetySpec != null && !mAutoTracker.isAdded(mSafetySpec)) {
+ initSafetyTile();
+ }
int settingsN = mAutoAddSettingList.size();
for (int i = 0; i < settingsN; i++) {
@@ -315,6 +326,15 @@
}
}
+ private void initSafetyTile() {
+ if (mSafetySpec == null) {
+ return;
+ }
+ if (mAutoTracker.isAdded(mSafetySpec)) return;
+ mHost.addTile(CustomTile.getComponentFromSpec(mSafetySpec), true);
+ mAutoTracker.setTileAdded(mSafetySpec);
+ }
+
@VisibleForTesting
final NightDisplayListener.Callback mNightDisplayCallback =
new NightDisplayListener.Callback() {
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 d5d1cea..fe637c1 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 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
similarity index 95%
rename from packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
index 82e0e67..5642744 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.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;
@@ -245,7 +245,6 @@
import com.android.systemui.volume.VolumeComponent;
import com.android.systemui.wmshell.BubblesManager;
import com.android.wm.shell.bubbles.Bubbles;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.startingsurface.SplashscreenContentDrawer;
import com.android.wm.shell.startingsurface.StartingSurface;
@@ -261,8 +260,20 @@
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;
@@ -270,6 +281,7 @@
protected static final int MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU = 1027;
// Should match the values in PhoneWindowManager
+ public static final String SYSTEM_DIALOG_REASON_KEY = "reason";
public static final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
public static final String SYSTEM_DIALOG_REASON_DREAM = "dream";
static public final String SYSTEM_DIALOG_REASON_SCREENSHOT = "screenshot";
@@ -278,7 +290,7 @@
"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 @@
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 @@
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,11 +507,8 @@
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 Optional<LegacySplitScreen> mSplitScreenOptional;
- private final StatusBarNotificationActivityStarter.Builder
- mStatusBarNotificationActivityStarterBuilder;
private final ShadeController mShadeController;
private final InitController mInitController;
@@ -544,7 +554,7 @@
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.
@@ -666,7 +676,7 @@
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;
@@ -685,13 +695,13 @@
/**
- * 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,
@@ -751,11 +761,8 @@
DozeScrimController dozeScrimController,
VolumeComponent volumeComponent,
CommandQueue commandQueue,
- StatusBarComponent.Factory statusBarComponentFactory,
+ CentralSurfacesComponent.Factory centralSurfacesComponentFactory,
PluginManager pluginManager,
- Optional<LegacySplitScreen> splitScreenOptional,
- StatusBarNotificationActivityStarter.Builder
- statusBarNotificationActivityStarterBuilder,
ShadeController shadeController,
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
ViewMediatorCallback viewMediatorCallback,
@@ -850,10 +857,8 @@
mNotificationShadeDepthControllerLazy = notificationShadeDepthControllerLazy;
mVolumeComponent = volumeComponent;
mCommandQueue = commandQueue;
- mStatusBarComponentFactory = statusBarComponentFactory;
+ mCentralSurfacesComponentFactory = centralSurfacesComponentFactory;
mPluginManager = pluginManager;
- mSplitScreenOptional = splitScreenOptional;
- mStatusBarNotificationActivityStarterBuilder = statusBarNotificationActivityStarterBuilder;
mShadeController = shadeController;
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
mKeyguardViewMediatorCallback = viewMediatorCallback;
@@ -882,7 +887,7 @@
mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
mStartingSurfaceOptional = startingSurfaceOptional;
mNotifPipelineFlags = notifPipelineFlags;
- lockscreenShadeTransitionController.setStatusbar(this);
+ lockscreenShadeTransitionController.setCentralSurfaces(this);
statusBarWindowStateController.addListener(this::onStatusBarWindowStateChanged);
mScreenOffAnimationController = screenOffAnimationController;
@@ -1114,7 +1119,7 @@
}
private void onFoldedStateChanged(boolean isFolded, boolean willGoToSleep) {
- Trace.beginSection("StatusBar#onFoldedStateChanged");
+ Trace.beginSection("CentralSurfaces#onFoldedStateChanged");
onFoldedStateChangedInternal(isFolded, willGoToSleep);
Trace.endSection();
}
@@ -1158,19 +1163,14 @@
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
@@ -1178,7 +1178,7 @@
mPluginDependencyProvider.allowPluginDependency(StatusBarStateController.class);
// Set up CollapsedStatusBarFragment and PhoneStatusBarView
- StatusBarInitializer initializer = mStatusBarComponent.getStatusBarInitializer();
+ StatusBarInitializer initializer = mCentralSurfacesComponent.getStatusBarInitializer();
initializer.setStatusBarViewUpdatedListener(
(statusBarView, statusBarViewController, statusBarTransitions) -> {
mStatusBarView = statusBarView;
@@ -1195,7 +1195,7 @@
setBouncerShowingForStatusBarComponents(mBouncerShowing);
checkBarModes();
});
- initializer.initializeStatusBar(mStatusBarComponent);
+ initializer.initializeStatusBar(mCentralSurfacesComponent);
mStatusBarTouchableRegionManager.setup(this, mNotificationShadeWindowView);
mHeadsUpManager.addListener(mNotificationPanelViewController.getOnHeadsUpChangedListener());
@@ -1445,65 +1445,19 @@
mActivityLaunchAnimator.addListener(mActivityLaunchAnimatorListener);
mNotificationAnimationProvider = new NotificationLaunchAnimatorControllerProvider(
mNotificationShadeWindowViewController,
- mStackScrollerController.getNotificationListContainer(),
+ mNotifListContainer,
mHeadsUpManager,
- mJankMonitor
- );
-
- // TODO: inject this.
- mPresenter = new StatusBarNotificationPresenter(
- mContext,
- mNotificationPanelViewController,
- 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());
}
/**
@@ -1561,30 +1515,34 @@
}
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);
@@ -1592,18 +1550,19 @@
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() {
@@ -1624,7 +1583,7 @@
@Override
public void notifyBiometricAuthModeChanged() {
- StatusBar.this.notifyBiometricAuthModeChanged();
+ CentralSurfaces.this.notifyBiometricAuthModeChanged();
}
private void setWakeAndUnlocking(boolean wakeAndUnlocking) {
@@ -1633,7 +1592,7 @@
}
}
});
- mStatusBarKeyguardViewManager.registerStatusBar(
+ mStatusBarKeyguardViewManager.registerCentralSurfaces(
/* statusBar= */ this,
mNotificationPanelViewController,
mPanelExpansionStateManager,
@@ -1672,35 +1631,6 @@
return mStatusBarWindowController.getStatusBarHeight();
}
- public boolean toggleSplitScreenMode(int metricsDockAction, int metricsUndockAction) {
- if (!mSplitScreenOptional.isPresent()) {
- return false;
- }
-
- final LegacySplitScreen legacySplitScreen = mSplitScreenOptional.get();
- if (legacySplitScreen.isDividerVisible()) {
- if (legacySplitScreen.isMinimized() && !legacySplitScreen.isHomeStackResizable()) {
- // Undocking from the minimized state is not supported
- return false;
- }
-
- legacySplitScreen.onUndockingTask();
- if (metricsUndockAction != -1) {
- mMetricsLogger.action(metricsUndockAction);
- }
- return true;
- }
-
- if (legacySplitScreen.splitPrimaryTask()) {
- if (metricsDockAction != -1) {
- mMetricsLogger.action(metricsDockAction);
- }
- return true;
- }
-
- return false;
- }
-
/**
* Disable QS if device not provisioned.
* If the user switcher is simple then disable QS during setup because
@@ -1791,7 +1721,7 @@
getDelegate().onIntentStarted(willAnimate);
if (willAnimate) {
- StatusBar.this.mIsLaunchingActivityOverLockscreen = true;
+ CentralSurfaces.this.mIsLaunchingActivityOverLockscreen = true;
}
}
@@ -1801,7 +1731,7 @@
// 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);
}
@@ -1811,7 +1741,7 @@
// 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();
}
};
@@ -2635,7 +2565,7 @@
// 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
@@ -2658,18 +2588,15 @@
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);
if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
KeyboardShortcuts.dismiss();
mRemoteInputManager.closeRemoteInputs();
- if (mBubblesOptional.isPresent() && mBubblesOptional.get().isStackExpanded()) {
- mBubblesOptional.get().collapseStack();
- }
if (mLockscreenUserManager.isCurrentProfile(getSendingUserId())) {
int flags = CommandQueue.FLAG_EXCLUDE_NONE;
- String reason = intent.getStringExtra("reason");
if (reason != null) {
if (reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) {
flags |= CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL;
@@ -2684,19 +2611,13 @@
}
mShadeController.animateCollapsePanels(flags);
}
- }
- else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
+ } else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
if (mNotificationShadeWindowController != null) {
mNotificationShadeWindowController.setNotTouchable(false);
}
- if (mBubblesOptional.isPresent() && mBubblesOptional.get().isStackExpanded()) {
- // Post to main thread, since updating the UI.
- mMainExecutor.execute(() -> mBubblesOptional.get().collapseStack());
- }
finishBarAnimations();
resetUserExpandedStates();
- }
- else if (DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG.equals(action)) {
+ } else if (DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG.equals(action)) {
mQSPanelController.showDeviceMonitoringDialog();
}
Trace.endSection();
@@ -2813,7 +2734,9 @@
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() &&
@@ -2962,8 +2885,9 @@
// 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();
}
@@ -2992,7 +2916,7 @@
}
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();
@@ -3115,7 +3039,7 @@
*/
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))) {
@@ -3232,7 +3156,7 @@
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();
@@ -3587,7 +3511,7 @@
@Override
public void onStartedGoingToSleep() {
- String tag = "StatusBar#onStartedGoingToSleep";
+ String tag = "CentralSurfaces#onStartedGoingToSleep";
DejankUtils.startDetectingBlockingIpcs(tag);
updateRevealEffect(false /* wakingUp */);
updateNotificationPanelTouchState();
@@ -3607,7 +3531,7 @@
@Override
public void onStartedWakingUp() {
- String tag = "StatusBar#onStartedWakingUp";
+ String tag = "CentralSurfaces#onStartedWakingUp";
DejankUtils.startDetectingBlockingIpcs(tag);
mNotificationShadeWindowController.batchApplyWindowLayoutParams(()-> {
mDeviceInteractive = true;
@@ -3682,7 +3606,7 @@
@Override
public void onScreenTurnedOff() {
- Trace.beginSection("StatusBar#onScreenTurnedOff");
+ Trace.beginSection("CentralSurfaces#onScreenTurnedOff");
mFalsingCollector.onScreenOff();
mScrimController.onScreenTurnedOff();
if (mCloseQsBeforeScreenOff) {
@@ -3773,6 +3697,10 @@
== WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP;
}
+ boolean isWaking() {
+ return mWakefulnessLifecycle.getWakefulness() == WakefulnessLifecycle.WAKEFULNESS_WAKING;
+ }
+
public void notifyBiometricAuthModeChanged() {
mDozeServiceHost.updateDozing();
updateScrimController();
@@ -3789,7 +3717,7 @@
@VisibleForTesting
public void updateScrimController() {
- Trace.beginSection("StatusBar#updateScrimController");
+ Trace.beginSection("CentralSurfaces#updateScrimController");
boolean unlocking = mKeyguardStateController.isShowing() && (
mBiometricUnlockController.isWakeAndUnlock()
@@ -4355,7 +4283,7 @@
if (mBrightnessMirrorController != null) {
mBrightnessMirrorController.onDensityOrFontScaleChanged();
}
- // TODO: Bring these out of StatusBar.
+ // TODO: Bring these out of CentralSurfaces.
mUserInfoControllerImpl.onDensityOrFontScaleChanged();
mUserSwitcherController.onDensityOrFontScaleChanged();
mNotificationIconAreaController.onDensityOrFontScaleChanged(mContext);
@@ -4413,7 +4341,7 @@
mDozeServiceHost.updateDozing();
updateTheme();
mNavigationBarController.touchAutoDim(mDisplayId);
- Trace.beginSection("StatusBar#updateKeyguardState");
+ Trace.beginSection("CentralSurfaces#updateKeyguardState");
if (mState == StatusBarState.KEYGUARD) {
mNotificationPanelViewController.cancelPendingPanelCollapse();
}
@@ -4436,7 +4364,7 @@
@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
similarity index 80%
rename from packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
index 4081962..536be1c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
@@ -59,26 +59,24 @@
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;
import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
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;
private final NotificationPanelViewController mNotificationPanelViewController;
- private final Optional<LegacySplitScreen> mSplitScreenOptional;
private final RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
private final MetricsLogger mMetricsLogger;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@@ -107,14 +105,13 @@
VibrationAttributes.createForUsage(VibrationAttributes.USAGE_HARDWARE_FEEDBACK);
@Inject
- StatusBarCommandQueueCallbacks(
- StatusBar statusBar,
+ CentralSurfacesCommandQueueCallbacks(
+ CentralSurfaces centralSurfaces,
Context context,
@Main Resources resources,
ShadeController shadeController,
CommandQueue commandQueue,
NotificationPanelViewController notificationPanelViewController,
- Optional<LegacySplitScreen> splitScreenOptional,
RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
MetricsLogger metricsLogger,
KeyguardUpdateMonitor keyguardUpdateMonitor,
@@ -136,12 +133,11 @@
DisableFlagsLogger disableFlagsLogger,
@DisplayId int displayId) {
- mStatusBar = statusBar;
+ mCentralSurfaces = centralSurfaces;
mContext = context;
mShadeController = shadeController;
mCommandQueue = commandQueue;
mNotificationPanelViewController = notificationPanelViewController;
- mSplitScreenOptional = splitScreenOptional;
mRemoteInputQuickSettingsDisabler = remoteInputQuickSettingsDisabler;
mMetricsLogger = metricsLogger;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
@@ -176,12 +172,12 @@
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);
}
@@ -189,7 +185,7 @@
@Override
public void remQsTile(ComponentName tile) {
- QSPanelController qsPanelController = mStatusBar.getQSPanelController();
+ QSPanelController qsPanelController = mCentralSurfaces.getQSPanelController();
if (qsPanelController != null && qsPanelController.getHost() != null) {
qsPanelController.getHost().removeTile(tile);
}
@@ -197,7 +193,7 @@
@Override
public void clickTile(ComponentName tile) {
- QSPanelController qsPanelController = mStatusBar.getQSPanelController();
+ QSPanelController qsPanelController = mCentralSurfaces.getQSPanelController();
if (qsPanelController != null) {
qsPanelController.clickTile(tile);
}
@@ -211,9 +207,9 @@
@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;
@@ -224,9 +220,9 @@
@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;
@@ -240,21 +236,15 @@
@Override
public void appTransitionCancelled(int displayId) {
- if (displayId == mDisplayId) {
- mSplitScreenOptional.ifPresent(LegacySplitScreen::onAppTransitionFinished);
- }
}
@Override
public void appTransitionFinished(int displayId) {
- if (displayId == mDisplayId) {
- mSplitScreenOptional.ifPresent(LegacySplitScreen::onAppTransitionFinished);
- }
}
@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.
@@ -267,22 +257,22 @@
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) {
@@ -291,17 +281,17 @@
}
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();
}
@@ -314,8 +304,8 @@
*/
@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()) {
@@ -351,81 +341,82 @@
@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");
@@ -434,17 +425,18 @@
// 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()) {
@@ -458,12 +450,12 @@
// 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);
}
@@ -474,12 +466,12 @@
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);
}
@@ -493,12 +485,12 @@
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
@@ -514,12 +506,12 @@
@Override
public void showPinningEnterExitToast(boolean entering) {
- mStatusBar.showPinningEnterExitToast(entering);
+ mCentralSurfaces.showPinningEnterExitToast(entering);
}
@Override
public void showPinningEscapeToast() {
- mStatusBar.showPinningEscapeToast();
+ mCentralSurfaces.showPinningEscapeToast();
}
@Override
@@ -529,12 +521,12 @@
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
@@ -544,23 +536,18 @@
@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();
}
}
- @Override
- public void toggleSplitScreen() {
- mStatusBar.toggleSplitScreenMode(-1 /* metricsDockAction */, -1 /* metricsUndockAction */);
- }
-
private boolean isGoingToSleep() {
return mWakefulnessLifecycle.getWakefulness()
== WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP;
@@ -591,8 +578,8 @@
// 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 b141110..8b25c2b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -16,9 +16,14 @@
package com.android.systemui.statusbar.phone;
+import android.content.ContentResolver;
+import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.database.ContentObserver;
import android.hardware.display.AmbientDisplayConfiguration;
+import android.net.Uri;
+import android.os.Handler;
import android.os.PowerManager;
import android.os.SystemProperties;
import android.os.UserHandle;
@@ -34,6 +39,7 @@
import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.doze.AlwaysOnDisplayPolicy;
import com.android.systemui.doze.DozeScreenState;
@@ -86,6 +92,7 @@
private boolean mDozeAlwaysOn;
private boolean mControlScreenOffAnimation;
+ private boolean mIsQuickPickupEnabled;
private boolean mKeyguardShowing;
@VisibleForTesting
@@ -101,10 +108,17 @@
public void onShadeExpandedChanged(boolean expanded) {
updateControlScreenOff();
}
+
+ @Override
+ public void onUserSwitchComplete(int newUserId) {
+ updateQuickPickupEnabled();
+ }
};
@Inject
protected DozeParameters(
+ Context context,
+ @Background Handler handler,
@Main Resources resources,
AmbientDisplayConfiguration ambientDisplayConfiguration,
AlwaysOnDisplayPolicy alwaysOnDisplayPolicy,
@@ -146,6 +160,14 @@
if (mFoldAodAnimationController != null) {
mFoldAodAnimationController.addCallback(this);
}
+
+ SettingsObserver quickPickupSettingsObserver = new SettingsObserver(context, handler);
+ quickPickupSettingsObserver.observe();
+ }
+
+ private void updateQuickPickupEnabled() {
+ mIsQuickPickupEnabled =
+ mAmbientDisplayConfiguration.quickPickupSensorEnabled(UserHandle.USER_CURRENT);
}
public boolean getDisplayStateSupported() {
@@ -239,8 +261,11 @@
return mDozeAlwaysOn && !mBatteryController.isAodPowerSave();
}
+ /**
+ * Whether the quick pickup gesture is supported and enabled for the device.
+ */
public boolean isQuickPickupEnabled() {
- return mAmbientDisplayConfiguration.quickPickupSensorEnabled(UserHandle.USER_CURRENT);
+ return mIsQuickPickupEnabled;
}
/**
@@ -436,6 +461,7 @@
pw.print("getPickupVibrationThreshold(): "); pw.println(getPickupVibrationThreshold());
pw.print("getSelectivelyRegisterSensorsUsingProx(): ");
pw.println(getSelectivelyRegisterSensorsUsingProx());
+ pw.print("isQuickPickupEnabled(): "); pw.println(isQuickPickupEnabled());
}
private boolean getPostureSpecificBool(
@@ -458,4 +484,44 @@
*/
void onAlwaysOnChange();
}
+
+ private final class SettingsObserver extends ContentObserver {
+ private final Uri mQuickPickupGesture =
+ Settings.Secure.getUriFor(Settings.Secure.DOZE_QUICK_PICKUP_GESTURE);
+ private final Uri mPickupGesture =
+ Settings.Secure.getUriFor(Settings.Secure.DOZE_PICK_UP_GESTURE);
+ private final Uri mAlwaysOnEnabled =
+ Settings.Secure.getUriFor(Settings.Secure.DOZE_ALWAYS_ON);
+ private final Context mContext;
+
+ SettingsObserver(Context context, Handler handler) {
+ super(handler);
+ mContext = context;
+ }
+
+ void observe() {
+ ContentResolver resolver = mContext.getContentResolver();
+ resolver.registerContentObserver(mQuickPickupGesture, false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(mPickupGesture, false, this, UserHandle.USER_ALL);
+ resolver.registerContentObserver(mAlwaysOnEnabled, false, this, UserHandle.USER_ALL);
+ update(null);
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ update(uri);
+ }
+
+ public void update(Uri uri) {
+ if (uri == null
+ || mQuickPickupGesture.equals(uri)
+ || mPickupGesture.equals(uri)
+ || mAlwaysOnEnabled.equals(uri)) {
+ // the quick pickup gesture is dependent on alwaysOn being disabled and
+ // the pickup gesture being enabled
+ updateQuickPickupEnabled();
+ }
+ }
+ }
}
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 05fba54..55b310f 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 @@
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 @@
* 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 @@
mDozingRequested = true;
updateDozing();
mDozeLog.traceDozing(mStatusBarStateController.isDozing());
- mStatusBar.updateIsKeyguard();
+ mCentralSurfaces.updateIsKeyguard();
}
}
@@ -247,13 +247,13 @@
&& 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 void onPulseFinished() {
mPulsing = false;
callback.onPulseFinished();
- mStatusBar.updateNotificationPanelTouchState();
+ mCentralSurfaces.updateNotificationPanelTouchState();
mScrimController.setWakeLockScreenSensorActive(false);
setPulsing(false);
}
@@ -274,14 +274,14 @@
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 @@
}
@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 @@
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 @@
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 84103c0..541aeab 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 @@
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 @@
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 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 @@
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 @@
} 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 @@
@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 9bdefcd..2c4fc6c 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 a0f8d05..61760fb 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.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 javax.inject.Inject;
import javax.inject.Provider;
-@StatusBarComponent.StatusBarScope
+@CentralSurfacesComponent.CentralSurfacesScope
public class NotificationPanelViewController extends PanelViewController
implements NotifPanelEventSource {
@@ -665,6 +666,8 @@
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 @@
InteractionJankMonitor interactionJankMonitor,
QsFrameTranslateController qsFrameTranslateController,
SysUiState sysUiState,
- KeyguardUnlockAnimationController keyguardUnlockAnimationController) {
+ KeyguardUnlockAnimationController keyguardUnlockAnimationController,
+ NotificationListContainer notificationListContainer) {
super(view,
falsingManager,
dozeLog,
@@ -823,6 +827,7 @@
mMediaHierarchyManager = mediaHierarchyManager;
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
mNotificationsQSContainerController = notificationsQSContainerController;
+ mNotificationListContainer = notificationListContainer;
mNotificationsQSContainerController.init();
mNotificationStackScrollLayoutController = notificationStackScrollLayoutController;
mGroupManager = groupManager;
@@ -1127,10 +1132,10 @@
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() {
@@ -1141,8 +1146,13 @@
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 =
+
+ final boolean newShouldUseSplitNotificationShade =
Utils.shouldUseSplitNotificationShade(mResources);
+ final boolean splitNotificationShadeChanged =
+ mShouldUseSplitNotificationShade != newShouldUseSplitNotificationShade;
+
+ mShouldUseSplitNotificationShade = newShouldUseSplitNotificationShade;
if (mQs != null) {
mQs.setInSplitShade(mShouldUseSplitNotificationShade);
}
@@ -1188,6 +1198,10 @@
updateKeyguardStatusViewAlignment(/* animate= */false);
mKeyguardMediaController.refreshMediaPosition();
+
+ if (splitNotificationShadeChanged) {
+ updateClockAppearance();
+ }
}
private static void ensureAllViewsHaveIds(ViewGroup parentView) {
@@ -1311,7 +1325,7 @@
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 +1588,7 @@
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 +1742,7 @@
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 +1841,7 @@
@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 +2030,8 @@
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 +2309,7 @@
}
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 +2336,7 @@
// 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 +2347,7 @@
updateQsState();
requestPanelHeightUpdate();
mFalsingCollector.setQsExpanded(expanded);
- mStatusBar.setQsExpanded(expanded);
+ mCentralSurfaces.setQsExpanded(expanded);
mNotificationsQSContainerController.setQsExpanded(expanded);
mPulseExpansionHandler.setQsExpanded(expanded);
mKeyguardBypassController.setQSExpanded(expanded);
@@ -2417,7 +2431,7 @@
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 +3119,7 @@
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 +3244,7 @@
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 +3583,7 @@
@Override
protected void onClosingFinished() {
- mStatusBar.onClosingFinished();
+ mCentralSurfaces.onClosingFinished();
setClosingWithAlphaFadeout(false);
mMediaHierarchyManager.closeGuts();
}
@@ -3631,7 +3645,7 @@
}
public void clearNotificationEffects() {
- mStatusBar.clearNotificationEffects();
+ mCentralSurfaces.clearNotificationEffects();
}
@Override
@@ -3693,7 +3707,7 @@
* 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 +4051,7 @@
}
public boolean hasPulsingNotifications() {
- return mNotificationStackScrollLayoutController
- .getNotificationListContainer().hasPulsingNotifications();
+ return mNotificationListContainer.hasPulsingNotifications();
}
public ActivatableNotificationView getActivatedChild() {
@@ -4073,10 +4086,10 @@
* @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 +4162,7 @@
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 +4205,8 @@
// 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 +4270,15 @@
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 +4495,7 @@
: !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 +4503,7 @@
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 +4519,7 @@
}
mFalsingCollector.onCameraOn();
if (mFalsingCollector.shouldEnforceBouncer()) {
- mStatusBar.executeRunnableDismissingKeyguard(
+ mCentralSurfaces.executeRunnableDismissingKeyguard(
() -> mKeyguardBottomArea.launchCamera(mLastCameraLaunchSource), null,
true /* dismissShade */, false /* afterKeyguardGone */,
true /* deferred */);
@@ -4514,7 +4527,7 @@
mKeyguardBottomArea.launchCamera(mLastCameraLaunchSource);
}
}
- mStatusBar.startLaunchTransitionTimeout();
+ mCentralSurfaces.startLaunchTransitionTimeout();
mBlockTouches = true;
}
@@ -4526,7 +4539,7 @@
mLaunchAnimationEndRunnable.run();
mLaunchAnimationEndRunnable = null;
}
- mStatusBar.readyForKeyguardDone();
+ mCentralSurfaces.readyForKeyguardDone();
}
@Override
@@ -4563,18 +4576,18 @@
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 +4618,7 @@
@Override
public float getAffordanceFalsingFactor() {
- return mStatusBar.isWakeUpComingFromTouch() ? 1.5f : 1.0f;
+ return mCentralSurfaces.isWakeUpComingFromTouch() ? 1.5f : 1.0f;
}
@Override
@@ -5121,7 +5134,7 @@
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 9f9e7d9..0ff010a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
@@ -26,6 +26,7 @@
import android.app.IActivityManager;
import android.content.Context;
import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.graphics.Region;
import android.os.Binder;
@@ -117,6 +118,7 @@
* @see #batchApplyWindowLayoutParams(Runnable)
*/
private int mDeferWindowLayoutParams;
+ private boolean mLastKeyguardRotationAllowed;
@Inject
public NotificationShadeWindowControllerImpl(Context context, WindowManager windowManager,
@@ -143,7 +145,7 @@
mScreenOffAnimationController = screenOffAnimationController;
dumpManager.registerDumpable(getClass().getName(), this);
mAuthController = authController;
-
+ mLastKeyguardRotationAllowed = mKeyguardStateController.isKeyguardScreenRotationAllowed();
mLockScreenDisplayTimeout = context.getResources()
.getInteger(R.integer.config_lockScreenDisplayTimeout);
((SysuiStatusBarStateController) statusBarStateController)
@@ -779,6 +781,17 @@
setKeyguardDark(useDarkText);
}
+ @Override
+ public void onConfigChanged(Configuration newConfig) {
+ final boolean newScreenRotationAllowed = mKeyguardStateController
+ .isKeyguardScreenRotationAllowed();
+
+ if (mLastKeyguardRotationAllowed != newScreenRotationAllowed) {
+ apply(mCurrentState);
+ mLastKeyguardRotationAllowed = newScreenRotationAllowed;
+ }
+ }
+
/**
* When keyguard will be dismissed but didn't start animation yet.
*/
@@ -827,7 +840,7 @@
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 fb0e306..1e3a02b 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 @@
*/
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 396703b..101c86f 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.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 @@
/**
* Controller for {@link NotificationShadeWindowView}.
*/
+@CentralSurfacesComponent.CentralSurfacesScope
public class NotificationShadeWindowViewController {
private static final String TAG = "NotifShadeWindowVC";
private final FalsingCollector mFalsingCollector;
@@ -77,8 +79,8 @@
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 @@
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 @@
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 @@
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 249f988..45dc943 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 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 85e8042..7c1775e 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 @@
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 @@
//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 @@
}
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 @@
if (mUpdateFlingOnLayout) {
mUpdateFlingVelocity = vel;
}
- } else if (!mStatusBar.isBouncerShowing()
+ } else if (!mCentralSurfaces.isBouncerShowing()
&& !mStatusBarKeyguardViewManager.isShowingAlternateAuthOrAnimating()
&& !mKeyguardStateController.isKeyguardGoingAway()) {
boolean expands = onEmptySpaceClick(mInitialTouchX);
@@ -469,7 +470,7 @@
}
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 @@
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 @@
*/
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 @@
mView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
return;
}
- if (mStatusBar.getNotificationShadeWindowView().isVisibleToUser()) {
+ if (mCentralSurfaces.getNotificationShadeWindowView().isVisibleToUser()) {
mView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
if (mAnimateAfterExpanding) {
notifyExpandingStarted();
@@ -976,11 +977,11 @@
}
protected void onUnlockHintFinished() {
- mStatusBar.onHintFinished();
+ mCentralSurfaces.onHintFinished();
}
protected void onUnlockHintStarted() {
- mStatusBar.onUnlockHintStarted();
+ mCentralSurfaces.onUnlockHintStarted();
}
public boolean isUnlockHintRunning() {
@@ -1018,7 +1019,7 @@
View[] viewsToAnimate = {
mKeyguardBottomArea.getIndicationArea(),
- mStatusBar.getAmbientIndicationContainer()};
+ mCentralSurfaces.getAmbientIndicationContainer()};
for (View v : viewsToAnimate) {
if (v == null) {
continue;
@@ -1210,7 +1211,7 @@
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 @@
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 224b2e4..9da2ef73 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.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 @@
@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 @@
* 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 @@
@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 @@
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 ea61a8b..c817466 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 @@
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 @@
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 @@
}
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 8d64041..a3c795f 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 @@
}
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 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 bfd625b..9028870 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 @@
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 24bb7f2..83ee125 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 @@
/**
* {@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 @@
/**
* 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 72237b1..cee8b33 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeControllerImpl.java
@@ -27,7 +27,6 @@
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.StatusBarState;
-import com.android.wm.shell.bubbles.Bubbles;
import java.util.ArrayList;
import java.util.Optional;
@@ -48,9 +47,8 @@
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 Optional<Bubbles> mBubblesOptional;
private final ArrayList<Runnable> mPostCollapseRunnables = new ArrayList<>();
@@ -61,25 +59,23 @@
NotificationShadeWindowController notificationShadeWindowController,
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
WindowManager windowManager,
- Lazy<Optional<StatusBar>> statusBarOptionalLazy,
- Lazy<AssistManager> assistManagerLazy,
- Optional<Bubbles> bubblesOptional
+ Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy,
+ Lazy<AssistManager> assistManagerLazy
) {
mCommandQueue = commandQueue;
mStatusBarStateController = statusBarStateController;
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;
- mBubblesOptional = bubblesOptional;
}
@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 */);
}
@@ -114,7 +110,7 @@
}
if (SPEW) {
Log.d(TAG, "animateCollapse():"
- + " mExpandedVisible=" + getStatusBar().isExpandedVisible()
+ + " mExpandedVisible=" + getCentralSurfaces().isExpandedVisible()
+ " flags=" + flags);
}
@@ -128,11 +124,9 @@
// release focus immediately to kick off focus change transition
mNotificationShadeWindowController.setNotificationShadeFocusable(false);
- getStatusBar().getNotificationShadeWindowViewController().cancelExpandHelper();
+ getCentralSurfaces().getNotificationShadeWindowViewController().cancelExpandHelper();
getNotificationPanelViewController()
.collapsePanel(true /* animate */, delayed, speedUpFactor);
- } else if (mBubblesOptional.isPresent()) {
- mBubblesOptional.get().collapseStack();
}
}
@@ -142,7 +136,7 @@
if (!getNotificationPanelViewController().isFullyCollapsed()) {
mCommandQueue.animateCollapsePanels(
CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */);
- getStatusBar().visibilityChanged(false);
+ getCentralSurfaces().visibilityChanged(false);
mAssistManagerLazy.get().hideAssist();
}
return false;
@@ -161,7 +155,7 @@
new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
- if (getStatusBar().getNotificationShadeWindowView().isVisibleToUser()) {
+ if (getCentralSurfaces().getNotificationShadeWindowView().isVisibleToUser()) {
getNotificationPanelViewController().removeOnGlobalLayoutListener(this);
getNotificationPanelViewController().getView().post(executable);
}
@@ -191,7 +185,7 @@
// 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 {
@@ -207,26 +201,26 @@
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 a1be5ac..7555356 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.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 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 6eeae7f..50f2169 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.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 81fb903..31d9266 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.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 @@
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 @@
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 @@
mDemoable = demoable;
}
- public void setBlockList(@Nullable List<String> blockList) {
- mBlockList.clear();
- if (blockList == null || blockList.isEmpty()) {
- return;
- }
+ void setController(StatusBarIconController controller) {
+ mController = controller;
+ }
+ public void setBlockList(@Nullable List<String> blockList) {
+ Assert.isMainThread();
+ mBlockList.clear();
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 c5d3937..623ec5e 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 @@
}
}
+ group.setController(this);
mIconGroups.add(group);
List<Slot> allSlots = getSlots();
for (int i = 0; i < allSlots.size(); i++) {
@@ -115,6 +116,12 @@
}
}
+ @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 @@
/**
* 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 @@
/**
* 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 11d9c31..c160c22 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 @@
@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 @@
protected LockPatternUtils mLockPatternUtils;
protected ViewMediatorCallback mViewMediatorCallback;
- protected StatusBar mStatusBar;
+ protected CentralSurfaces mCentralSurfaces;
private NotificationPanelViewController mNotificationPanelViewController;
private BiometricUnlockController mBiometricUnlockController;
@@ -277,16 +277,16 @@
}
@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 @@
} 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 @@
} 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 @@
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 @@
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 @@
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 @@
@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 @@
}
/**
- * If {@link StatusBar} is pulsing.
+ * If {@link CentralSurfaces} is pulsing.
*/
public void setPulsing(boolean pulsing) {
if (mPulsing != pulsing) {
@@ -649,13 +651,13 @@
@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 @@
return;
}
- if (mStatusBar.isLaunchingActivityOverLockscreen()) {
+ if (mCentralSurfaces.isLaunchingActivityOverLockscreen()) {
setOccludedAndUpdateStates(true);
// When isLaunchingActivityOverLockscreen() is true, we know for sure that the post
@@ -695,7 +697,7 @@
reset(isOccluding /* hideBouncerWhenShowing*/);
}
if (animate && !occluded && mShowing && !mBouncer.isShowing()) {
- mStatusBar.animateKeyguardUnoccluding();
+ mCentralSurfaces.animateKeyguardUnoccluding();
}
}
@@ -712,7 +714,7 @@
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 @@
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 @@
}, 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 @@
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 @@
mNotificationContainer,
fadeoutDuration,
() -> {
- mStatusBar.hideKeyguard();
+ mCentralSurfaces.hideKeyguard();
onKeyguardFadedAway();
});
} else {
- mStatusBar.fadeKeyguardWhilePulsing();
+ mCentralSurfaces.fadeKeyguardWhilePulsing();
}
wakeAndUnlockDejank();
} else {
@@ -810,20 +812,20 @@
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 @@
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 @@
@Override
public void dismissAndCollapse() {
- mStatusBar.executeRunnableDismissingKeyguard(null, null, true, false, true);
+ mCentralSurfaces.executeRunnableDismissingKeyguard(null, null, true, false, true);
}
/**
@@ -922,7 +924,7 @@
*/
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 @@
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 @@
if (bouncerShowing != mLastBouncerShowing || mFirstUpdate) {
mNotificationShadeWindowController.setBouncerShowing(bouncerShowing);
- mStatusBar.setBouncerShowing(bouncerShowing);
+ mCentralSurfaces.setBouncerShowing(bouncerShowing);
}
if (occluded != mLastOccluded || mFirstUpdate) {
@@ -1040,11 +1042,11 @@
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 @@
* 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 @@
}
} else {
mNotificationContainer.removeCallbacks(mMakeNavigationBarVisibleRunnable);
- mStatusBar.getNotificationShadeWindowView().getWindowInsetsController()
+ mCentralSurfaces.getNotificationShadeWindowView().getWindowInsetsController()
.hide(navigationBars());
}
}
@@ -1077,7 +1079,8 @@
&& mBiometricUnlockController.getMode() == MODE_WAKE_AND_UNLOCK_PULSING;
boolean keyguardShowing = mShowing && !mOccluded;
boolean hideWhileDozing = mDozing && !isWakeAndUnlockPulsing;
- boolean keyguardWithGestureNav = (keyguardShowing && !mDozing || mPulsing && !mIsDocked)
+ boolean keyguardWithGestureNav = (keyguardShowing && !mDozing && !mScreenOffAnimationPlaying
+ || mPulsing && !mIsDocked)
&& mGesturalNav;
return (!keyguardShowing && !hideWhileDozing && !mScreenOffAnimationPlaying
|| mBouncer.isShowing() || mRemoteInputActive || keyguardWithGestureNav
@@ -1091,7 +1094,8 @@
boolean keyguardShowing = mLastShowing && !mLastOccluded;
boolean hideWhileDozing = mLastDozing && mLastBiometricMode != MODE_WAKE_AND_UNLOCK_PULSING;
boolean keyguardWithGestureNav = (keyguardShowing && !mLastDozing
- || mLastPulsing && !mLastIsDocked) && mLastGesturalNav;
+ && !mLastScreenOffAnimationPlaying || mLastPulsing && !mLastIsDocked)
+ && mLastGesturalNav;
return (!keyguardShowing && !hideWhileDozing && !mLastScreenOffAnimationPlaying
|| mLastBouncerShowing || mLastRemoteInputActive || keyguardWithGestureNav
|| mLastGlobalActionsVisible);
@@ -1118,7 +1122,7 @@
@Override
public boolean shouldDisableWindowAnimationsForUnlock() {
- return mStatusBar.isInLaunchTransition();
+ return mCentralSurfaces.isInLaunchTransition();
}
@Override
@@ -1137,7 +1141,7 @@
@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 09fca100..56b6dfc 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 @@
*/
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 @@
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 ff86d74..edbddbb 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 @@
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.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.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 @@
/**
* 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 @@
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 @@
private boolean mIsCollapsingToShowActivityOverLockscreen;
- private StatusBarNotificationActivityStarter(
+ @Inject
+ StatusBarNotificationActivityStarter(
Context context,
CommandQueue commandQueue,
Handler mainThreadHandler,
@@ -162,7 +162,7 @@
MetricsLogger metricsLogger,
StatusBarNotificationActivityStarterLogger logger,
OnUserInteractionCallback onUserInteractionCallback,
- StatusBar statusBar,
+ CentralSurfaces centralSurfaces,
NotificationPresenter presenter,
NotificationPanelViewController panel,
ActivityLaunchAnimator activityLaunchAnimator,
@@ -199,7 +199,7 @@
mOnUserInteractionCallback = onUserInteractionCallback;
// TODO: use KeyguardStateController#isOccluded to remove this dependency
- mStatusBar = statusBar;
+ mCentralSurfaces = centralSurfaces;
mPresenter = presenter;
mNotificationPanel = panel;
mActivityLaunchAnimator = activityLaunchAnimator;
@@ -259,7 +259,7 @@
&& 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 @@
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 @@
try {
ActivityLaunchAnimator.Controller animationController =
new StatusBarLaunchAnimatorController(
- mNotificationAnimationProvider.getAnimatorController(row), mStatusBar,
+ mNotificationAnimationProvider.getAnimatorController(row),
+ mCentralSurfaces,
isActivityIntent);
mActivityLaunchAnimator.startPendingIntentWithAnimation(animationController,
@@ -483,11 +484,11 @@
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 @@
@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 @@
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 @@
@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 @@
);
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 @@
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 @@
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 0000000..caa149e
--- /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 c8e1cdc..aa061d7 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.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 @@
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 @@
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 @@
DynamicPrivacyController dynamicPrivacyController,
KeyguardStateController keyguardStateController,
KeyguardIndicationController keyguardIndicationController,
- StatusBar statusBar,
+ CentralSurfaces centralSurfaces,
ShadeController shadeController,
LockscreenShadeTransitionController shadeTransitionController,
CommandQueue commandQueue,
@@ -144,14 +152,17 @@
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 @@
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 @@
}
}
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 @@
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 @@
updateNotificationViews("user switched");
}
mMediaManager.clearCurrentMediaNotification();
- mStatusBar.setLockscreenUser(newUserId);
+ mCentralSurfaces.setLockscreenUser(newUserId);
updateMediaMetaData(true, false);
}
@@ -395,7 +406,8 @@
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 @@
@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 @@
// 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 @@
@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 0000000..26c483c
--- /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 b0206f0..ee242a4 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 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 @@
}
/**
- * 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 b742394..95667cc 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 @@
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 @@
}
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 @@
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/SystemUIDialog.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
index 9722528..79d646c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
@@ -42,7 +42,10 @@
import com.android.systemui.Dependency;
import com.android.systemui.R;
+import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.model.SysUiState;
+import com.android.systemui.shared.system.QuickStepContract;
import java.util.ArrayList;
import java.util.List;
@@ -64,7 +67,8 @@
private final Context mContext;
@Nullable private final DismissReceiver mDismissReceiver;
private final Handler mHandler = new Handler();
- @Nullable private final SystemUIDialogManager mDialogManager;
+ private final SystemUIDialogManager mDialogManager;
+ private final SysUiState mSysUiState;
private int mLastWidth = Integer.MIN_VALUE;
private int mLastHeight = Integer.MIN_VALUE;
@@ -77,24 +81,11 @@
this(context, R.style.Theme_SystemUI_Dialog);
}
- public SystemUIDialog(Context context, SystemUIDialogManager dialogManager) {
- this(context, R.style.Theme_SystemUI_Dialog, true, dialogManager);
- }
-
public SystemUIDialog(Context context, int theme) {
this(context, theme, true /* dismissOnDeviceLock */);
}
- public SystemUIDialog(Context context, int theme, SystemUIDialogManager dialogManager) {
- this(context, theme, true /* dismissOnDeviceLock */, dialogManager);
- }
-
public SystemUIDialog(Context context, int theme, boolean dismissOnDeviceLock) {
- this(context, theme, dismissOnDeviceLock, null);
- }
-
- public SystemUIDialog(Context context, int theme, boolean dismissOnDeviceLock,
- @Nullable SystemUIDialogManager dialogManager) {
super(context, theme);
mContext = context;
@@ -104,7 +95,12 @@
getWindow().setAttributes(attrs);
mDismissReceiver = dismissOnDeviceLock ? new DismissReceiver(this) : null;
- mDialogManager = dialogManager;
+
+ // TODO(b/219008720): Remove those calls to Dependency.get by introducing a
+ // SystemUIDialogFactory and make all other dialogs create a SystemUIDialog to which we set
+ // the content and attach listeners.
+ mDialogManager = Dependency.get(SystemUIDialogManager.class);
+ mSysUiState = Dependency.get(SysUiState.class);
}
@Override
@@ -174,13 +170,11 @@
mDismissReceiver.register();
}
- if (mDialogManager != null) {
- mDialogManager.setShowing(this, true);
- }
-
// Listen for configuration changes to resize this dialog window. This is mostly necessary
// for foldables that often go from large <=> small screen when folding/unfolding.
ViewRootImpl.addConfigCallback(this);
+ mDialogManager.setShowing(this, true);
+ mSysUiState.setFlag(QuickStepContract.SYSUI_STATE_DIALOG_SHOWING, true);
}
@Override
@@ -191,11 +185,9 @@
mDismissReceiver.unregister();
}
- if (mDialogManager != null) {
- mDialogManager.setShowing(this, false);
- }
-
ViewRootImpl.removeConfigCallback(this);
+ mDialogManager.setShowing(this, false);
+ mSysUiState.setFlag(QuickStepContract.SYSUI_STATE_DIALOG_SHOWING, false);
}
public void setShowForAllUsers(boolean show) {
@@ -401,10 +393,13 @@
private final Dialog mDialog;
private boolean mRegistered;
private final BroadcastDispatcher mBroadcastDispatcher;
+ private final DialogLaunchAnimator mDialogLaunchAnimator;
DismissReceiver(Dialog dialog) {
mDialog = dialog;
+ // TODO(b/219008720): Remove those calls to Dependency.get.
mBroadcastDispatcher = Dependency.get(BroadcastDispatcher.class);
+ mDialogLaunchAnimator = Dependency.get(DialogLaunchAnimator.class);
}
void register() {
@@ -421,6 +416,10 @@
@Override
public void onReceive(Context context, Intent intent) {
+ // These broadcast are usually received when locking the device, swiping up to home
+ // (which collapses the shade), etc. In those cases, we usually don't want to animate
+ // back into the view.
+ mDialogLaunchAnimator.disableAllCurrentDialogsExitAnimations();
mDialog.dismiss();
}
}
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 26ba31c..582afb1 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 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 @@
/**
* 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 0abe8e4..c11d450 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,13 @@
private val handler: Handler = Handler()
) : WakefulnessLifecycle.Observer, ScreenOffAnimation {
- private lateinit var statusBar: StatusBar
+ private lateinit var mCentralSurfaces: CentralSurfaces
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 +80,6 @@
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 +91,6 @@
override fun onAnimationCancel(animation: Animator?) {
lightRevealScrim.revealAmount = 1f
lightRevealAnimationPlaying = false
- sendUnlockedScreenOffProgressUpdate(0f, 0f)
interactionJankMonitor.cancel(CUJ_SCREEN_OFF)
}
@@ -105,7 +100,8 @@
}
override fun onAnimationStart(animation: Animator?) {
- interactionJankMonitor.begin(statusBar.notificationShadeWindowView, CUJ_SCREEN_OFF)
+ interactionJankMonitor.begin(
+ mCentralSurfaces.notificationShadeWindowView, CUJ_SCREEN_OFF)
}
})
}
@@ -117,11 +113,11 @@
}
override fun initialize(
- statusBar: StatusBar,
+ centralSurfaces: CentralSurfaces,
lightRevealScrim: LightRevealScrim
) {
this.lightRevealScrim = lightRevealScrim
- this.statusBar = statusBar
+ this.mCentralSurfaces = centralSurfaces
updateAnimatorDurationScale()
globalSettings.registerContentObserver(
@@ -176,9 +172,9 @@
// 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 +192,8 @@
override fun onAnimationStart(animation: Animator?) {
interactionJankMonitor.begin(
- statusBar.notificationShadeWindowView, CUJ_SCREEN_OFF_SHOW_AOD)
+ mCentralSurfaces.notificationShadeWindowView,
+ CUJ_SCREEN_OFF_SHOW_AOD)
}
})
.start()
@@ -213,12 +210,12 @@
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 +224,7 @@
// 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 +246,7 @@
// Show AOD. That'll cause the KeyguardVisibilityHelper to call
// #animateInKeyguard.
- statusBar.notificationPanelViewController.showAodUi()
+ mCentralSurfaces.notificationPanelViewController.showAodUi()
}
}, (ANIMATE_IN_KEYGUARD_DELAY * animatorDurationScale).toLong())
@@ -285,8 +282,8 @@
// 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()
@@ -309,20 +306,6 @@
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)
- }
- }
-
/**
* Whether we're doing the light reveal animation or we're done with that and animating in the
* AOD UI.
@@ -356,8 +339,4 @@
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
similarity index 69%
rename from packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarComponent.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java
index ad8e79e..59c9d0b 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 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 @@
/**
* 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 @@
* 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 @@
/**
* 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 c6b5b1d..c024c72 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.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;
@@ -115,7 +114,6 @@
import com.android.systemui.volume.VolumeComponent;
import com.android.systemui.wmshell.BubblesManager;
import com.android.wm.shell.bubbles.Bubbles;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.startingsurface.StartingSurface;
import java.util.Optional;
@@ -128,16 +126,16 @@
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,
@@ -197,11 +195,8 @@
DozeScrimController dozeScrimController,
VolumeComponent volumeComponent,
CommandQueue commandQueue,
- StatusBarComponent.Factory statusBarComponentFactory,
+ CentralSurfacesComponent.Factory statusBarComponentFactory,
PluginManager pluginManager,
- Optional<LegacySplitScreen> splitScreenOptional,
- StatusBarNotificationActivityStarter.Builder
- statusBarNotificationActivityStarterBuilder,
ShadeController shadeController,
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
ViewMediatorCallback viewMediatorCallback,
@@ -236,7 +231,7 @@
DeviceStateManager deviceStateManager,
DreamOverlayStateController dreamOverlayStateController,
WiredChargingRippleController wiredChargingRippleController) {
- return new StatusBar(
+ return new CentralSurfaces(
context,
notificationsController,
fragmentService,
@@ -298,8 +293,6 @@
commandQueue,
statusBarComponentFactory,
pluginManager,
- splitScreenOptional,
- 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 ebd58fb..79fe700 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.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 @@
/** */
@Provides
- @StatusBarComponent.StatusBarScope
+ @CentralSurfacesComponent.CentralSurfacesScope
public static NotificationShadeWindowView providesNotificationShadeWindowView(
LayoutInflater layoutInflater) {
NotificationShadeWindowView notificationShadeWindowView = (NotificationShadeWindowView)
@@ -92,7 +95,7 @@
/** */
@Provides
- @StatusBarComponent.StatusBarScope
+ @CentralSurfacesComponent.CentralSurfacesScope
public static NotificationStackScrollLayout providesNotificationStackScrollLayout(
NotificationShadeWindowView notificationShadeWindowView) {
return notificationShadeWindowView.findViewById(R.id.notification_stack_scroller);
@@ -100,7 +103,7 @@
/** */
@Provides
- @StatusBarComponent.StatusBarScope
+ @CentralSurfacesComponent.CentralSurfacesScope
public static NotificationShelf providesNotificationShelf(LayoutInflater layoutInflater,
NotificationStackScrollLayout notificationStackScrollLayout) {
NotificationShelf view = (NotificationShelf) layoutInflater.inflate(
@@ -115,7 +118,7 @@
/** */
@Provides
- @StatusBarComponent.StatusBarScope
+ @CentralSurfacesComponent.CentralSurfacesScope
public static NotificationShelfController providesStatusBarWindowView(
NotificationShelfComponent.Builder notificationShelfComponentBuilder,
NotificationShelf notificationShelf) {
@@ -131,7 +134,7 @@
/** */
@Provides
- @StatusBarComponent.StatusBarScope
+ @CentralSurfacesComponent.CentralSurfacesScope
public static NotificationPanelView getNotificationPanelView(
NotificationShadeWindowView notificationShadeWindowView) {
return notificationShadeWindowView.getNotificationPanelView();
@@ -139,7 +142,7 @@
/** */
@Provides
- @StatusBarComponent.StatusBarScope
+ @CentralSurfacesComponent.CentralSurfacesScope
public static LockIconView getLockIconView(
NotificationShadeWindowView notificationShadeWindowView) {
return notificationShadeWindowView.findViewById(R.id.lock_icon_view);
@@ -147,7 +150,7 @@
/** */
@Provides
- @StatusBarComponent.StatusBarScope
+ @CentralSurfacesComponent.CentralSurfacesScope
@Nullable
public static AuthRippleView getAuthRippleView(
NotificationShadeWindowView notificationShadeWindowView) {
@@ -157,7 +160,7 @@
/** */
@Provides
@Named(SPLIT_SHADE_HEADER)
- @StatusBarComponent.StatusBarScope
+ @CentralSurfacesComponent.CentralSurfacesScope
public static View getSplitShadeStatusBarView(
NotificationShadeWindowView notificationShadeWindowView,
FeatureFlags featureFlags) {
@@ -172,7 +175,7 @@
/** */
@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 @@
/** */
@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 @@
/** */
@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 @@
* 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 @@
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 @@
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 2af0772..2c84219 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.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.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.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 @@
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 @@
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 @@
mCommandQueue = commandQueue;
mCollapsedStatusBarFragmentLogger = collapsedStatusBarFragmentLogger;
mOperatorNameViewControllerFactory = operatorNameViewControllerFactory;
+ mSecureSettings = secureSettings;
+ mMainExecutor = mainExecutor;
}
@Override
@@ -187,10 +200,7 @@
}
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 @@
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 @@
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 @@
mCommandQueue.removeCallback(this);
mStatusBarStateController.removeCallback(this);
mOngoingCallController.removeCallback(mOngoingCallListener);
+ mSecureSettings.unregisterContentObserver(mVolumeSettingObserver);
}
@Override
@@ -584,6 +618,13 @@
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 22b7f64..2eba325 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 @@
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 @@
*
* 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 c7f7258..de05eb1 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.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 @@
*/
@SysUISingleton
class OngoingCallController @Inject constructor(
+ private val context: Context,
private val notifCollection: CommonNotifCollection,
private val ongoingCallFlags: OngoingCallFlags,
private val systemClock: SystemClock,
@@ -242,8 +244,16 @@
* Sets up an [IUidObserver] to monitor the status of the application managing the ongoing call.
*/
private fun setUpUidObserver(currentCallNotificationInfo: CallNotificationInfo) {
- isCallAppVisible = isProcessVisibleToUser(
- iActivityManager.getUidProcessState(currentCallNotificationInfo.uid, null))
+ try {
+ isCallAppVisible = isProcessVisibleToUser(
+ iActivityManager.getUidProcessState(
+ currentCallNotificationInfo.uid, context.opPackageName
+ )
+ )
+ } catch (se: SecurityException) {
+ Log.e(TAG, "Security exception when trying to get process state: $se")
+ return
+ }
if (uidObserver != null) {
iActivityManager.unregisterUidObserver(uidObserver)
@@ -275,12 +285,17 @@
override fun onUidCachedChanged(uid: Int, cached: Boolean) {}
}
- iActivityManager.registerUidObserver(
+ try {
+ iActivityManager.registerUidObserver(
uidObserver,
ActivityManager.UID_OBSERVER_PROCSTATE,
ActivityManager.PROCESS_STATE_UNKNOWN,
- null
- )
+ context.opPackageName
+ )
+ } 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. */
@@ -295,7 +310,7 @@
swipeStatusBarAwayGestureHandler.ifPresent { it.removeOnGestureDetectedCallback(TAG) }
} else {
swipeStatusBarAwayGestureHandler.ifPresent {
- it.addOnGestureDetectedCallback(TAG, this::onSwipeAwayGestureDetected)
+ it.addOnGestureDetectedCallback(TAG) { _ -> onSwipeAwayGestureDetected() }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index f4e53e2..d1c9b3f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -76,14 +76,11 @@
import com.android.systemui.qs.QSUserSwitcherEvent;
import com.android.systemui.qs.user.UserSwitchDialogController.DialogShower;
import com.android.systemui.settings.UserTracker;
-import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.telephony.TelephonyListenerManager;
import com.android.systemui.user.CreateUserActivity;
import com.android.systemui.util.settings.SecureSettings;
-import dagger.Lazy;
-
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
@@ -129,7 +126,6 @@
private final InteractionJankMonitor mInteractionJankMonitor;
private final LatencyTracker mLatencyTracker;
private final DialogLaunchAnimator mDialogLaunchAnimator;
- private final Lazy<ShadeController> mShadeController;
private ArrayList<UserRecord> mUsers = new ArrayList<>();
@VisibleForTesting
@@ -178,7 +174,6 @@
InteractionJankMonitor interactionJankMonitor,
LatencyTracker latencyTracker,
DumpManager dumpManager,
- Lazy<ShadeController> shadeController,
DialogLaunchAnimator dialogLaunchAnimator) {
mContext = context;
mActivityManager = activityManager;
@@ -207,7 +202,6 @@
mActivityStarter = activityStarter;
mUserManager = userManager;
mDialogLaunchAnimator = dialogLaunchAnimator;
- mShadeController = shadeController;
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_USER_ADDED);
@@ -1206,8 +1200,12 @@
if (ActivityManager.isUserAMonkey()) {
return;
}
- mShadeController.get().collapsePanel();
- getContext().startActivity(CreateUserActivity.createIntentForStart(getContext()));
+ // Use broadcast instead of ShadeController, as this dialog may have started in
+ // another process and normal dagger bindings are not available
+ getContext().sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
+ getContext().startActivityAsUser(
+ CreateUserActivity.createIntentForStart(getContext()),
+ mUserTracker.getUserHandle());
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java
index 6f587fd..c53d510 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java
@@ -68,6 +68,7 @@
private final StatusBarContentInsetsProvider mContentInsetsProvider;
private int mBarHeight = -1;
private final State mCurrentState = new State();
+ private boolean mIsAttached;
private final ViewGroup mStatusBarWindowView;
// The container in which we should run launch animations started from the status bar and
@@ -136,6 +137,8 @@
mContentInsetsProvider.addCallback(this::calculateStatusBarLocationsForAllRotations);
calculateStatusBarLocationsForAllRotations();
+ mIsAttached = true;
+ apply(mCurrentState);
}
/** Adds the given view to the status bar window view. */
@@ -282,6 +285,9 @@
}
private void apply(State state) {
+ if (!mIsAttached) {
+ return;
+ }
applyForceStatusBarVisibleFlag(state);
applyHeight(state);
if (mLp != null && mLp.copyFrom(mLpChanged) != 0) {
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 3a14914..60f6df6 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 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 @@
}
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/touch/TouchInsetManager.java b/packages/SystemUI/src/com/android/systemui/touch/TouchInsetManager.java
new file mode 100644
index 0000000..de4e1e2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/touch/TouchInsetManager.java
@@ -0,0 +1,181 @@
+/*
+ * 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.touch;
+
+import android.graphics.Rect;
+import android.graphics.Region;
+import android.view.View;
+import android.view.ViewRootImpl;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.concurrent.Executor;
+
+/**
+ * {@link TouchInsetManager} handles setting the touchable inset regions for a given View. This
+ * is useful for passing through touch events for all but select areas.
+ */
+public class TouchInsetManager {
+ /**
+ * {@link TouchInsetSession} provides an individualized session with the
+ * {@link TouchInsetManager}, linking any action to the client.
+ */
+ public static class TouchInsetSession {
+ private final TouchInsetManager mManager;
+
+ private final HashSet<View> mTrackedViews;
+ private final Executor mExecutor;
+
+ private final View.OnLayoutChangeListener mOnLayoutChangeListener =
+ (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom)
+ -> updateTouchRegion();
+
+ /**
+ * Default constructor
+ * @param manager The parent {@link TouchInsetManager} which will be affected by actions on
+ * this session.
+ * @param rootView The parent of views that will be tracked.
+ * @param executor An executor for marshalling operations.
+ */
+ TouchInsetSession(TouchInsetManager manager, Executor executor) {
+ mManager = manager;
+ mTrackedViews = new HashSet<>();
+ mExecutor = executor;
+ }
+
+ /**
+ * Adds a descendant of the root view to be tracked.
+ * @param view {@link View} to be tracked.
+ */
+ public void addViewToTracking(View view) {
+ mExecutor.execute(() -> {
+ mTrackedViews.add(view);
+ view.addOnLayoutChangeListener(mOnLayoutChangeListener);
+ updateTouchRegion();
+ });
+ }
+
+ /**
+ * Removes a view from further tracking
+ * @param view {@link View} to be removed.
+ */
+ public void removeViewFromTracking(View view) {
+ mExecutor.execute(() -> {
+ mTrackedViews.remove(view);
+ view.removeOnLayoutChangeListener(mOnLayoutChangeListener);
+ updateTouchRegion();
+ });
+ }
+
+ private void updateTouchRegion() {
+ final Region cumulativeRegion = Region.obtain();
+
+ mTrackedViews.stream().forEach(view -> {
+ final Rect boundaries = new Rect();
+ view.getBoundsOnScreen(boundaries);
+ cumulativeRegion.op(boundaries, Region.Op.UNION);
+ });
+
+ mManager.setTouchRegion(this, cumulativeRegion);
+
+ cumulativeRegion.recycle();
+ }
+
+ /**
+ * Removes all tracked views and updates insets accordingly.
+ */
+ public void clear() {
+ mExecutor.execute(() -> {
+ mManager.clearRegion(this);
+ mTrackedViews.clear();
+ });
+ }
+ }
+
+ private final HashMap<TouchInsetSession, Region> mDefinedRegions = new HashMap<>();
+ private final Executor mExecutor;
+ private final View mRootView;
+
+ private final View.OnAttachStateChangeListener mAttachListener =
+ new View.OnAttachStateChangeListener() {
+ @Override
+ public void onViewAttachedToWindow(View v) {
+ updateTouchInset();
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+ }
+ };
+
+ /**
+ * Default constructor.
+ * @param executor An {@link Executor} to marshal all operations on.
+ * @param rootView The root {@link View} for all views in sessions.
+ */
+ public TouchInsetManager(Executor executor, View rootView) {
+ mExecutor = executor;
+ mRootView = rootView;
+ mRootView.addOnAttachStateChangeListener(mAttachListener);
+
+ }
+
+ /**
+ * Creates a new associated session.
+ */
+ public TouchInsetSession createSession() {
+ return new TouchInsetSession(this, mExecutor);
+ }
+
+ private void updateTouchInset() {
+ final ViewRootImpl viewRootImpl = mRootView.getViewRootImpl();
+
+ if (viewRootImpl == null) {
+ return;
+ }
+
+ final Region aggregateRegion = Region.obtain();
+
+ for (Region region : mDefinedRegions.values()) {
+ aggregateRegion.op(region, Region.Op.UNION);
+ }
+
+ viewRootImpl.setTouchableRegion(aggregateRegion);
+
+ aggregateRegion.recycle();
+ }
+
+ protected void setTouchRegion(TouchInsetSession session, Region region) {
+ final Region introducedRegion = Region.obtain(region);
+ mExecutor.execute(() -> {
+ mDefinedRegions.put(session, introducedRegion);
+ updateTouchInset();
+ });
+ }
+
+ private void clearRegion(TouchInsetSession session) {
+ mExecutor.execute(() -> {
+ final Region storedRegion = mDefinedRegions.remove(session);
+
+ if (storedRegion != null) {
+ storedRegion.recycle();
+ }
+
+ updateTouchInset();
+ });
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt b/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt
index e2374ad..d6dfcea 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.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 @@
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 @@
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 @@
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 @@
override fun onStartedWakingUp() {
if (isAnimationPlaying) {
handler.removeCallbacks(startAnimationRunnable)
- statusBar.notificationPanelViewController.cancelFoldToAodAnimation()
+ mCentralSurfaces.notificationPanelViewController.cancelFoldToAodAnimation()
}
setAnimationState(playing = false)
@@ -131,12 +131,14 @@
// 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/user/UserSwitcherActivity.kt b/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt
index 14585fb..c0d7925 100644
--- a/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt
@@ -35,9 +35,8 @@
import android.widget.ArrayAdapter
import android.widget.ImageView
import android.widget.TextView
-
import androidx.constraintlayout.helper.widget.Flow
-
+import com.android.internal.annotations.VisibleForTesting
import com.android.internal.util.UserIcons
import com.android.settingslib.Utils
import com.android.systemui.R
@@ -47,12 +46,12 @@
import com.android.systemui.statusbar.phone.ShadeController
import com.android.systemui.statusbar.policy.UserSwitcherController
import com.android.systemui.statusbar.policy.UserSwitcherController.BaseUserAdapter
-import com.android.systemui.statusbar.policy.UserSwitcherController.UserRecord
import com.android.systemui.statusbar.policy.UserSwitcherController.USER_SWITCH_DISABLED_ALPHA
import com.android.systemui.statusbar.policy.UserSwitcherController.USER_SWITCH_ENABLED_ALPHA
+import com.android.systemui.statusbar.policy.UserSwitcherController.UserRecord
import com.android.systemui.util.LifecycleActivity
-
import javax.inject.Inject
+import kotlin.math.ceil
private const val USER_VIEW = "user_view"
@@ -137,6 +136,18 @@
return UserIcons.getDefaultUserIcon(resources, item.info.id, false)
}
+ fun getTotalUserViews(): Int {
+ return users.count { item ->
+ !doNotRenderUserView(item)
+ }
+ }
+
+ fun doNotRenderUserView(item: UserRecord): Boolean {
+ return item.isAddUser ||
+ item.isAddSupervisedUser ||
+ item.isGuest && item.info == null
+ }
+
private fun getDrawable(item: UserRecord): Drawable {
var drawable = if (item.isCurrent && item.isGuest) {
getDrawable(R.drawable.ic_avatar_guest_user)
@@ -211,7 +222,8 @@
userSwitcherController.init(parent)
initBroadcastReceiver()
- buildUserViews()
+
+ parent.post { buildUserViews() }
}
private fun showPopupMenu() {
@@ -272,16 +284,32 @@
}
parent.removeViews(start, count)
addUserRecords.clear()
-
val flow = requireViewById<Flow>(R.id.flow)
+ val totalWidth = parent.width
+ val userViewCount = adapter.getTotalUserViews()
+ val maxColumns = getMaxColumns(userViewCount)
+ val horizontalGap = resources
+ .getDimensionPixelSize(R.dimen.user_switcher_fullscreen_horizontal_gap)
+ val totalWidthOfHorizontalGap = (maxColumns - 1) * horizontalGap
+ val maxWidgetDiameter = (totalWidth - totalWidthOfHorizontalGap) / maxColumns
+
+ flow.setMaxElementsWrap(maxColumns)
+
for (i in 0 until adapter.getCount()) {
val item = adapter.getItem(i)
- if (item.isAddUser ||
- item.isAddSupervisedUser ||
- item.isGuest && item.info == null) {
+ if (adapter.doNotRenderUserView(item)) {
addUserRecords.add(item)
} else {
val userView = adapter.getView(i, null, parent)
+ userView.requireViewById<ImageView>(R.id.user_switcher_icon).apply {
+ val lp = layoutParams
+ if (maxWidgetDiameter < lp.width) {
+ lp.width = maxWidgetDiameter
+ lp.height = maxWidgetDiameter
+ layoutParams = lp
+ }
+ }
+
userView.setId(View.generateViewId())
parent.addView(userView)
@@ -333,6 +361,11 @@
broadcastDispatcher.registerReceiver(broadcastReceiver, filter)
}
+ @VisibleForTesting
+ fun getMaxColumns(userCount: Int): Int {
+ return if (userCount < 5) 4 else ceil(userCount / 2.0).toInt()
+ }
+
private class ItemAdapter(
val parentContext: Context,
val resource: Int,
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 0000000..613a797
--- /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/src/com/android/systemui/volume/CaptionsToggleImageButton.java b/packages/SystemUI/src/com/android/systemui/volume/CaptionsToggleImageButton.java
index 1862ed3..ae23ca6 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/CaptionsToggleImageButton.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/CaptionsToggleImageButton.java
@@ -28,14 +28,11 @@
import com.android.keyguard.AlphaOptimizedImageButton;
import com.android.systemui.R;
-/** Toggle button in Volume Dialog that allows extra state for when streams are opted-out */
+/** Toggle button in Volume Dialog for controlling system captions state */
public class CaptionsToggleImageButton extends AlphaOptimizedImageButton {
- private static final int[] OPTED_OUT_STATE = new int[] { R.attr.optedOut };
-
private ConfirmedTapListener mConfirmedTapListener;
private boolean mCaptionsEnabled = false;
- private boolean mOptedOut = false;
private GestureDetector mGestureDetector;
private GestureDetector.SimpleOnGestureListener mGestureListener =
@@ -60,11 +57,7 @@
@Override
public int[] onCreateDrawableState(int extraSpace) {
- int[] state = super.onCreateDrawableState(extraSpace + 1);
- if (mOptedOut) {
- mergeDrawableStates(state, OPTED_OUT_STATE);
- }
- return state;
+ return super.onCreateDrawableState(extraSpace + 1);
}
Runnable setCaptionsEnabled(boolean areCaptionsEnabled) {
@@ -95,16 +88,6 @@
return this.mCaptionsEnabled;
}
- /** Sets whether or not the current stream has opted out of captions */
- void setOptedOut(boolean isOptedOut) {
- this.mOptedOut = isOptedOut;
- refreshDrawableState();
- }
-
- boolean getOptedOut() {
- return this.mOptedOut;
- }
-
void setOnConfirmedTapListener(ConfirmedTapListener listener, Handler handler) {
mConfirmedTapListener = listener;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index 57c7f11..97e03a6 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -54,6 +54,7 @@
import android.util.Log;
import android.util.Slog;
import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.CaptioningManager;
import androidx.lifecycle.Observer;
@@ -130,6 +131,7 @@
private final Receiver mReceiver = new Receiver();
private final RingerModeObservers mRingerModeObservers;
private final MediaSessions mMediaSessions;
+ private final CaptioningManager mCaptioningManager;
protected C mCallbacks = new C();
private final State mState = new State();
protected final MediaSessionsCallbacks mMediaSessionsCallbacksW;
@@ -175,7 +177,8 @@
IAudioService iAudioService,
AccessibilityManager accessibilityManager,
PackageManager packageManager,
- WakefulnessLifecycle wakefulnessLifecycle) {
+ WakefulnessLifecycle wakefulnessLifecycle,
+ CaptioningManager captioningManager) {
mContext = context.getApplicationContext();
mPackageManager = packageManager;
mWakefulnessLifecycle = wakefulnessLifecycle;
@@ -200,6 +203,7 @@
mVibrator = vibrator;
mHasVibrator = mVibrator.hasVibrator();
mAudioService = iAudioService;
+ mCaptioningManager = captioningManager;
boolean accessibilityVolumeStreamActive = accessibilityManager
.isAccessibilityVolumeStreamActive();
@@ -307,20 +311,11 @@
}
public boolean areCaptionsEnabled() {
- int currentValue = Settings.Secure.getIntForUser(mContext.getContentResolver(),
- Settings.Secure.ODI_CAPTIONS_ENABLED, 0, UserHandle.USER_CURRENT);
- return currentValue == 1;
+ return mCaptioningManager.isSystemAudioCaptioningEnabled();
}
public void setCaptionsEnabled(boolean isEnabled) {
- Settings.Secure.putIntForUser(mContext.getContentResolver(),
- Settings.Secure.ODI_CAPTIONS_ENABLED, isEnabled ? 1 : 0, UserHandle.USER_CURRENT);
- }
-
- @Override
- public boolean isCaptionStreamOptedOut() {
- // TODO(b/129768185): Removing secure setting, to be replaced by sound event listener
- return false;
+ mCaptioningManager.setSystemAudioCaptioningEnabled(isEnabled);
}
public void getCaptionsComponentState(boolean fromTooltip) {
@@ -423,6 +418,13 @@
}
private void onGetCaptionsComponentStateW(boolean fromTooltip) {
+ if (mCaptioningManager.isSystemAudioCaptioningUiEnabled()) {
+ mCallbacks.onCaptionComponentStateChanged(true, fromTooltip);
+ return;
+ }
+
+ // TODO(b/220968335): Remove this check once system captions component migrates
+ // to new CaptioningManager APIs.
try {
String componentNameString = mContext.getString(
com.android.internal.R.string.config_defaultSystemCaptionsService);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 58f74a0..bfdcbd6 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -1180,11 +1180,6 @@
if (mODICaptionsIcon.getCaptionsEnabled() != captionsEnabled) {
mHandler.post(mODICaptionsIcon.setCaptionsEnabled(captionsEnabled));
}
-
- boolean isOptedOut = mController.isCaptionStreamOptedOut();
- if (mODICaptionsIcon.getOptedOut() != isOptedOut) {
- mHandler.post(() -> mODICaptionsIcon.setOptedOut(isOptedOut));
- }
}
private void onCaptionIconClicked() {
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index 6fefce2..c3c3f90 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -21,7 +21,7 @@
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_GLOBAL_ACTIONS_SHOWING;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DIALOG_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_ONE_HANDED_ACTIVE;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
@@ -58,7 +58,6 @@
import com.android.wm.shell.compatui.CompatUI;
import com.android.wm.shell.draganddrop.DragAndDrop;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.nano.WmShellTraceProto;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.onehanded.OneHandedEventCallback;
@@ -97,7 +96,7 @@
implements CommandQueue.Callbacks, ProtoTraceable<SystemUiTraceProto> {
private static final String TAG = WMShell.class.getName();
private static final int INVALID_SYSUI_STATE_MASK =
- SYSUI_STATE_GLOBAL_ACTIONS_SHOWING
+ SYSUI_STATE_DIALOG_SHOWING
| SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING
| SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED
| SYSUI_STATE_BOUNCER_SHOWING
@@ -108,7 +107,6 @@
// Shell interfaces
private final Optional<Pip> mPipOptional;
- private final Optional<LegacySplitScreen> mLegacySplitScreenOptional;
private final Optional<SplitScreen> mSplitScreenOptional;
private final Optional<OneHanded> mOneHandedOptional;
private final Optional<HideDisplayCutout> mHideDisplayCutoutOptional;
@@ -128,7 +126,6 @@
private final Executor mSysUiMainExecutor;
private boolean mIsSysUiStateValid;
- private KeyguardUpdateMonitorCallback mLegacySplitScreenKeyguardCallback;
private KeyguardUpdateMonitorCallback mSplitScreenKeyguardCallback;
private KeyguardUpdateMonitorCallback mPipKeyguardCallback;
private KeyguardUpdateMonitorCallback mOneHandedKeyguardCallback;
@@ -138,7 +135,6 @@
@Inject
public WMShell(Context context,
Optional<Pip> pipOptional,
- Optional<LegacySplitScreen> legacySplitScreenOptional,
Optional<SplitScreen> splitScreenOptional,
Optional<OneHanded> oneHandedOptional,
Optional<HideDisplayCutout> hideDisplayCutoutOptional,
@@ -163,7 +159,6 @@
mScreenLifecycle = screenLifecycle;
mSysUiState = sysUiState;
mPipOptional = pipOptional;
- mLegacySplitScreenOptional = legacySplitScreenOptional;
mSplitScreenOptional = splitScreenOptional;
mOneHandedOptional = oneHandedOptional;
mHideDisplayCutoutOptional = hideDisplayCutoutOptional;
@@ -183,7 +178,6 @@
mProtoTracer.add(this);
mCommandQueue.addCallback(this);
mPipOptional.ifPresent(this::initPip);
- mLegacySplitScreenOptional.ifPresent(this::initLegacySplitScreen);
mSplitScreenOptional.ifPresent(this::initSplitScreen);
mOneHandedOptional.ifPresent(this::initOneHanded);
mHideDisplayCutoutOptional.ifPresent(this::initHideDisplayCutout);
@@ -238,21 +232,6 @@
}
@VisibleForTesting
- void initLegacySplitScreen(LegacySplitScreen legacySplitScreen) {
- mLegacySplitScreenKeyguardCallback = new KeyguardUpdateMonitorCallback() {
- @Override
- public void onKeyguardVisibilityChanged(boolean showing) {
- // Hide the divider when keyguard is showing. Even though keyguard/statusbar is
- // above everything, it is actually transparent except for notifications, so
- // we still need to hide any surfaces that are below it.
- // TODO(b/148906453): Figure out keyguard dismiss animation for divider view.
- legacySplitScreen.onKeyguardVisibilityChanged(showing);
- }
- };
- mKeyguardUpdateMonitor.registerCallback(mLegacySplitScreenKeyguardCallback);
- }
-
- @VisibleForTesting
void initSplitScreen(SplitScreen splitScreen) {
mSplitScreenKeyguardCallback = new KeyguardUpdateMonitorCallback() {
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorHwcLayerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorHwcLayerTest.kt
new file mode 100644
index 0000000..95aa08d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorHwcLayerTest.kt
@@ -0,0 +1,182 @@
+/*
+ * 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
+
+import android.graphics.Insets
+import android.graphics.PixelFormat
+import android.graphics.Rect
+import android.graphics.RectF
+import android.hardware.graphics.common.DisplayDecorationSupport
+import android.testing.AndroidTestingRunner
+import android.view.Display
+import android.view.DisplayCutout
+import android.view.DisplayInfo
+import android.view.View
+import androidx.test.filters.SmallTest
+import com.android.internal.R
+import com.android.systemui.util.mockito.eq
+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.Mockito
+import org.mockito.MockitoAnnotations
+import org.mockito.Mockito.`when` as whenever
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class ScreenDecorHwcLayerTest : SysuiTestCase() {
+
+ @Mock private lateinit var mockDisplay: Display
+ @Mock private lateinit var mockRootView: View
+
+ private val displayWidth = 100
+ private val displayHeight = 200
+ private val cutoutSize = 10
+ private val roundedSizeTop = 15
+ private val roundedSizeBottom = 20
+
+ private lateinit var decorHwcLayer: ScreenDecorHwcLayer
+ private val cutoutTop: DisplayCutout = DisplayCutout.Builder()
+ .setSafeInsets(Insets.of(0, cutoutSize, 0, 0))
+ .setBoundingRectTop(Rect(1, 0, 2, cutoutSize))
+ .build()
+
+ private val cutoutRight: DisplayCutout = DisplayCutout.Builder()
+ .setSafeInsets(Insets.of(0, 0, cutoutSize, 0))
+ .setBoundingRectRight(Rect(displayWidth - cutoutSize, 50, displayWidth, 52))
+ .build()
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ mContext.orCreateTestableResources.addOverride(
+ R.array.config_displayUniqueIdArray, arrayOf<String>())
+ mContext.orCreateTestableResources.addOverride(
+ R.bool.config_fillMainBuiltInDisplayCutout, true)
+
+ val decorationSupport = DisplayDecorationSupport()
+ decorationSupport.format = PixelFormat.R_8
+ decorHwcLayer = Mockito.spy(ScreenDecorHwcLayer(mContext, decorationSupport))
+ whenever(decorHwcLayer.width).thenReturn(displayWidth)
+ whenever(decorHwcLayer.height).thenReturn(displayHeight)
+ whenever(decorHwcLayer.display).thenReturn(mockDisplay)
+ whenever(decorHwcLayer.rootView).thenReturn(mockRootView)
+ whenever(mockRootView.left).thenReturn(0)
+ whenever(mockRootView.top).thenReturn(0)
+ whenever(mockRootView.right).thenReturn(displayWidth)
+ whenever(mockRootView.bottom).thenReturn(displayHeight)
+ }
+
+ @Test
+ fun testTransparentRegion_noCutout_noRoundedCorner_noProtection() {
+ setupConfigs(null, 0, 0, RectF(), 0f)
+
+ decorHwcLayer.calculateTransparentRect()
+
+ assertThat(decorHwcLayer.transparentRect)
+ .isEqualTo(Rect(0, 0, decorHwcLayer.width, decorHwcLayer.height))
+ }
+
+ @Test
+ fun testTransparentRegion_onlyShortEdgeCutout() {
+ setupConfigs(cutoutTop, 0, 0, RectF(), 0f)
+
+ decorHwcLayer.calculateTransparentRect()
+
+ assertThat(decorHwcLayer.transparentRect)
+ .isEqualTo(Rect(0, cutoutSize, decorHwcLayer.width, decorHwcLayer.height))
+ }
+
+ @Test
+ fun testTransparentRegion_onlyLongEdgeCutout() {
+ setupConfigs(cutoutRight, 0, 0, RectF(), 0f)
+
+ decorHwcLayer.calculateTransparentRect()
+
+ assertThat(decorHwcLayer.transparentRect)
+ .isEqualTo(Rect(0, 0, decorHwcLayer.width - cutoutSize, decorHwcLayer.height))
+ }
+
+ @Test
+ fun testTransparentRegion_onlyRoundedCorners() {
+ setupConfigs(null, roundedSizeTop, roundedSizeBottom, RectF(), 0f)
+
+ decorHwcLayer.calculateTransparentRect()
+
+ assertThat(decorHwcLayer.transparentRect)
+ .isEqualTo(Rect(0, roundedSizeTop, decorHwcLayer.width,
+ decorHwcLayer.height - roundedSizeBottom))
+ }
+
+ @Test
+ fun testTransparentRegion_onlyCutoutProtection() {
+ setupConfigs(null, 0, 0, RectF(48f, 1f, 52f, 5f), 0.5f)
+
+ decorHwcLayer.calculateTransparentRect()
+
+ assertThat(decorHwcLayer.transparentRect)
+ .isEqualTo(Rect(0, 4, decorHwcLayer.width, decorHwcLayer.height))
+
+ decorHwcLayer.cameraProtectionProgress = 1f
+
+ decorHwcLayer.calculateTransparentRect()
+
+ assertThat(decorHwcLayer.transparentRect)
+ .isEqualTo(Rect(0, 5, decorHwcLayer.width, decorHwcLayer.height))
+ }
+
+ @Test
+ fun testTransparentRegion_hasShortEdgeCutout_hasRoundedCorner_hasCutoutProtection() {
+ setupConfigs(cutoutTop, roundedSizeTop, roundedSizeBottom, RectF(48f, 1f, 52f, 5f), 1f)
+
+ decorHwcLayer.calculateTransparentRect()
+
+ assertThat(decorHwcLayer.transparentRect)
+ .isEqualTo(Rect(0, 15, decorHwcLayer.width, decorHwcLayer.height - 20))
+ }
+
+ @Test
+ fun testTransparentRegion_hasLongEdgeCutout_hasRoundedCorner_hasCutoutProtection() {
+ setupConfigs(cutoutRight, roundedSizeTop, roundedSizeBottom, RectF(48f, 1f, 52f, 5f), 1f)
+
+ decorHwcLayer.calculateTransparentRect()
+
+ assertThat(decorHwcLayer.transparentRect)
+ .isEqualTo(Rect(20, 5, decorHwcLayer.width - 20, decorHwcLayer.height))
+ }
+
+ private fun setupConfigs(
+ cutout: DisplayCutout?,
+ roundedTop: Int,
+ roundedBottom: Int,
+ protectionRect: RectF,
+ protectionProgress: Float
+ ) {
+ whenever(mockDisplay.getDisplayInfo(eq(decorHwcLayer.displayInfo))
+ ).then {
+ val info = it.getArgument<DisplayInfo>(0)
+ info.displayCutout = cutout
+ return@then true
+ }
+ decorHwcLayer.updateRoundedCornerSize(roundedTop, roundedBottom)
+ decorHwcLayer.protectionRect.set(protectionRect)
+ decorHwcLayer.cameraProtectionProgress = protectionProgress
+ decorHwcLayer.updateCutout()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
index 40632a8..7a0db1f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
@@ -42,6 +42,7 @@
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.SmartReplyController;
+import com.android.systemui.statusbar.phone.SystemUIDialogManager;
import org.junit.After;
import org.junit.AfterClass;
@@ -112,6 +113,11 @@
// KeyguardUpdateMonitor to be created (injected).
// TODO(b/1531701009) Clean up NotificationContentView creation to prevent this
mDependency.injectMockDependency(SmartReplyController.class);
+
+ // Make sure that all tests on any SystemUIDialog does not crash because this dependency
+ // is missing (constructing the actual one would throw).
+ // TODO(b/219008720): Remove this.
+ mDependency.injectMockDependency(SystemUIDialogManager.class);
}
@After
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
index 1dd5e22..6e5926d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -88,6 +88,7 @@
import org.mockito.MockitoAnnotations;
import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
@LargeTest
@TestableLooper.RunWithLooper
@@ -345,15 +346,17 @@
@Test
public void onOrientationChanged_disabled_updateDisplayRotation() {
- final Display display = Mockito.spy(mContext.getDisplay());
- when(display.getRotation()).thenReturn(Surface.ROTATION_90);
- when(mContext.getDisplay()).thenReturn(display);
+ final Rect windowBounds = new Rect(mWindowManager.getCurrentWindowMetrics().getBounds());
+ // Rotate the window clockwise 90 degree.
+ windowBounds.set(windowBounds.top, windowBounds.left, windowBounds.bottom,
+ windowBounds.right);
+ mWindowManager.setWindowBounds(windowBounds);
+ final int newRotation = simulateRotateTheDevice();
- mInstrumentation.runOnMainSync(() -> {
- mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_ORIENTATION);
- });
+ mInstrumentation.runOnMainSync(() -> mWindowMagnificationController.onConfigurationChanged(
+ ActivityInfo.CONFIG_ORIENTATION));
- assertEquals(Surface.ROTATION_90, mWindowMagnificationController.mRotation);
+ assertEquals(newRotation, mWindowMagnificationController.mRotation);
}
@Test
@@ -603,6 +606,113 @@
ReferenceTestUtils.waitForCondition(() -> hasMagnificationOverlapFlag());
}
+ @Test
+ public void setMinimumWindowSize_enabled_expectedWindowSize() {
+ final int minimumWindowSize = mResources.getDimensionPixelSize(
+ com.android.internal.R.dimen.accessibility_window_magnifier_min_size);
+ final int expectedWindowHeight = minimumWindowSize;
+ final int expectedWindowWidth = minimumWindowSize;
+ mInstrumentation.runOnMainSync(
+ () -> mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN,
+ Float.NaN, Float.NaN));
+
+ final AtomicInteger actualWindowHeight = new AtomicInteger();
+ final AtomicInteger actualWindowWidth = new AtomicInteger();
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationController.setWindowSize(expectedWindowWidth, expectedWindowHeight);
+ actualWindowHeight.set(mWindowManager.getLayoutParamsFromAttachedView().height);
+ actualWindowWidth.set(mWindowManager.getLayoutParamsFromAttachedView().width);
+
+ });
+
+ assertEquals(expectedWindowHeight, actualWindowHeight.get());
+ assertEquals(expectedWindowWidth, actualWindowWidth.get());
+ }
+
+ @Test
+ public void setMinimumWindowSizeThenEnable_expectedWindowSize() {
+ final int minimumWindowSize = mResources.getDimensionPixelSize(
+ com.android.internal.R.dimen.accessibility_window_magnifier_min_size);
+ final int expectedWindowHeight = minimumWindowSize;
+ final int expectedWindowWidth = minimumWindowSize;
+
+ final AtomicInteger actualWindowHeight = new AtomicInteger();
+ final AtomicInteger actualWindowWidth = new AtomicInteger();
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationController.setWindowSize(expectedWindowWidth, expectedWindowHeight);
+ mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN,
+ Float.NaN, Float.NaN);
+ actualWindowHeight.set(mWindowManager.getLayoutParamsFromAttachedView().height);
+ actualWindowWidth.set(mWindowManager.getLayoutParamsFromAttachedView().width);
+ });
+
+ assertEquals(expectedWindowHeight, actualWindowHeight.get());
+ assertEquals(expectedWindowWidth, actualWindowWidth.get());
+ }
+
+ @Test
+ public void setWindowSizeLessThanMin_enabled_minimumWindowSize() {
+ final int minimumWindowSize = mResources.getDimensionPixelSize(
+ com.android.internal.R.dimen.accessibility_window_magnifier_min_size);
+ mInstrumentation.runOnMainSync(
+ () -> mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN,
+ Float.NaN, Float.NaN));
+
+ final AtomicInteger actualWindowHeight = new AtomicInteger();
+ final AtomicInteger actualWindowWidth = new AtomicInteger();
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationController.setWindowSize(minimumWindowSize - 10,
+ minimumWindowSize - 10);
+ actualWindowHeight.set(mWindowManager.getLayoutParamsFromAttachedView().height);
+ actualWindowWidth.set(mWindowManager.getLayoutParamsFromAttachedView().width);
+ });
+
+ assertEquals(minimumWindowSize, actualWindowHeight.get());
+ assertEquals(minimumWindowSize, actualWindowWidth.get());
+ }
+
+ @Test
+ public void setWindowSizeLargerThanScreenSize_enabled_windowSizeIsScreenSize() {
+ final Rect bounds = mWindowManager.getCurrentWindowMetrics().getBounds();
+ mInstrumentation.runOnMainSync(
+ () -> mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN,
+ Float.NaN, Float.NaN));
+
+ final AtomicInteger actualWindowHeight = new AtomicInteger();
+ final AtomicInteger actualWindowWidth = new AtomicInteger();
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationController.setWindowSize(bounds.width() + 10, bounds.height() + 10);
+ actualWindowHeight.set(mWindowManager.getLayoutParamsFromAttachedView().height);
+ actualWindowWidth.set(mWindowManager.getLayoutParamsFromAttachedView().width);
+ });
+
+ assertEquals(bounds.height(), actualWindowHeight.get());
+ assertEquals(bounds.width(), actualWindowWidth.get());
+ }
+
+ @Test
+ public void setWindowCenterOutOfScreen_enabled_magnificationCenterIsInsideTheScreen() {
+
+ final int minimumWindowSize = mResources.getDimensionPixelSize(
+ com.android.internal.R.dimen.accessibility_window_magnifier_min_size);
+ final Rect bounds = mWindowManager.getCurrentWindowMetrics().getBounds();
+ mInstrumentation.runOnMainSync(
+ () -> mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN,
+ Float.NaN, Float.NaN));
+
+ final AtomicInteger magnificationCenterX = new AtomicInteger();
+ final AtomicInteger magnificationCenterY = new AtomicInteger();
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationController.setWindowSizeAndCenter(minimumWindowSize,
+ minimumWindowSize, bounds.right, bounds.bottom);
+ magnificationCenterX.set((int) mWindowMagnificationController.getCenterX());
+ magnificationCenterY.set((int) mWindowMagnificationController.getCenterY());
+ });
+
+ assertTrue(magnificationCenterX.get() < bounds.right);
+ assertTrue(magnificationCenterY.get() < bounds.bottom);
+ }
+
private CharSequence getAccessibilityWindowTitle() {
final View mirrorView = mWindowManager.getAttachedView();
if (mirrorView == null) {
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 5128ccc..ec2c1de 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.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 @@
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 @@
`when`(udfpsControllerProvider.get()).thenReturn(udfpsController)
controller = AuthRippleController(
- statusBar,
+ mCentralSurfaces,
context,
authController,
configurationController,
@@ -105,7 +105,7 @@
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 35e838b..1856fda 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.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 @@
@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 e9a4e15..7fb42b6 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 @@
mController.onViewAttached();
verify(mView, atLeast(1)).setPauseAuth(true);
- verify(mView).onDozeAmountChanged(dozeAmount, dozeAmount);
+ verify(mView).onDozeAmountChanged(dozeAmount, dozeAmount, true);
}
@Test
@@ -193,7 +193,7 @@
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/chooser/ChooserHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/chooser/ChooserHelperTest.java
deleted file mode 100644
index ecfb9ee..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/chooser/ChooserHelperTest.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2016 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.chooser;
-
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyBoolean;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.app.Activity;
-import android.app.ActivityTaskManager;
-import android.content.Intent;
-import android.os.Binder;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.systemui.SysuiTestCase;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class ChooserHelperTest extends SysuiTestCase {
-
- @Test
- public void testOnChoose_CallsStartActivityAsCallerWithToken() {
- final Intent intent = new Intent();
- final Binder token = new Binder();
- intent.putExtra(ActivityTaskManager.EXTRA_PERMISSION_TOKEN, token);
-
- final Activity mockActivity = mock(Activity.class);
- when(mockActivity.getIntent()).thenReturn(intent);
-
- ChooserHelper.onChoose(mockActivity);
- verify(mockActivity, times(1)).startActivityAsCaller(
- any(), any(), eq(token), anyBoolean(), anyInt());
- }
-}
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 9908d44..da25c62 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 @@
@SmallTest
@RunWith(AndroidTestingRunner::class)
class ControlActionCoordinatorImplTest : SysuiTestCase() {
-
@Mock
private lateinit var vibratorHelper: VibratorHelper
@Mock
@@ -61,6 +67,10 @@
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 @@
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 @@
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 5684429..3340f2f 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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 0000000..aa0a909
--- /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/DreamOverlayContainerViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
index 7af039b..d0e10fb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
@@ -17,9 +17,7 @@
package com.android.systemui.dreams;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -50,6 +48,7 @@
private static final int DREAM_OVERLAY_NOTIFICATIONS_DRAG_AREA_HEIGHT = 100;
private static final int MAX_BURN_IN_OFFSET = 20;
private static final long BURN_IN_PROTECTION_UPDATE_INTERVAL = 10;
+ private static final long MILLIS_UNTIL_FULL_JITTER = 240 * 1000;
@Mock
Resources mResources;
@@ -101,7 +100,8 @@
mDreamOverlayStatusBarViewController,
mHandler,
MAX_BURN_IN_OFFSET,
- BURN_IN_PROTECTION_UPDATE_INTERVAL);
+ BURN_IN_PROTECTION_UPDATE_INTERVAL,
+ MILLIS_UNTIL_FULL_JITTER);
}
@Test
@@ -118,31 +118,6 @@
}
@Test
- public void testOnViewAttachedRegistersComputeInsetsListener() {
- mController.onViewAttached();
- verify(mViewTreeObserver).addOnComputeInternalInsetsListener(any());
- }
-
- @Test
- public void testOnViewDetachedUnregistersComputeInsetsListener() {
- mController.onViewDetached();
- verify(mViewTreeObserver).removeOnComputeInternalInsetsListener(any());
- }
-
- @Test
- public void testComputeInsetsListenerReturnsRegion() {
- final ArgumentCaptor<ViewTreeObserver.OnComputeInternalInsetsListener>
- computeInsetsListenerCapture =
- ArgumentCaptor.forClass(ViewTreeObserver.OnComputeInternalInsetsListener.class);
- mController.onViewAttached();
- verify(mViewTreeObserver).addOnComputeInternalInsetsListener(
- computeInsetsListenerCapture.capture());
- final ViewTreeObserver.InternalInsetsInfo info = new ViewTreeObserver.InternalInsetsInfo();
- computeInsetsListenerCapture.getValue().onComputeInternalInsets(info);
- assertNotNull(info.touchableRegion);
- }
-
- @Test
public void testBurnInProtectionStartsWhenContentViewAttached() {
mController.onViewAttached();
verify(mHandler).postDelayed(any(Runnable.class), eq(BURN_IN_PROTECTION_UPDATE_INTERVAL));
@@ -155,14 +130,14 @@
}
@Test
- public void testBurnInProtectionUpdatesPeriodically() {
+ public void testBurnInProtectionOffsetsStartAtZero() {
ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
mController.onViewAttached();
verify(mHandler).postDelayed(
runnableCaptor.capture(), eq(BURN_IN_PROTECTION_UPDATE_INTERVAL));
runnableCaptor.getValue().run();
- verify(mDreamOverlayContainerView).setTranslationX(anyFloat());
- verify(mDreamOverlayContainerView).setTranslationY(anyFloat());
+ verify(mDreamOverlayContainerView).setTranslationX(0.f);
+ verify(mDreamOverlayContainerView).setTranslationY(0.f);
}
@Test
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 58ffbfa..21768ed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
@@ -38,6 +38,7 @@
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dreams.complication.DreamPreviewComplication;
import com.android.systemui.dreams.dagger.DreamOverlayComponent;
import com.android.systemui.dreams.touch.DreamOverlayTouchMonitor;
import com.android.systemui.util.concurrency.FakeExecutor;
@@ -95,6 +96,9 @@
@Mock
DreamOverlayStateController mStateController;
+ @Mock
+ DreamPreviewComplication mPreviewComplication;
+
DreamOverlayService mService;
@Before
@@ -119,7 +123,8 @@
mService = new DreamOverlayService(mContext, mMainExecutor,
mDreamOverlayComponentFactory,
mStateController,
- mKeyguardUpdateMonitor);
+ mKeyguardUpdateMonitor,
+ mPreviewComplication);
}
@Test
@@ -163,6 +168,31 @@
}
@Test
+ public void testPreviewModeFalseByDefault() {
+ mService.onBind(new Intent());
+
+ assertThat(mService.isPreviewMode()).isFalse();
+ }
+
+ @Test
+ public void testPreviewModeSetByIntentExtra() {
+ final Intent intent = new Intent();
+ intent.putExtra(DreamService.EXTRA_IS_PREVIEW, true);
+ mService.onBind(intent);
+
+ assertThat(mService.isPreviewMode()).isTrue();
+ }
+
+ @Test
+ public void testDreamLabel() {
+ final Intent intent = new Intent();
+ intent.putExtra(DreamService.EXTRA_DREAM_LABEL, "TestDream");
+ mService.onBind(intent);
+
+ assertThat(mService.getDreamLabel()).isEqualTo("TestDream");
+ }
+
+ @Test
public void testDestroy() {
mService.onDestroy();
mMainExecutor.runAllReady();
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 515a1ac8..49da4bd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
@@ -61,7 +61,7 @@
}
@Test
- public void testStateChange() {
+ public void testStateChange_overlayActive() {
final DreamOverlayStateController stateController = new DreamOverlayStateController(
mExecutor);
stateController.addCallback(mCallback);
@@ -83,6 +83,38 @@
}
@Test
+ public void testStateChange_isPreviewMode() {
+ final DreamOverlayStateController stateController = new DreamOverlayStateController(
+ mExecutor);
+ stateController.addCallback(mCallback);
+ stateController.setPreviewMode(true);
+ mExecutor.runAllReady();
+
+ verify(mCallback).onStateChanged();
+ assertThat(stateController.isPreviewMode()).isTrue();
+
+ Mockito.clearInvocations(mCallback);
+ stateController.setPreviewMode(true);
+ mExecutor.runAllReady();
+ verify(mCallback, never()).onStateChanged();
+ }
+
+ @Test
+ public void testPreviewModeFalseByDefault() {
+ final DreamOverlayStateController stateController = new DreamOverlayStateController(
+ mExecutor);
+ assertThat(stateController.isPreviewMode()).isFalse();
+ }
+
+ @Test
+ public void testPreviewModeSetToTrue() {
+ final DreamOverlayStateController stateController = new DreamOverlayStateController(
+ mExecutor);
+ stateController.setPreviewMode(true);
+ assertThat(stateController.isPreviewMode()).isTrue();
+ }
+
+ @Test
public void testCallback() {
final DreamOverlayStateController stateController = new DreamOverlayStateController(
mExecutor);
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 7f72dda..a32ff80 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
@@ -17,20 +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.battery.BatteryMeterViewController;
-import com.android.systemui.statusbar.policy.BatteryController;
+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;
@@ -42,41 +56,68 @@
@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;
@Mock
- BatteryController mBatteryController;
- @Mock
- BatteryMeterViewController mBatteryMeterViewController;
- @Mock
ConnectivityManager mConnectivityManager;
@Mock
NetworkCapabilities mNetworkCapabilities;
@Mock
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);
+
+ when(mResources.getString(R.string.dream_overlay_status_bar_notification_indicator))
+ .thenReturn(NOTIFICATION_INDICATOR_FORMATTER_STRING);
+
mController = new DreamOverlayStatusBarViewController(
- mContext, mView, mBatteryController, mBatteryMeterViewController,
- mConnectivityManager);
+ mView,
+ mResources,
+ mConnectivityManager,
+ mTouchSession,
+ mAlarmManager,
+ mNextAlarmController,
+ mDateFormatUtil,
+ mSensorPrivacyController,
+ mNotificationListener,
+ mZenModeController);
}
@Test
- public void testOnInitInitializesControllers() {
- mController.onInit();
- verify(mBatteryMeterViewController).init();
- }
-
- @Test
- public void testOnViewAttachedAddsBatteryControllerCallback() {
+ public void testOnViewAttachedAddsCallbacks() {
mController.onViewAttached();
- verify(mBatteryController)
- .addCallback(any(BatteryController.BatteryStateChangeCallback.class));
+ verify(mNextAlarmController).addCallback(any());
+ verify(mSensorPrivacyController).addCallback(any());
+ verify(mZenModeController).addCallback(any());
}
@Test
@@ -88,35 +129,97 @@
}
@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 testOnViewDetachedRemovesBatteryControllerCallback() {
- mController.onViewDetached();
- verify(mBatteryController)
- .removeCallback(any(BatteryController.BatteryStateChangeCallback.class));
+ 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
@@ -127,30 +230,19 @@
}
@Test
- public void testBatteryPercentTextShownWhenBatteryLevelChangesWhileCharging() {
- final ArgumentCaptor<BatteryController.BatteryStateChangeCallback> callbackCapture =
- ArgumentCaptor.forClass(BatteryController.BatteryStateChangeCallback.class);
- mController.onViewAttached();
- verify(mBatteryController).addCallback(callbackCapture.capture());
- callbackCapture.getValue().onBatteryLevelChanged(1, true, true);
- verify(mView).showBatteryPercentText(true);
+ public void testOnViewDetachedRemovesCallbacks() {
+ mController.onViewDetached();
+ verify(mNextAlarmController).removeCallback(any());
+ verify(mSensorPrivacyController).removeCallback(any());
+ verify(mZenModeController).removeCallback(any());
}
@Test
- public void testBatteryPercentTextHiddenWhenBatteryLevelChangesWhileNotCharging() {
- final ArgumentCaptor<BatteryController.BatteryStateChangeCallback> callbackCapture =
- ArgumentCaptor.forClass(BatteryController.BatteryStateChangeCallback.class);
- mController.onViewAttached();
- verify(mBatteryController).addCallback(callbackCapture.capture());
- callbackCapture.getValue().onBatteryLevelChanged(1, true, false);
- verify(mView).showBatteryPercentText(false);
- }
-
- @Test
- public void testWifiStatusHiddenWhenWifiBecomesAvailable() {
- // Make sure wifi starts out unavailable when onViewAttached is called.
+ 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();
@@ -158,14 +250,15 @@
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();
@@ -173,11 +266,11 @@
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);
@@ -190,6 +283,102 @@
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/complication/ComplicationLayoutEngineTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationLayoutEngineTest.java
index 64b267d..51dcf2e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationLayoutEngineTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationLayoutEngineTest.java
@@ -29,6 +29,7 @@
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.touch.TouchInsetManager;
import org.junit.Before;
import org.junit.Test;
@@ -46,6 +47,9 @@
@Mock
ConstraintLayout mLayout;
+ @Mock
+ TouchInsetManager.TouchInsetSession mTouchSession;
+
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
@@ -112,7 +116,8 @@
Complication.CATEGORY_STANDARD,
mLayout);
- final ComplicationLayoutEngine engine = new ComplicationLayoutEngine(mLayout, 0);
+ final ComplicationLayoutEngine engine =
+ new ComplicationLayoutEngine(mLayout, 0, mTouchSession);
addComplication(engine, firstViewInfo);
// Ensure the view is added to the top end corner
@@ -139,7 +144,8 @@
Complication.CATEGORY_STANDARD,
mLayout);
- final ComplicationLayoutEngine engine = new ComplicationLayoutEngine(mLayout, 0);
+ final ComplicationLayoutEngine engine =
+ new ComplicationLayoutEngine(mLayout, 0, mTouchSession);
addComplication(engine, firstViewInfo);
// Ensure the view is added to the top end corner
@@ -155,7 +161,8 @@
*/
@Test
public void testDirectionLayout() {
- final ComplicationLayoutEngine engine = new ComplicationLayoutEngine(mLayout, 0);
+ final ComplicationLayoutEngine engine =
+ new ComplicationLayoutEngine(mLayout, 0, mTouchSession);
final ViewInfo firstViewInfo = new ViewInfo(
new ComplicationLayoutParams(
@@ -203,7 +210,8 @@
*/
@Test
public void testPositionLayout() {
- final ComplicationLayoutEngine engine = new ComplicationLayoutEngine(mLayout, 0);
+ final ComplicationLayoutEngine engine =
+ new ComplicationLayoutEngine(mLayout, 0, mTouchSession);
final ViewInfo firstViewInfo = new ViewInfo(
new ComplicationLayoutParams(
@@ -290,7 +298,8 @@
@Test
public void testMargin() {
final int margin = 5;
- final ComplicationLayoutEngine engine = new ComplicationLayoutEngine(mLayout, margin);
+ final ComplicationLayoutEngine engine =
+ new ComplicationLayoutEngine(mLayout, margin, mTouchSession);
final ViewInfo firstViewInfo = new ViewInfo(
new ComplicationLayoutParams(
@@ -364,7 +373,8 @@
*/
@Test
public void testRemoval() {
- final ComplicationLayoutEngine engine = new ComplicationLayoutEngine(mLayout, 0);
+ final ComplicationLayoutEngine engine =
+ new ComplicationLayoutEngine(mLayout, 0, mTouchSession);
final ViewInfo firstViewInfo = new ViewInfo(
new ComplicationLayoutParams(
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 cad98f4..6e01541 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 @@
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.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.Mockito;
import org.mockito.MockitoAnnotations;
-import java.util.Random;
-
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
@@ -60,7 +59,7 @@
StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@Mock
- StatusBar mStatusBar;
+ CentralSurfaces mCentralSurfaces;
@Mock
NotificationShadeWindowController mNotificationShadeWindowController;
@@ -89,38 +88,51 @@
@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 @@
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 @@
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 @@
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 74b217b..29f56e0 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 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 @@
}
@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/flags/FeatureFlagsDebugTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt
index 4cc5673..23a5b2b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt
@@ -20,7 +20,7 @@
import android.content.Intent
import android.content.pm.PackageManager.NameNotFoundException
import android.content.res.Resources
-import androidx.test.filters.SmallTest
+import android.test.suitebuilder.annotation.SmallTest
import com.android.internal.statusbar.IStatusBarService
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
@@ -35,6 +35,8 @@
import org.junit.Before
import org.junit.Test
import org.mockito.Mock
+import org.mockito.Mockito.anyBoolean
+import org.mockito.Mockito.anyString
import org.mockito.Mockito.inOrder
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
@@ -57,6 +59,7 @@
@Mock private lateinit var mFlagManager: FlagManager
@Mock private lateinit var mMockContext: Context
@Mock private lateinit var mSecureSettings: SecureSettings
+ @Mock private lateinit var mSystemProperties: SystemPropertiesHelper
@Mock private lateinit var mResources: Resources
@Mock private lateinit var mDumpManager: DumpManager
@Mock private lateinit var mBarService: IStatusBarService
@@ -71,12 +74,13 @@
mFlagManager,
mMockContext,
mSecureSettings,
+ mSystemProperties,
mResources,
mDumpManager,
{ mFlagMap },
mBarService
)
- verify(mFlagManager).restartAction = any()
+ verify(mFlagManager).onSettingsChangedAction = any()
mBroadcastReceiver = withArgCaptor {
verify(mMockContext).registerReceiver(capture(), any(), nullable(), nullable(),
any())
@@ -123,6 +127,22 @@
}
@Test
+ fun testReadSysPropBooleanFlag() {
+ whenever(mSystemProperties.getBoolean(anyString(), anyBoolean())).thenAnswer {
+ if ("b".equals(it.getArgument<String?>(0))) {
+ return@thenAnswer true
+ }
+ return@thenAnswer it.getArgument(1)
+ }
+
+ assertThat(mFeatureFlagsDebug.isEnabled(SysPropBooleanFlag(1, "a"))).isFalse()
+ assertThat(mFeatureFlagsDebug.isEnabled(SysPropBooleanFlag(2, "b"))).isTrue()
+ assertThat(mFeatureFlagsDebug.isEnabled(SysPropBooleanFlag(3, "c", true))).isTrue()
+ assertThat(mFeatureFlagsDebug.isEnabled(SysPropBooleanFlag(4, "d", false))).isFalse()
+ assertThat(mFeatureFlagsDebug.isEnabled(SysPropBooleanFlag(5, "e"))).isFalse()
+ }
+
+ @Test
fun testReadStringFlag() {
whenever(mFlagManager.readFlagValue<String>(eq(3), any())).thenReturn("foo")
whenever(mFlagManager.readFlagValue<String>(eq(4), any())).thenReturn("bar")
@@ -259,7 +279,7 @@
verify(mFlagManager, times(numReads)).readFlagValue(eq(id), any<FlagSerializer<*>>())
verify(mFlagManager).idToSettingsKey(eq(id))
verify(mSecureSettings).putString(eq("key-$id"), eq(data))
- verify(mFlagManager).dispatchListenersAndMaybeRestart(eq(id))
+ verify(mFlagManager).dispatchListenersAndMaybeRestart(eq(id), any())
}.verifyNoMoreInteractions()
verifyNoMoreInteractions(mFlagManager, mSecureSettings)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseTest.kt
index b5e6602..ad304c4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseTest.kt
@@ -17,7 +17,7 @@
import android.content.pm.PackageManager.NameNotFoundException
import android.content.res.Resources
-import androidx.test.filters.SmallTest
+import android.test.suitebuilder.annotation.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
import com.android.systemui.util.mockito.any
@@ -44,12 +44,13 @@
private lateinit var mFeatureFlagsRelease: FeatureFlagsRelease
@Mock private lateinit var mResources: Resources
+ @Mock private lateinit var mSystemProperties: SystemPropertiesHelper
@Mock private lateinit var mDumpManager: DumpManager
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
- mFeatureFlagsRelease = FeatureFlagsRelease(mResources, mDumpManager)
+ mFeatureFlagsRelease = FeatureFlagsRelease(mResources, mSystemProperties, mDumpManager)
}
@After
@@ -87,6 +88,17 @@
}
@Test
+ fun testSysPropBooleanFlag() {
+ val flagId = 213
+ val flagName = "sys_prop_flag"
+ val flagDefault = true
+
+ val flag = SysPropBooleanFlag(flagId, flagName, flagDefault)
+ whenever(mSystemProperties.getBoolean(flagName, flagDefault)).thenReturn(flagDefault)
+ assertThat(mFeatureFlagsRelease.isEnabled(flag)).isEqualTo(flagDefault)
+ }
+
+ @Test
fun testDump() {
val flag1 = BooleanFlag(1, true)
val flag2 = ResourceBooleanFlag(2, 1002)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FlagManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FlagManagerTest.kt
index 644bd21..a2eca81 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/FlagManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FlagManagerTest.kt
@@ -19,7 +19,7 @@
import android.database.ContentObserver
import android.net.Uri
import android.os.Handler
-import androidx.test.filters.SmallTest
+import android.test.suitebuilder.annotation.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
@@ -130,14 +130,14 @@
mFlagManager.addListener(BooleanFlag(1, true), listener1)
mFlagManager.addListener(BooleanFlag(10, true), listener10)
- mFlagManager.dispatchListenersAndMaybeRestart(1)
+ mFlagManager.dispatchListenersAndMaybeRestart(1, null)
val flagEvent1 = withArgCaptor<FlagListenable.FlagEvent> {
verify(listener1).onFlagChanged(capture())
}
assertThat(flagEvent1.flagId).isEqualTo(1)
verifyNoMoreInteractions(listener1, listener10)
- mFlagManager.dispatchListenersAndMaybeRestart(10)
+ mFlagManager.dispatchListenersAndMaybeRestart(10, null)
val flagEvent10 = withArgCaptor<FlagListenable.FlagEvent> {
verify(listener10).onFlagChanged(capture())
}
@@ -151,14 +151,14 @@
mFlagManager.addListener(BooleanFlag(1, true), listener)
mFlagManager.addListener(BooleanFlag(10, true), listener)
- mFlagManager.dispatchListenersAndMaybeRestart(1)
+ mFlagManager.dispatchListenersAndMaybeRestart(1, null)
val flagEvent1 = withArgCaptor<FlagListenable.FlagEvent> {
verify(listener).onFlagChanged(capture())
}
assertThat(flagEvent1.flagId).isEqualTo(1)
verifyNoMoreInteractions(listener)
- mFlagManager.dispatchListenersAndMaybeRestart(10)
+ mFlagManager.dispatchListenersAndMaybeRestart(10, null)
val flagEvent10 = withArgCaptor<FlagListenable.FlagEvent> {
verify(listener, times(2)).onFlagChanged(capture())
}
@@ -169,8 +169,7 @@
@Test
fun testRestartWithNoListeners() {
val restartAction = mock<Consumer<Boolean>>()
- mFlagManager.restartAction = restartAction
- mFlagManager.dispatchListenersAndMaybeRestart(1)
+ mFlagManager.dispatchListenersAndMaybeRestart(1, restartAction)
verify(restartAction).accept(eq(false))
verifyNoMoreInteractions(restartAction)
}
@@ -178,11 +177,10 @@
@Test
fun testListenerCanSuppressRestart() {
val restartAction = mock<Consumer<Boolean>>()
- mFlagManager.restartAction = restartAction
mFlagManager.addListener(BooleanFlag(1, true)) { event ->
event.requestNoRestart()
}
- mFlagManager.dispatchListenersAndMaybeRestart(1)
+ mFlagManager.dispatchListenersAndMaybeRestart(1, restartAction)
verify(restartAction).accept(eq(true))
verifyNoMoreInteractions(restartAction)
}
@@ -190,11 +188,10 @@
@Test
fun testListenerOnlySuppressesRestartForOwnFlag() {
val restartAction = mock<Consumer<Boolean>>()
- mFlagManager.restartAction = restartAction
mFlagManager.addListener(BooleanFlag(10, true)) { event ->
event.requestNoRestart()
}
- mFlagManager.dispatchListenersAndMaybeRestart(1)
+ mFlagManager.dispatchListenersAndMaybeRestart(1, restartAction)
verify(restartAction).accept(eq(false))
verifyNoMoreInteractions(restartAction)
}
@@ -202,14 +199,13 @@
@Test
fun testRestartWhenNotAllListenersRequestSuppress() {
val restartAction = mock<Consumer<Boolean>>()
- mFlagManager.restartAction = restartAction
mFlagManager.addListener(BooleanFlag(10, true)) { event ->
event.requestNoRestart()
}
mFlagManager.addListener(BooleanFlag(10, true)) {
// do not request
}
- mFlagManager.dispatchListenersAndMaybeRestart(1)
+ mFlagManager.dispatchListenersAndMaybeRestart(1, restartAction)
verify(restartAction).accept(eq(false))
verifyNoMoreInteractions(restartAction)
}
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 71fc8ee..6fead9e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
@@ -19,7 +19,6 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
@@ -57,13 +56,11 @@
import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.colorextraction.SysuiColorExtractor;
-import com.android.systemui.model.SysUiState;
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.SystemUIDialogManager;
+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;
@@ -112,15 +109,13 @@
@Mock private UiEventLogger mUiEventLogger;
@Mock private RingerModeTracker mRingerModeTracker;
@Mock private RingerModeLiveData mRingerModeLiveData;
- @Mock private SysUiState mSysUiState;
@Mock private PackageManager mPackageManager;
@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;
- @Mock private SystemUIDialogManager mDialogManager;
private TestableLooper mTestableLooper;
@@ -161,19 +156,16 @@
mBackgroundExecutor,
mUiEventLogger,
mRingerModeTracker,
- mSysUiState,
mHandler,
mPackageManager,
- Optional.of(mStatusBar),
+ Optional.of(mCentralSurfaces),
mKeyguardUpdateMonitor,
- mDialogLaunchAnimator,
- mDialogManager);
+ mDialogLaunchAnimator);
mGlobalActionsDialogLite.setZeroDialogPressDelayForTesting();
ColorExtractor.GradientColors backdropColors = new ColorExtractor.GradientColors();
backdropColors.setMainColor(Color.BLACK);
when(mColorExtractor.getNeutralColors()).thenReturn(backdropColors);
- when(mSysUiState.setFlag(anyInt(), anyBoolean())).thenReturn(mSysUiState);
}
@Test
@@ -235,7 +227,7 @@
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,
@@ -250,7 +242,7 @@
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
@@ -259,7 +251,7 @@
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,
@@ -274,7 +266,7 @@
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
@@ -440,7 +432,7 @@
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 e606be1..b359ae5 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.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.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 @@
@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 @@
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 @@
@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 @@
// 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()
- // 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 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)
+
+ val transformType = mediaHiearchyManager.calculateTransformationType()
+ 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 @@
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/dialog/MediaOutputBaseDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
index c5c4d79..2be30b3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
@@ -45,7 +45,6 @@
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.phone.ShadeController;
-import com.android.systemui.statusbar.phone.SystemUIDialogManager;
import org.junit.Before;
import org.junit.Test;
@@ -68,7 +67,6 @@
mock(NotificationEntryManager.class);
private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class);
private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class);
- private final SystemUIDialogManager mDialogManager = mock(SystemUIDialogManager.class);
private MediaOutputBaseDialogImpl mMediaOutputBaseDialogImpl;
private MediaOutputController mMediaOutputController;
@@ -82,7 +80,7 @@
public void setUp() {
mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE, false,
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator, mDialogManager);
+ mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator);
mMediaOutputBaseDialogImpl = new MediaOutputBaseDialogImpl(mContext,
mMediaOutputController);
mMediaOutputBaseDialogImpl.onCreate(new Bundle());
@@ -175,7 +173,7 @@
class MediaOutputBaseDialogImpl extends MediaOutputBaseDialog {
MediaOutputBaseDialogImpl(Context context, MediaOutputController mediaOutputController) {
- super(context, mediaOutputController, mDialogManager);
+ super(context, mediaOutputController);
mAdapter = mMediaOutputBaseAdapter;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
index bdc3117..789822e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
@@ -55,7 +55,6 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
import com.android.systemui.statusbar.phone.ShadeController;
-import com.android.systemui.statusbar.phone.SystemUIDialogManager;
import org.junit.Before;
import org.junit.Test;
@@ -94,7 +93,6 @@
private CommonNotifCollection mNotifCollection = mock(CommonNotifCollection.class);
private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class);
private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class);
- private final SystemUIDialogManager mDialogManager = mock(SystemUIDialogManager.class);
private Context mSpyContext;
private MediaOutputController mMediaOutputController;
@@ -117,7 +115,7 @@
mMediaOutputController = new MediaOutputController(mSpyContext, TEST_PACKAGE_NAME, false,
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotifCollection, mUiEventLogger, mDialogLaunchAnimator, mDialogManager);
+ mNotifCollection, mUiEventLogger, mDialogLaunchAnimator);
mLocalMediaManager = spy(mMediaOutputController.mLocalMediaManager);
mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
MediaDescription.Builder builder = new MediaDescription.Builder();
@@ -161,7 +159,7 @@
public void start_withoutPackageName_verifyMediaControllerInit() {
mMediaOutputController = new MediaOutputController(mSpyContext, null, false,
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotifCollection, mUiEventLogger, mDialogLaunchAnimator, mDialogManager);
+ mNotifCollection, mUiEventLogger, mDialogLaunchAnimator);
mMediaOutputController.start(mCb);
@@ -182,7 +180,7 @@
public void stop_withoutPackageName_verifyMediaControllerDeinit() {
mMediaOutputController = new MediaOutputController(mSpyContext, null, false,
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotifCollection, mUiEventLogger, mDialogLaunchAnimator, mDialogManager);
+ mNotifCollection, mUiEventLogger, mDialogLaunchAnimator);
mMediaOutputController.start(mCb);
@@ -453,7 +451,7 @@
public void getNotificationLargeIcon_withoutPackageName_returnsNull() {
mMediaOutputController = new MediaOutputController(mSpyContext, null, false,
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotifCollection, mUiEventLogger, mDialogLaunchAnimator, mDialogManager);
+ mNotifCollection, mUiEventLogger, mDialogLaunchAnimator);
assertThat(mMediaOutputController.getNotificationIcon()).isNull();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
index ada8d35..8a3ea56 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
@@ -40,7 +40,6 @@
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.phone.ShadeController;
-import com.android.systemui.statusbar.phone.SystemUIDialogManager;
import org.junit.After;
import org.junit.Before;
@@ -68,7 +67,6 @@
mock(NotificationEntryManager.class);
private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class);
private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class);
- private final SystemUIDialogManager mDialogManager = mock(SystemUIDialogManager.class);
private MediaOutputDialog mMediaOutputDialog;
private MediaOutputController mMediaOutputController;
@@ -78,10 +76,10 @@
public void setUp() {
mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE, false,
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator, mDialogManager);
+ mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator);
mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
mMediaOutputDialog = new MediaOutputDialog(mContext, false,
- mMediaOutputController, mUiEventLogger, mDialogManager);
+ mMediaOutputController, mUiEventLogger);
mMediaOutputDialog.show();
when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(mMediaDevice);
@@ -127,7 +125,7 @@
// and verify if the calling times increases.
public void onCreate_ShouldLogVisibility() {
MediaOutputDialog testDialog = new MediaOutputDialog(mContext, false,
- mMediaOutputController, mUiEventLogger, mDialogManager);
+ mMediaOutputController, mUiEventLogger);
testDialog.show();
testDialog.dismissDialog();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupDialogTest.java
index b114452..e8cd6c8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupDialogTest.java
@@ -38,7 +38,6 @@
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.phone.ShadeController;
-import com.android.systemui.statusbar.phone.SystemUIDialogManager;
import org.junit.After;
import org.junit.Before;
@@ -67,7 +66,6 @@
mock(NotificationEntryManager.class);
private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class);
private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class);
- private final SystemUIDialogManager mDialogManager = mock(SystemUIDialogManager.class);
private MediaOutputGroupDialog mMediaOutputGroupDialog;
private MediaOutputController mMediaOutputController;
@@ -77,10 +75,10 @@
public void setUp() {
mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE, false,
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator, mDialogManager);
+ mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator);
mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
mMediaOutputGroupDialog = new MediaOutputGroupDialog(mContext, false,
- mMediaOutputController, mDialogManager);
+ mMediaOutputController);
mMediaOutputGroupDialog.show();
when(mLocalMediaManager.getSelectedMediaDevice()).thenReturn(mMediaDevices);
}
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 ea0a5a4..809b890 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 @@
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
@@ -26,10 +27,14 @@
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
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.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
@@ -38,6 +43,7 @@
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
@@ -50,6 +56,10 @@
private lateinit var appIconDrawable: Drawable
@Mock
private lateinit var windowManager: WindowManager
+ @Mock
+ private lateinit var viewUtil: ViewUtil
+ @Mock
+ private lateinit var tapGestureDetector: TapGestureDetector
@Before
fun setUp() {
@@ -58,23 +68,28 @@
fakeClock = FakeSystemClock()
fakeExecutor = FakeExecutor(fakeClock)
- controllerCommon = TestControllerCommon(context, windowManager, fakeExecutor)
+ controllerCommon = TestControllerCommon(
+ context, windowManager, viewUtil, fakeExecutor, tapGestureDetector
+ )
}
@Test
- fun displayChip_chipAdded() {
+ fun displayChip_chipAddedAndGestureDetectionStarted() {
controllerCommon.displayChip(getState())
verify(windowManager).addView(any(), any())
+ verify(tapGestureDetector).addOnGestureDetectedCallback(any(), any())
}
@Test
- fun displayChip_twice_chipNotAddedTwice() {
+ fun displayChip_twice_chipAndGestureDetectionNotAddedTwice() {
controllerCommon.displayChip(getState())
reset(windowManager)
+ reset(tapGestureDetector)
controllerCommon.displayChip(getState())
verify(windowManager, never()).addView(any(), any())
+ verify(tapGestureDetector, never()).addOnGestureDetectedCallback(any(), any())
}
@Test
@@ -130,7 +145,7 @@
}
@Test
- fun removeChip_chipRemoved() {
+ fun removeChip_chipRemovedAndGestureDetectionStopped() {
// First, add the chip
controllerCommon.displayChip(getState())
@@ -138,6 +153,7 @@
controllerCommon.removeChip()
verify(windowManager).removeView(any())
+ verify(tapGestureDetector).removeOnGestureDetectedCallback(any())
}
@Test
@@ -160,6 +176,40 @@
.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 {
@@ -173,9 +223,11 @@
inner class TestControllerCommon(
context: Context,
windowManager: WindowManager,
+ viewUtil: ViewUtil,
@Main mainExecutor: DelayableExecutor,
- ) : MediaTttChipControllerCommon<MediaTttChipState>(
- context, windowManager, mainExecutor, R.layout.media_ttt_chip
+ tapGestureDetector: TapGestureDetector,
+ ) : MediaTttChipControllerCommon<MediaTttChipState>(
+ 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 117a6c8..86d4c1b 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
@@ -22,6 +22,8 @@
import android.graphics.drawable.Drawable
import android.media.MediaRoute2Info
import android.os.Handler
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
@@ -30,13 +32,16 @@
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.CommandQueue
+import com.android.systemui.statusbar.gesture.TapGestureDetector
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
+import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Mock
import org.mockito.Mockito.never
@@ -45,6 +50,8 @@
import org.mockito.MockitoAnnotations
@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
class MediaTttChipControllerReceiverTest : SysuiTestCase() {
private lateinit var controllerReceiver: MediaTttChipControllerReceiver
@@ -55,6 +62,8 @@
@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
@@ -75,8 +84,10 @@
commandQueue,
context,
windowManager,
+ viewUtil,
FakeExecutor(FakeSystemClock()),
- Handler.getMain()
+ TapGestureDetector(context),
+ Handler.getMain(),
)
val callbackCaptor = ArgumentCaptor.forClass(CommandQueue.Callbacks::class.java)
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 b440064..88888f0 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
@@ -21,6 +21,8 @@
import android.content.pm.PackageManager
import android.graphics.drawable.Drawable
import android.media.MediaRoute2Info
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
import android.view.View
import android.view.WindowManager
import android.widget.ImageView
@@ -31,13 +33,17 @@
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.CommandQueue
+import com.android.systemui.statusbar.gesture.TapGestureDetector
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
+import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Mock
import org.mockito.Mockito.never
@@ -46,6 +52,8 @@
import org.mockito.MockitoAnnotations
@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
class MediaTttChipControllerSenderTest : SysuiTestCase() {
private lateinit var controllerSender: MediaTttChipControllerSender
@@ -56,6 +64,8 @@
@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
@@ -73,7 +83,12 @@
context.setMockPackageManager(packageManager)
controllerSender = MediaTttChipControllerSender(
- commandQueue, context, windowManager, FakeExecutor(FakeSystemClock())
+ commandQueue,
+ context,
+ windowManager,
+ viewUtil,
+ FakeExecutor(FakeSystemClock()),
+ TapGestureDetector(context)
)
val callbackCaptor = ArgumentCaptor.forClass(CommandQueue.Callbacks::class.java)
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 3a95ed3..634d9e4 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.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 @@
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 48d3857..eb1e1a2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
@@ -28,6 +28,7 @@
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.HOME_BUTTON_LONG_PRESS_DURATION_MS;
import static com.android.systemui.navigationbar.NavigationBar.NavBarActionEvent.NAVBAR_ASSIST_LONGPRESS;
+
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
@@ -93,13 +94,11 @@
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.policy.AccessibilityManagerWrapper;
+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;
import com.android.wm.shell.back.BackAnimation;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.pip.Pip;
import org.junit.After;
@@ -161,7 +160,7 @@
@Mock
private AssistManager mAssistManager;
@Mock
- private StatusBar mStatusBar;
+ private CentralSurfaces mCentralSurfaces;
@Rule
public final LeakCheckedTest.SysuiLeakCheck mLeakCheck = new LeakCheckedTest.SysuiLeakCheck();
@@ -190,7 +189,7 @@
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);
@@ -283,7 +282,7 @@
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();
@@ -319,7 +318,7 @@
@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);
@@ -336,7 +335,7 @@
// 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,9 +400,8 @@
mBroadcastDispatcher,
mCommandQueue,
Optional.of(mock(Pip.class)),
- Optional.of(mock(LegacySplitScreen.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 721809c..373770e 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.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 @@
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();
@@ -685,7 +685,7 @@
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/FooterActionsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt
index 8ce50a6..7b17c36 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt
@@ -33,12 +33,15 @@
import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.Mock
import org.mockito.Mockito
+import org.mockito.Mockito.never
+import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
+import javax.inject.Provider
import org.mockito.Mockito.`when` as whenever
@SmallTest
-@TestableLooper.RunWithLooper
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
@RunWith(AndroidTestingRunner::class)
class FooterActionsControllerTest : LeakCheckedTest() {
@Mock
@@ -56,6 +59,8 @@
@Mock
private lateinit var multiUserSwitchController: MultiUserSwitchController
@Mock
+ private lateinit var globalActionsDialogProvider: Provider<GlobalActionsDialogLite>
+ @Mock
private lateinit var globalActionsDialog: GlobalActionsDialogLite
@Mock
private lateinit var uiEventLogger: UiEventLogger
@@ -83,15 +88,11 @@
whenever(multiUserSwitchControllerFactory.create(any()))
.thenReturn(multiUserSwitchController)
whenever(featureFlags.isEnabled(Flags.NEW_FOOTER)).thenReturn(false)
+ whenever(globalActionsDialogProvider.get()).thenReturn(globalActionsDialog)
- view = LayoutInflater.from(context)
- .inflate(R.layout.footer_actions, null) as FooterActionsView
+ view = inflateView()
- controller = FooterActionsController(view, multiUserSwitchControllerFactory,
- activityStarter, userManager, userTracker, userInfoController,
- deviceProvisionedController, securityFooterController, fgsManagerController,
- falsingManager, metricsLogger, globalActionsDialog, uiEventLogger,
- showPMLiteButton = true, fakeSettings, Handler(testableLooper.looper), featureFlags)
+ controller = constructFooterActionsController(view)
controller.init()
ViewUtils.attachView(view)
// View looper is the testable looper associated with the test
@@ -100,7 +101,9 @@
@After
fun tearDown() {
- ViewUtils.detachView(view)
+ if (view.isAttachedToWindow) {
+ ViewUtils.detachView(view)
+ }
}
@Test
@@ -139,8 +142,7 @@
@Test
fun testMultiUserSwitchUpdatedWhenSettingChanged() {
- // When expanded, listening is true
- controller.setListening(true)
+ // Always listening to setting while View is attached
testableLooper.processAllMessages()
val multiUserSwitch = view.requireViewById<View>(R.id.multi_user_switch)
@@ -156,4 +158,56 @@
assertThat(multiUserSwitch.visibility).isEqualTo(View.VISIBLE)
}
+
+ @Test
+ fun testMultiUserSettingNotListenedAfterDetach() {
+ testableLooper.processAllMessages()
+
+ val multiUserSwitch = view.requireViewById<View>(R.id.multi_user_switch)
+ assertThat(multiUserSwitch.visibility).isNotEqualTo(View.VISIBLE)
+
+ ViewUtils.detachView(view)
+
+ // The setting is only used as an indicator for whether the view should refresh. The actual
+ // value of the setting is ignored; isMultiUserEnabled is the source of truth
+ whenever(multiUserSwitchController.isMultiUserEnabled).thenReturn(true)
+
+ // Changing the value of USER_SWITCHER_ENABLED should cause the view to update
+ fakeSettings.putIntForUser(Settings.Global.USER_SWITCHER_ENABLED, 1, userTracker.userId)
+ testableLooper.processAllMessages()
+
+ assertThat(multiUserSwitch.visibility).isNotEqualTo(View.VISIBLE)
+ }
+
+ @Test
+ fun testCleanUpGAD() {
+ reset(globalActionsDialogProvider)
+ whenever(globalActionsDialogProvider.get()).thenReturn(globalActionsDialog)
+ val view = inflateView()
+ controller = constructFooterActionsController(view)
+ controller.init()
+ verify(globalActionsDialogProvider, never()).get()
+
+ // GAD is constructed during attachment
+ ViewUtils.attachView(view)
+ testableLooper.processAllMessages()
+ verify(globalActionsDialogProvider).get()
+
+ ViewUtils.detachView(view)
+ testableLooper.processAllMessages()
+ verify(globalActionsDialog).destroy()
+ }
+
+ private fun inflateView(): FooterActionsView {
+ return LayoutInflater.from(context)
+ .inflate(R.layout.footer_actions, null) as FooterActionsView
+ }
+
+ private fun constructFooterActionsController(view: FooterActionsView): FooterActionsController {
+ return FooterActionsController(view, multiUserSwitchControllerFactory,
+ activityStarter, userManager, userTracker, userInfoController,
+ deviceProvisionedController, securityFooterController, fgsManagerController,
+ falsingManager, metricsLogger, globalActionsDialogProvider, uiEventLogger,
+ showPMLiteButton = true, fakeSettings, Handler(testableLooper.looper), featureFlags)
+ }
}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index 4ab3926..534c7e7 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.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 @@
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/QSPanelControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt
new file mode 100644
index 0000000..ac1e86f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt
@@ -0,0 +1,136 @@
+package com.android.systemui.qs
+
+import android.test.suitebuilder.annotation.SmallTest
+import android.testing.AndroidTestingRunner
+import com.android.internal.logging.MetricsLogger
+import com.android.internal.logging.UiEventLogger
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.media.MediaFlags
+import com.android.systemui.media.MediaHost
+import com.android.systemui.media.MediaHostState
+import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.qs.customize.QSCustomizerController
+import com.android.systemui.qs.logging.QSLogger
+import com.android.systemui.settings.brightness.BrightnessController
+import com.android.systemui.settings.brightness.BrightnessSliderController
+import com.android.systemui.tuner.TunerService
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.any
+import org.mockito.Mockito.reset
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class QSPanelControllerTest : SysuiTestCase() {
+
+ @Mock private lateinit var qsPanel: QSPanel
+ @Mock private lateinit var qsFgsManagerFooter: QSFgsManagerFooter
+ @Mock private lateinit var qsSecurityFooter: QSSecurityFooter
+ @Mock private lateinit var tunerService: TunerService
+ @Mock private lateinit var qsTileHost: QSTileHost
+ @Mock private lateinit var qsCustomizerController: QSCustomizerController
+ @Mock private lateinit var qsTileRevealControllerFactory: QSTileRevealController.Factory
+ @Mock private lateinit var dumpManager: DumpManager
+ @Mock private lateinit var metricsLogger: MetricsLogger
+ @Mock private lateinit var uiEventLogger: UiEventLogger
+ @Mock private lateinit var qsLogger: QSLogger
+ @Mock private lateinit var brightnessControllerFactory: BrightnessController.Factory
+ @Mock private lateinit var brightnessController: BrightnessController
+ @Mock private lateinit var brightnessSlider: BrightnessSliderController
+ @Mock private lateinit var brightnessSliderFactory: BrightnessSliderController.Factory
+ @Mock private lateinit var falsingManager: FalsingManager
+ @Mock private lateinit var featureFlags: FeatureFlags
+ @Mock private lateinit var mediaFlags: MediaFlags
+ @Mock private lateinit var mediaHost: MediaHost
+
+ private lateinit var controller: QSPanelController
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ whenever(brightnessSliderFactory.create(any(), any())).thenReturn(brightnessSlider)
+ whenever(brightnessControllerFactory.create(any())).thenReturn(brightnessController)
+ whenever(qsPanel.resources).thenReturn(mContext.orCreateTestableResources.resources)
+
+ controller = QSPanelController(
+ qsPanel,
+ qsFgsManagerFooter,
+ qsSecurityFooter,
+ tunerService,
+ qsTileHost,
+ qsCustomizerController,
+ /* usingMediaPlayer= */ true,
+ mediaHost,
+ qsTileRevealControllerFactory,
+ dumpManager,
+ metricsLogger,
+ uiEventLogger,
+ qsLogger,
+ brightnessControllerFactory,
+ brightnessSliderFactory,
+ falsingManager,
+ featureFlags,
+ mediaFlags
+ )
+ }
+
+ @After
+ fun tearDown() {
+ reset(mediaHost)
+ }
+
+ @Test
+ fun onInit_notSplitShade_newMediaLayoutAvailable_setsMediaAsExpanded() {
+ setSplitShadeEnabled(false)
+ whenever(mediaFlags.useMediaSessionLayout()).thenReturn(true)
+
+ controller.onInit()
+
+ verify(mediaHost).expansion = MediaHostState.EXPANDED
+ }
+
+ @Test
+ fun onInit_notSplitShade_newMediaLayoutNotAvailable_setsMediaAsExpanded() {
+ setSplitShadeEnabled(false)
+ whenever(mediaFlags.useMediaSessionLayout()).thenReturn(false)
+
+ controller.onInit()
+
+ verify(mediaHost).expansion = MediaHostState.EXPANDED
+ }
+
+ @Test
+ fun onInit_inSplitShade_newMediaLayoutAvailable_setsMediaAsExpanded() {
+ setSplitShadeEnabled(true)
+ whenever(mediaFlags.useMediaSessionLayout()).thenReturn(true)
+
+ controller.onInit()
+
+ verify(mediaHost).expansion = MediaHostState.EXPANDED
+ }
+
+ @Test
+ fun onInit_inSplitShade_newMediaLayoutNotAvailable_setsMediaAsCollapsed() {
+ setSplitShadeEnabled(true)
+ whenever(mediaFlags.useMediaSessionLayout()).thenReturn(false)
+
+ controller.onInit()
+
+ verify(mediaHost).expansion = MediaHostState.COLLAPSED
+ }
+
+ private fun setSplitShadeEnabled(enabled: Boolean) {
+ mContext.orCreateTestableResources
+ .addOverride(R.bool.config_use_split_notification_shade, enabled)
+ }
+}
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 8872e28..e67d37ac 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.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 @@
@Mock
private QSTile.State mMockState;
@Mock
- private StatusBar mStatusBar;
+ private CentralSurfaces mCentralSurfaces;
@Mock
private QSLogger mQSLogger;
@Mock
@@ -152,7 +152,7 @@
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 @@
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 e39d6a1..19a9863 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.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 @@
@Mock
private DumpManager mDumpManager;
@Mock
- private StatusBar mStatusBar;
+ private CentralSurfaces mCentralSurfaces;
@Mock
private QSLogger mQSLogger;
@Mock
@@ -132,7 +132,7 @@
() -> mAutoTileManager,
mDumpManager,
mock(BroadcastDispatcher.class),
- Optional.of(mStatusBar),
+ Optional.of(mCentralSurfaces),
mQSLogger,
mUiEventLogger,
mUserTracker,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
index ea4d7cc..c5bc68d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
@@ -45,6 +45,7 @@
import android.metrics.LogMaker;
import android.os.Handler;
import android.os.Looper;
+import android.provider.Settings;
import android.service.quicksettings.Tile;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -58,6 +59,7 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.testing.UiEventLoggerFake;
+import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.plugins.ActivityStarter;
@@ -101,6 +103,7 @@
private StatusBarStateController mStatusBarStateController;
@Mock
private ActivityStarter mActivityStarter;
+
private UiEventLoggerFake mUiEventLoggerFake;
private InstanceId mInstanceId = InstanceId.fakeInstanceId(5);
@@ -113,7 +116,7 @@
mTestableLooper = TestableLooper.get(this);
mUiEventLoggerFake = new UiEventLoggerFake();
when(mHost.indexOf(SPEC)).thenReturn(POSITION);
- when(mHost.getContext()).thenReturn(mContext.getBaseContext());
+ when(mHost.getContext()).thenReturn(mContext);
when(mHost.getUiEventLogger()).thenReturn(mUiEventLoggerFake);
when(mHost.getNewInstanceId()).thenReturn(mInstanceId);
@@ -342,6 +345,22 @@
mTestableLooper.processAllMessages();
}
+ @Test
+ public void testClickOnDisabledByPolicyDoesntClickLaunchesIntent() {
+ String restriction = "RESTRICTION";
+ mTile.getState().disabledByPolicy = true;
+ EnforcedAdmin admin = EnforcedAdmin.createDefaultEnforcedAdminWithRestriction(restriction);
+ mTile.setEnforcedAdmin(admin);
+
+ mTile.click(null);
+ mTestableLooper.processAllMessages();
+ assertFalse(mTile.mClicked);
+
+ ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
+ verify(mActivityStarter).postStartActivityDismissingKeyguard(captor.capture(), anyInt());
+ assertEquals(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS, captor.getValue().getAction());
+ }
+
private void assertEvent(UiEventLogger.UiEventEnum eventType,
UiEventLoggerFake.FakeUiEvent fakeEvent) {
assertEquals(eventType.getId(), fakeEvent.eventId);
@@ -400,6 +419,10 @@
getState().state = Tile.STATE_ACTIVE;
}
+ public void setEnforcedAdmin(EnforcedAdmin admin) {
+ mEnforcedAdmin = admin;
+ }
+
@Override
public BooleanState newTileState() {
return new BooleanState();
@@ -412,7 +435,6 @@
@Override
protected void handleUpdateState(BooleanState state, Object arg) {
-
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt
new file mode 100644
index 0000000..cc47248
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt
@@ -0,0 +1,117 @@
+package com.android.systemui.qs.tiles
+
+import android.content.Context
+import android.os.Handler
+import android.os.Looper
+import android.os.UserManager
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.testing.TestableLooper.RunWithLooper
+import androidx.test.filters.SmallTest
+import com.android.internal.logging.MetricsLogger
+import com.android.internal.logging.testing.UiEventLoggerFake
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.classifier.FalsingManagerFake
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.plugins.qs.QSTile
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.qs.QSTileHost
+import com.android.systemui.qs.logging.QSLogger
+import com.android.systemui.statusbar.policy.BluetoothController
+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.Mockito
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@RunWithLooper(setAsMainLooper = true)
+@SmallTest
+class BluetoothTileTest : SysuiTestCase() {
+
+ @Mock
+ private lateinit var mockContext: Context
+ @Mock
+ private lateinit var qsLogger: QSLogger
+ @Mock
+ private lateinit var qsHost: QSTileHost
+ @Mock
+ private lateinit var metricsLogger: MetricsLogger
+ private val falsingManager = FalsingManagerFake()
+ @Mock
+ private lateinit var statusBarStateController: StatusBarStateController
+ @Mock
+ private lateinit var activityStarter: ActivityStarter
+ @Mock
+ private lateinit var bluetoothController: BluetoothController
+
+ private val uiEventLogger = UiEventLoggerFake()
+ private lateinit var testableLooper: TestableLooper
+ private lateinit var tile: FakeBluetoothTile
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ testableLooper = TestableLooper.get(this)
+
+ Mockito.`when`(qsHost.context).thenReturn(mockContext)
+ Mockito.`when`(qsHost.uiEventLogger).thenReturn(uiEventLogger)
+
+ tile = FakeBluetoothTile(
+ qsHost,
+ testableLooper.looper,
+ Handler(testableLooper.looper),
+ falsingManager,
+ metricsLogger,
+ statusBarStateController,
+ activityStarter,
+ qsLogger,
+ bluetoothController
+ )
+
+ tile.initialize()
+ testableLooper.processAllMessages()
+ }
+
+ @Test
+ fun testRestrictionChecked() {
+ tile.refreshState()
+ testableLooper.processAllMessages()
+
+ assertThat(tile.restrictionChecked).isEqualTo(UserManager.DISALLOW_BLUETOOTH)
+ }
+
+ private class FakeBluetoothTile(
+ qsTileHost: QSTileHost,
+ backgroundLooper: Looper,
+ mainHandler: Handler,
+ falsingManager: FalsingManager,
+ metricsLogger: MetricsLogger,
+ statusBarStateController: StatusBarStateController,
+ activityStarter: ActivityStarter,
+ qsLogger: QSLogger,
+ bluetoothController: BluetoothController
+ ) : BluetoothTile(
+ qsTileHost,
+ backgroundLooper,
+ mainHandler,
+ falsingManager,
+ metricsLogger,
+ statusBarStateController,
+ activityStarter,
+ qsLogger,
+ bluetoothController
+ ) {
+ var restrictionChecked: String? = null
+
+ override fun checkIfRestrictionEnforcedByAdminOnly(
+ state: QSTile.State?,
+ userRestriction: String?
+ ) {
+ restrictionChecked = userRestriction
+ }
+ }
+}
\ No newline at end of file
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 bfe875c..7ab49584f 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 @@
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 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 @@
public class ActionProxyReceiverTest extends SysuiTestCase {
@Mock
- private StatusBar mMockStatusBar;
+ private CentralSurfaces mMockCentralSurfaces;
@Mock
private ActivityManagerWrapper mMockActivityManagerWrapper;
@Mock
@@ -83,7 +83,7 @@
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 @@
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 @@
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 9076e16..25a5b90 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.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 @@
@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 @@
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 @@
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 @@
@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 @@
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 @@
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 @@
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 4213b07..a4ce9cd 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 @@
/**
* 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 bd9f91f..2691ff9 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.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 @@
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 @@
NotificationVisibilityProvider visibilityProvider,
NotificationEntryManager notificationEntryManager,
RemoteInputNotificationRebuilder rebuilder,
- Lazy<Optional<StatusBar>> statusBarOptionalLazy,
+ Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy,
StatusBarStateController statusBarStateController,
Handler mainHandler,
RemoteInputUriController remoteInputUriController,
@@ -211,7 +211,7 @@
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 7fafb24..407044b 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.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 @@
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 e0689f3..3500e4d 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.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 @@
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
new file mode 100644
index 0000000..ea06647
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/gesture/GenericGestureDetectorTest.kt
@@ -0,0 +1,130 @@
+package com.android.systemui.statusbar.gesture
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.InputEvent
+import android.view.MotionEvent
+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.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class GenericGestureDetectorTest : SysuiTestCase() {
+
+ private lateinit var gestureDetector: TestGestureDetector
+
+ @Before
+ fun setUp() {
+ gestureDetector = TestGestureDetector()
+ }
+
+ @Test
+ fun noCallbacksRegistered_notGestureListening() {
+ assertThat(gestureDetector.isGestureListening).isFalse()
+ }
+
+ @Test
+ fun callbackRegistered_isGestureListening() {
+ gestureDetector.addOnGestureDetectedCallback("tag"){}
+
+ assertThat(gestureDetector.isGestureListening).isTrue()
+ }
+
+ @Test
+ fun multipleCallbacksRegistered_isGestureListening() {
+ gestureDetector.addOnGestureDetectedCallback("tag"){}
+ gestureDetector.addOnGestureDetectedCallback("tag2"){}
+
+ assertThat(gestureDetector.isGestureListening).isTrue()
+ }
+
+ @Test
+ fun allCallbacksUnregistered_notGestureListening() {
+ gestureDetector.addOnGestureDetectedCallback("tag"){}
+ gestureDetector.addOnGestureDetectedCallback("tag2"){}
+
+ gestureDetector.removeOnGestureDetectedCallback("tag")
+ gestureDetector.removeOnGestureDetectedCallback("tag2")
+
+ assertThat(gestureDetector.isGestureListening).isFalse()
+ }
+
+ @Test
+ fun someButNotAllCallbacksUnregistered_isGestureListening() {
+ gestureDetector.addOnGestureDetectedCallback("tag"){}
+ gestureDetector.addOnGestureDetectedCallback("tag2"){}
+
+ gestureDetector.removeOnGestureDetectedCallback("tag2")
+
+ assertThat(gestureDetector.isGestureListening).isTrue()
+ }
+
+ @Test
+ fun onInputEvent_meetsGestureCriteria_allCallbacksNotified() {
+ var callbackNotified = false
+ gestureDetector.addOnGestureDetectedCallback("tag"){
+ callbackNotified = true
+ }
+
+ gestureDetector.onInputEvent(
+ MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, CORRECT_X, 0f, 0)
+ )
+
+ assertThat(callbackNotified).isTrue()
+ }
+
+ @Test
+ fun onInputEvent_doesNotMeetGestureCriteria_callbackNotNotified() {
+ var callbackNotified = false
+ gestureDetector.addOnGestureDetectedCallback("tag"){
+ callbackNotified = true
+ }
+
+ gestureDetector.onInputEvent(
+ MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, CORRECT_X - 5, 0f, 0)
+ )
+
+ assertThat(callbackNotified).isFalse()
+ }
+
+ @Test
+ fun callbackUnregisteredThenGestureDetected_oldCallbackNotNotified() {
+ var oldCallbackNotified = false
+ gestureDetector.addOnGestureDetectedCallback("tag"){
+ oldCallbackNotified = true
+ }
+ gestureDetector.addOnGestureDetectedCallback("tag2"){}
+
+ gestureDetector.removeOnGestureDetectedCallback("tag")
+ gestureDetector.onInputEvent(MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, CORRECT_X, 0f, 0))
+
+ assertThat(oldCallbackNotified).isFalse()
+ }
+
+ inner class TestGestureDetector : GenericGestureDetector("fakeTag") {
+ var isGestureListening = false
+
+ override fun onInputEvent(ev: InputEvent) {
+ if (ev is MotionEvent && ev.x == CORRECT_X) {
+ onGestureDetected(ev)
+ }
+ }
+
+ override fun startGestureListening() {
+ super.startGestureListening()
+ isGestureListening = true
+ }
+
+ override fun stopGestureListening() {
+ super.stopGestureListening()
+ isGestureListening = false
+ }
+ }
+}
+
+private const val CORRECT_X = 1234f
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 f2b7bf5..0fff5f5 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 @@
() -> 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 52189e4..7fc5ece 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.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 @@
() -> 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 7d8e0d2..e9d8f58 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.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 @@
@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 @@
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 c4f954f..1561b5a 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.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.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 @@
@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 @@
@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 @@
when(mNotificationSwipeHelperBuilder.build()).thenReturn(mNotificationSwipeHelper);
when(mNotifPipelineFlags.isNewPipelineEnabled()).thenReturn(false);
- when(mFgServicesSectionController.createView(mLayoutInflater))
- .thenReturn(mForegroundServiceDungeonView);
mController = new NotificationStackScrollLayoutController(
true,
@@ -175,7 +168,7 @@
new FalsingManagerFake(),
mResources,
mNotificationSwipeHelperBuilder,
- mStatusBar,
+ mCentralSurfaces,
mScrimController,
mLegacyGroupManager,
mLegacyGroupManager,
@@ -187,8 +180,6 @@
mLockscreenShadeTransitionController,
mIStatusBarService,
mUiEventLogger,
- mFgFeatureController,
- mFgServicesSectionController,
mLayoutInflater,
mRemoteInputManager,
mVisualStabilityManager,
@@ -399,22 +390,6 @@
}
@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 4f731ed..eafcc35 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.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 @@
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 @@
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 @@
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/AutoTileManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
index 2289936..0e12c2a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
@@ -52,6 +52,7 @@
import com.android.systemui.qs.QSTileHost;
import com.android.systemui.qs.ReduceBrightColorsController;
import com.android.systemui.qs.SettingObserver;
+import com.android.systemui.qs.external.CustomTile;
import com.android.systemui.statusbar.policy.CastController;
import com.android.systemui.statusbar.policy.CastController.CastDevice;
import com.android.systemui.statusbar.policy.DataSaverController;
@@ -85,6 +86,7 @@
private static final String TEST_SETTING_COMPONENT = "setting_component";
private static final String TEST_COMPONENT = "test_pkg/test_cls";
private static final String TEST_CUSTOM_SPEC = "custom(" + TEST_COMPONENT + ")";
+ private static final String TEST_CUSTOM_SAFETY_SPEC = "custom(safety_pkg/safety_cls)";
private static final String SEPARATOR = AutoTileManager.SETTING_SEPARATOR;
private static final int USER = 0;
@@ -121,6 +123,8 @@
);
mContext.getOrCreateTestableResources().addOverride(
com.android.internal.R.bool.config_nightDisplayAvailable, true);
+ mContext.getOrCreateTestableResources().addOverride(
+ R.string.safety_quick_settings_tile, TEST_CUSTOM_SAFETY_SPEC);
when(mAutoAddTrackerBuilder.build()).thenReturn(mAutoAddTracker);
when(mQsTileHost.getUserContext()).thenReturn(mUserContext);
@@ -435,6 +439,25 @@
}
@Test
+ public void testSafetyTileNotAdded_ifPreviouslyAdded() {
+ ComponentName safetyComponent = CustomTile.getComponentFromSpec(TEST_CUSTOM_SAFETY_SPEC);
+ mAutoTileManager.init();
+ verify(mQsTileHost, times(1)).addTile(safetyComponent, true);
+ when(mAutoAddTracker.isAdded(TEST_CUSTOM_SAFETY_SPEC)).thenReturn(true);
+ mAutoTileManager.init();
+ verify(mQsTileHost, times(1)).addTile(safetyComponent, true);
+ }
+
+ @Test
+ public void testSafetyTileAdded_onUserChange() {
+ ComponentName safetyComponent = CustomTile.getComponentFromSpec(TEST_CUSTOM_SAFETY_SPEC);
+ mAutoTileManager.init();
+ verify(mQsTileHost, times(1)).addTile(safetyComponent, true);
+ when(mAutoAddTracker.isAdded(TEST_CUSTOM_SAFETY_SPEC)).thenReturn(false);
+ mAutoTileManager.changeUser(UserHandle.of(USER + 1));
+ verify(mQsTileHost, times(2)).addTile(safetyComponent, true);
+ }
+ @Test
public void testEmptyArray_doesNotCrash() {
mContext.getOrCreateTestableResources().addOverride(
R.array.config_quickSettingsAutoAdd, new String[0]);
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
similarity index 86%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacksTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
index aabf923..9bfb2c4 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
@@ -45,7 +45,6 @@
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import org.junit.Before;
import org.junit.Test;
@@ -58,12 +57,11 @@
@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;
- @Mock private LegacySplitScreen mLegacySplitScreen;
@Mock private RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
private final MetricsLogger mMetricsLogger = new FakeMetricsLogger();
@Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@@ -83,20 +81,19 @@
@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,
mCommandQueue,
mNotificationPanelViewController,
- Optional.of(mLegacySplitScreen),
mRemoteInputQuickSettingsDisabler,
mMetricsLogger,
mKeyguardUpdateMonitor,
@@ -125,13 +122,13 @@
@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.
@@ -143,12 +140,13 @@
@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.
@@ -161,13 +159,13 @@
@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
similarity index 90%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesTest.java
index c7db9e4..953a330 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.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;
@@ -159,7 +159,6 @@
import com.android.systemui.volume.VolumeComponent;
import com.android.systemui.wmshell.BubblesManager;
import com.android.wm.shell.bubbles.Bubbles;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.startingsurface.StartingSurface;
import org.junit.Before;
@@ -178,12 +177,12 @@
@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;
@@ -253,15 +252,12 @@
@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 LegacySplitScreen mLegacySplitScreen;
@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;
@@ -338,8 +334,6 @@
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));
@@ -370,8 +364,8 @@
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();
@@ -381,12 +375,12 @@
mShadeController = new ShadeControllerImpl(mCommandQueue,
mStatusBarStateController, mNotificationShadeWindowController,
mStatusBarKeyguardViewManager, mContext.getSystemService(WindowManager.class),
- () -> Optional.of(mStatusBar), () -> mAssistManager, Optional.of(mBubbles));
+ () -> Optional.of(mCentralSurfaces), () -> mAssistManager);
when(mOperatorNameViewControllerFactory.create(any()))
.thenReturn(mOperatorNameViewController);
- mStatusBar = new StatusBar(
+ mCentralSurfaces = new CentralSurfaces(
mContext,
mNotificationsController,
mock(FragmentService.class),
@@ -447,8 +441,6 @@
mCommandQueue,
mStatusBarComponentFactory,
mPluginManager,
- Optional.of(mLegacySplitScreen),
- mStatusBarNotificationActivityStarterBuilder,
mShadeController,
mStatusBarKeyguardViewManager,
mViewMediatorCallback,
@@ -483,8 +475,8 @@
mDeviceStateManager,
mDreamOverlayStateController,
mWiredChargingRippleController);
- when(mKeyguardViewMediator.registerStatusBar(
- any(StatusBar.class),
+ when(mKeyguardViewMediator.registerCentralSurfaces(
+ any(CentralSurfaces.class),
any(NotificationPanelViewController.class),
any(PanelExpansionStateManager.class),
any(BiometricUnlockController.class),
@@ -495,23 +487,23 @@
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
@@ -519,7 +511,7 @@
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
@@ -527,7 +519,7 @@
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
@@ -535,7 +527,7 @@
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
@@ -547,7 +539,7 @@
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(),
@@ -566,7 +558,7 @@
when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false);
when(mKeyguardStateController.isMethodSecure()).thenReturn(true);
- mStatusBar.onKeyguardViewManagerStatesUpdated();
+ mCentralSurfaces.onKeyguardViewManagerStatesUpdated();
MetricsAsserts.assertHasLog("missing hidden secure lockscreen log",
mMetricsLogger.getLogs(),
@@ -585,7 +577,7 @@
when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false);
when(mKeyguardStateController.isMethodSecure()).thenReturn(false);
- mStatusBar.onKeyguardViewManagerStatesUpdated();
+ mCentralSurfaces.onKeyguardViewManagerStatesUpdated();
MetricsAsserts.assertHasLog("missing insecure lockscreen showing",
mMetricsLogger.getLogs(),
@@ -604,7 +596,7 @@
when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false);
when(mKeyguardStateController.isMethodSecure()).thenReturn(true);
- mStatusBar.onKeyguardViewManagerStatesUpdated();
+ mCentralSurfaces.onKeyguardViewManagerStatesUpdated();
MetricsAsserts.assertHasLog("missing secure lockscreen showing log",
mMetricsLogger.getLogs(),
@@ -623,7 +615,7 @@
when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(true);
when(mKeyguardStateController.isMethodSecure()).thenReturn(true);
- mStatusBar.onKeyguardViewManagerStatesUpdated();
+ mCentralSurfaces.onKeyguardViewManagerStatesUpdated();
MetricsAsserts.assertHasLog("missing bouncer log",
mMetricsLogger.getLogs(),
@@ -724,7 +716,7 @@
@Test
public void testLogHidden() {
try {
- mStatusBar.handleVisibleToUserChanged(false);
+ mCentralSurfaces.handleVisibleToUserChanged(false);
mUiBgExecutor.runAllReady();
verify(mBarService, times(1)).onPanelHidden();
verify(mBarService, never()).onPanelRevealed(anyBoolean(), anyInt());
@@ -739,10 +731,10 @@
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);
@@ -758,10 +750,10 @@
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);
@@ -776,10 +768,10 @@
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);
@@ -791,18 +783,18 @@
@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());
}
@@ -811,81 +803,81 @@
// 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));
}
@@ -893,45 +885,45 @@
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),
@@ -941,7 +933,7 @@
@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 a14ea54..5f2bbd3 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
@@ -27,6 +27,7 @@
import android.content.res.Resources;
import android.hardware.display.AmbientDisplayConfiguration;
+import android.os.Handler;
import android.os.PowerManager;
import android.provider.Settings;
import android.test.suitebuilder.annotation.SmallTest;
@@ -61,6 +62,7 @@
public class DozeParametersTest extends SysuiTestCase {
private DozeParameters mDozeParameters;
+ @Mock Handler mHandler;
@Mock Resources mResources;
@Mock private AmbientDisplayConfiguration mAmbientDisplayConfiguration;
@Mock private AlwaysOnDisplayPolicy mAlwaysOnDisplayPolicy;
@@ -102,6 +104,8 @@
.thenReturn(mFoldAodAnimationController);
mDozeParameters = new DozeParameters(
+ mContext,
+ mHandler,
mResources,
mAmbientDisplayConfiguration,
mAlwaysOnDisplayPolicy,
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 6ce3b4b..26ac70c 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 @@
@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 @@
mAuthController, mNotificationIconAreaController);
mDozeServiceHost.initialize(
- mStatusBar,
+ mCentralSurfaces,
mStatusBarKeyguardViewManager,
mNotificationShadeWindowViewController,
mNotificationPanel,
@@ -119,7 +119,7 @@
mDozeServiceHost.startDozing();
verify(mStatusBarStateController).setIsDozing(eq(true));
- verify(mStatusBar).updateIsKeyguard();
+ verify(mCentralSurfaces).updateIsKeyguard();
mDozeServiceHost.stopDozing();
verify(mStatusBarStateController).setIsDozing(eq(false));
@@ -128,8 +128,8 @@
@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 @@
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 421d8f6a..db5741c 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 @@
@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 3257a84..31465f4 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 @@
class KeyguardBottomAreaTest : SysuiTestCase() {
@Mock
- private lateinit var mStatusBar: StatusBar
+ private lateinit var mCentralSurfaces: CentralSurfaces
private lateinit var mKeyguardBottomArea: KeyguardBottomAreaView
@Before
@@ -42,7 +42,7 @@
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 479c271..38412fd 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.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 @@
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 @@
private NotificationShadeWindowController mNotificationShadeWindowController;
@Mock
private SysUiState mSysUiState;
+ @Mock
+ private NotificationListContainer mNotificationListContainer;
private Optional<SysUIUnfoldComponent> mSysUIUnfoldComponent = Optional.empty();
private SysuiStatusBarStateController mStatusBarStateController;
private NotificationPanelViewController mNotificationPanelViewController;
@@ -542,9 +545,10 @@
mInteractionJankMonitor,
mQsFrameTranslateController,
mSysUiState,
- mKeyguardUnlockAnimationController);
+ mKeyguardUnlockAnimationController,
+ mNotificationListContainer);
mNotificationPanelViewController.initDependencies(
- mStatusBar,
+ mCentralSurfaces,
() -> {},
mNotificationShelfController);
mNotificationPanelViewController.setHeadsUpManager(mHeadsUpManager);
@@ -904,6 +908,7 @@
public void testSwitchesToCorrectClockInSplitShade() {
mStatusBarStateController.setState(KEYGUARD);
enableSplitShade(/* enabled= */ true);
+ clearInvocations(mKeyguardStatusViewController);
when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(0);
triggerPositionClockAndNotifications();
@@ -918,11 +923,56 @@
}
@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 +984,7 @@
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 +997,7 @@
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/NotificationShadeWindowControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImplTest.java
index 671ab59..c797bc8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImplTest.java
@@ -32,6 +32,8 @@
import static org.mockito.Mockito.when;
import android.app.IActivityManager;
+import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
import android.view.View;
@@ -228,6 +230,36 @@
}
@Test
+ public void rotationBecameAllowed_layoutParamsUpdated() {
+ mNotificationShadeWindowController.setKeyguardShowing(true);
+ when(mKeyguardStateController.isKeyguardScreenRotationAllowed()).thenReturn(false);
+ mNotificationShadeWindowController.onConfigChanged(new Configuration());
+ clearInvocations(mWindowManager);
+
+ when(mKeyguardStateController.isKeyguardScreenRotationAllowed()).thenReturn(true);
+ mNotificationShadeWindowController.onConfigChanged(new Configuration());
+
+ verify(mWindowManager).updateViewLayout(any(), mLayoutParameters.capture());
+ assertThat(mLayoutParameters.getValue().screenOrientation)
+ .isEqualTo(ActivityInfo.SCREEN_ORIENTATION_USER);
+ }
+
+ @Test
+ public void rotationBecameNotAllowed_layoutParamsUpdated() {
+ mNotificationShadeWindowController.setKeyguardShowing(true);
+ when(mKeyguardStateController.isKeyguardScreenRotationAllowed()).thenReturn(true);
+ mNotificationShadeWindowController.onConfigChanged(new Configuration());
+ clearInvocations(mWindowManager);
+
+ when(mKeyguardStateController.isKeyguardScreenRotationAllowed()).thenReturn(false);
+ mNotificationShadeWindowController.onConfigChanged(new Configuration());
+
+ verify(mWindowManager).updateViewLayout(any(), mLayoutParameters.capture());
+ assertThat(mLayoutParameters.getValue().screenOrientation)
+ .isEqualTo(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
+ }
+
+ @Test
public void batchApplyWindowLayoutParams_doesNotDispatchEvents() {
mNotificationShadeWindowController.setForceDozeBrightness(true);
verify(mWindowManager).updateViewLayout(any(), any());
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 34a5d4b..093f926 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 @@
@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 @@
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 6c33113..62a1bcd 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 @@
@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 @@
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 5891161..9ab88dc 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.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 @@
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 @@
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 @@
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 @@
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 @@
}
}
}
-
-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 8b93de5..f4f55cc 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 @@
@Mock
private KeyguardStateController mKeyguardStateController;
@Mock
- private StatusBar mStatusBar;
+ private CentralSurfaces mCentralSurfaces;
@Mock
private ViewGroup mContainer;
@Mock
@@ -118,7 +118,7 @@
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 @@
Optional.of(mSysUiUnfoldComponent),
() -> mShadeController,
mLatencyTracker);
- mStatusBarKeyguardViewManager.registerStatusBar(
- mStatusBar,
+ mStatusBarKeyguardViewManager.registerCentralSurfaces(
+ mCentralSurfaces,
mNotificationPanelView,
new PanelExpansionStateManager(),
mBiometricUnlockController,
@@ -261,7 +261,7 @@
@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 @@
@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 @@
@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 @@
@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 743311f..ace7415 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 @@
@Mock
private NotificationRemoteInputManager mRemoteInputManager;
@Mock
- private StatusBar mStatusBar;
+ private CentralSurfaces mCentralSurfaces;
@Mock
private KeyguardStateController mKeyguardStateController;
@Mock
@@ -203,7 +203,7 @@
mJankMonitor);
mNotificationActivityStarter =
- new StatusBarNotificationActivityStarter.Builder(
+ new StatusBarNotificationActivityStarter(
getContext(),
mock(CommandQueue.class),
mHandler,
@@ -229,18 +229,16 @@
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 @@
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 @@
// 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 @@
// 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 @@
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 7d9e6b4..1a3dd3a 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.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 @@
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 @@
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 @@
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 @@
.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 71b32c0..050563a 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
@@ -61,7 +61,7 @@
@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 +93,8 @@
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
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 5861617..5095094 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 @@
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.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.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 @@
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 @@
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 @@
mOperatorNameViewControllerFactory = mock(OperatorNameViewController.Factory.class);
when(mOperatorNameViewControllerFactory.create(any()))
.thenReturn(mOperatorNameViewController);
+ mSecureSettings = mock(SecureSettings.class);
setUpNotificationIconAreaController();
return new CollapsedStatusBarFragment(
@@ -334,7 +377,9 @@
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 0920cac..ada0453 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 @@
val notificationCollection = mock(CommonNotifCollection::class.java)
controller = OngoingCallController(
+ context,
notificationCollection,
mockOngoingCallFlags,
clock,
@@ -217,6 +218,39 @@
verify(mockIActivityManager, times(numCalls - 1)).unregisterUidObserver(any())
}
+ /** Regression test for b/216248574. */
+ @Test
+ fun entryUpdated_getUidProcessStateThrowsException_noCrash() {
+ `when`(mockIActivityManager.getUidProcessState(eq(CALL_UID), nullable(String::class.java)))
+ .thenThrow(SecurityException())
+
+ // No assert required, just check no crash
+ notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
+ }
+
+ /** Regression test for b/216248574. */
+ @Test
+ fun entryUpdated_registerUidObserverThrowsException_noCrash() {
+ `when`(mockIActivityManager.registerUidObserver(
+ any(), any(), any(), nullable(String::class.java)
+ )).thenThrow(SecurityException())
+
+ // No assert required, just check no crash
+ 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 0000000..3a5d9ee
--- /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/statusbar/policy/UserSwitcherControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt
index 07e0279..896dab6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt
@@ -48,7 +48,6 @@
import com.android.systemui.qs.user.UserSwitchDialogController
import com.android.systemui.settings.UserTracker
import com.android.systemui.statusbar.phone.NotificationShadeWindowView
-import com.android.systemui.statusbar.phone.ShadeController
import com.android.systemui.telephony.TelephonyListenerManager
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.settings.SecureSettings
@@ -95,7 +94,6 @@
@Mock private lateinit var notificationShadeWindowView: NotificationShadeWindowView
@Mock private lateinit var threadedRenderer: ThreadedRenderer
@Mock private lateinit var dialogLaunchAnimator: DialogLaunchAnimator
- @Mock private lateinit var shadeController: ShadeController
private lateinit var testableLooper: TestableLooper
private lateinit var bgExecutor: FakeExecutor
private lateinit var uiExecutor: FakeExecutor
@@ -171,7 +169,6 @@
interactionJankMonitor,
latencyTracker,
dumpManager,
- { shadeController },
dialogLaunchAnimator)
userSwitcherController.init(notificationShadeWindowView)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/touch/TouchInsetManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/touch/TouchInsetManagerTest.java
new file mode 100644
index 0000000..14b9bfb
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/touch/TouchInsetManagerTest.java
@@ -0,0 +1,203 @@
+/*
+ * 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.touch;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.doAnswer;
+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.view.View;
+import android.view.ViewRootImpl;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class TouchInsetManagerTest extends SysuiTestCase {
+ @Mock
+ private View mRootView;
+
+ @Mock
+ private ViewRootImpl mRootViewImpl;
+
+ private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ when(mRootView.getViewRootImpl()).thenReturn(mRootViewImpl);
+ }
+
+ @Test
+ public void testRootViewOnAttachedHandling() {
+ // Create inset manager
+ final TouchInsetManager insetManager = new TouchInsetManager(mFakeExecutor,
+ mRootView);
+
+ final ArgumentCaptor<View.OnAttachStateChangeListener> listener =
+ ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class);
+
+ // Ensure manager has registered to listen to attached state of root view.
+ verify(mRootView).addOnAttachStateChangeListener(listener.capture());
+
+ // Trigger attachment and verify touchable region is set.
+ listener.getValue().onViewAttachedToWindow(mRootView);
+ verify(mRootViewImpl).setTouchableRegion(any());
+ }
+
+ @Test
+ public void testInsetRegionPropagation() {
+ // Create inset manager
+ final TouchInsetManager insetManager = new TouchInsetManager(mFakeExecutor,
+ mRootView);
+
+ // Create session
+ final TouchInsetManager.TouchInsetSession session = insetManager.createSession();
+
+ // Add a view to the session.
+ final Rect rect = new Rect(0, 0, 2, 2);
+
+ session.addViewToTracking(createView(rect));
+ mFakeExecutor.runAllReady();
+
+ // Check to see if view was properly accounted for.
+ final Region expectedRegion = Region.obtain();
+ expectedRegion.op(rect, Region.Op.UNION);
+ verify(mRootViewImpl).setTouchableRegion(eq(expectedRegion));
+ }
+
+ @Test
+ public void testMultipleRegions() {
+ // Create inset manager
+ final TouchInsetManager insetManager = new TouchInsetManager(mFakeExecutor,
+ mRootView);
+
+ // Create session
+ final TouchInsetManager.TouchInsetSession session = insetManager.createSession();
+
+ // Add a view to the session.
+ final Rect firstBounds = new Rect(0, 0, 2, 2);
+ session.addViewToTracking(createView(firstBounds));
+
+ mFakeExecutor.runAllReady();
+ clearInvocations(mRootViewImpl);
+
+ // Create second session
+ final TouchInsetManager.TouchInsetSession secondSession = insetManager.createSession();
+
+ // Add a view to the second session.
+ final Rect secondBounds = new Rect(4, 4, 8, 10);
+ secondSession.addViewToTracking(createView(secondBounds));
+
+ mFakeExecutor.runAllReady();
+
+ // Check to see if all views and sessions was properly accounted for.
+ {
+ final Region expectedRegion = Region.obtain();
+ expectedRegion.op(firstBounds, Region.Op.UNION);
+ expectedRegion.op(secondBounds, Region.Op.UNION);
+ verify(mRootViewImpl).setTouchableRegion(eq(expectedRegion));
+ }
+
+
+ clearInvocations(mRootViewImpl);
+
+ // clear first session, ensure second session is still reflected.
+ session.clear();
+ mFakeExecutor.runAllReady();
+ {
+ final Region expectedRegion = Region.obtain();
+ expectedRegion.op(firstBounds, Region.Op.UNION);
+ verify(mRootViewImpl).setTouchableRegion(eq(expectedRegion));
+ }
+ }
+
+ @Test
+ public void testMultipleViews() {
+ // Create inset manager
+ final TouchInsetManager insetManager = new TouchInsetManager(mFakeExecutor,
+ mRootView);
+
+ // Create session
+ final TouchInsetManager.TouchInsetSession session = insetManager.createSession();
+
+ // Add a view to the session.
+ final Rect firstViewBounds = new Rect(0, 0, 2, 2);
+ session.addViewToTracking(createView(firstViewBounds));
+
+ // only capture second invocation.
+ mFakeExecutor.runAllReady();
+ clearInvocations(mRootViewImpl);
+
+ // Add a second view to the session
+ final Rect secondViewBounds = new Rect(4, 4, 9, 10);
+ final View secondView = createView(secondViewBounds);
+ session.addViewToTracking(secondView);
+
+ mFakeExecutor.runAllReady();
+
+ // Check to see if all views and sessions was properly accounted for.
+ {
+ final Region expectedRegion = Region.obtain();
+ expectedRegion.op(firstViewBounds, Region.Op.UNION);
+ expectedRegion.op(secondViewBounds, Region.Op.UNION);
+ verify(mRootViewImpl).setTouchableRegion(eq(expectedRegion));
+ }
+
+ // Remove second view.
+ session.removeViewFromTracking(secondView);
+
+ clearInvocations(mRootViewImpl);
+ mFakeExecutor.runAllReady();
+
+ // Ensure first view still reflected in touch region.
+ {
+ final Region expectedRegion = Region.obtain();
+ expectedRegion.op(firstViewBounds, Region.Op.UNION);
+ verify(mRootViewImpl).setTouchableRegion(eq(expectedRegion));
+ }
+ }
+
+ private View createView(Rect bounds) {
+ final Rect rect = new Rect(bounds);
+ final View view = Mockito.mock(View.class);
+ doAnswer(invocation -> {
+ ((Rect) invocation.getArgument(0)).set(rect);
+ return null;
+ }).when(view).getBoundsOnScreen(any());
+
+ return view;
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/UserSwitcherActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/UserSwitcherActivityTest.kt
new file mode 100644
index 0000000..d4be881
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/UserSwitcherActivityTest.kt
@@ -0,0 +1,77 @@
+/*
+ * 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.user
+
+import android.os.UserManager
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper.RunWithLooper
+import android.view.LayoutInflater
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.statusbar.phone.ShadeController
+import com.android.systemui.statusbar.policy.UserSwitcherController
+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
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@RunWithLooper(setAsMainLooper = true)
+class UserSwitcherActivityTest : SysuiTestCase() {
+ @Mock
+ private lateinit var activity: UserSwitcherActivity
+ @Mock
+ private lateinit var userSwitcherController: UserSwitcherController
+ @Mock
+ private lateinit var broadcastDispatcher: BroadcastDispatcher
+ @Mock
+ private lateinit var layoutInflater: LayoutInflater
+ @Mock
+ private lateinit var falsingManager: FalsingManager
+ @Mock
+ private lateinit var userManager: UserManager
+ @Mock
+ private lateinit var shadeController: ShadeController
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ activity = UserSwitcherActivity(
+ userSwitcherController,
+ broadcastDispatcher,
+ layoutInflater,
+ falsingManager,
+ userManager,
+ shadeController
+ )
+ }
+
+ @Test
+ fun testMaxColumns() {
+ assertThat(activity.getMaxColumns(3)).isEqualTo(4)
+ assertThat(activity.getMaxColumns(4)).isEqualTo(4)
+ assertThat(activity.getMaxColumns(5)).isEqualTo(3)
+ assertThat(activity.getMaxColumns(6)).isEqualTo(3)
+ assertThat(activity.getMaxColumns(7)).isEqualTo(4)
+ assertThat(activity.getMaxColumns(9)).isEqualTo(5)
+ }
+}
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 0000000..dead159
--- /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 8ad6271..2be67ed 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 @@
}
@Override
+ public void refreshIconGroup(IconManager iconManager) {
+ }
+
+ @Override
public void setExternalIcon(String slot) {
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
index b380553..ec619bb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
@@ -36,6 +36,7 @@
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.CaptioningManager;
import androidx.test.filters.SmallTest;
@@ -88,6 +89,8 @@
private PackageManager mPackageManager;
@Mock
private WakefulnessLifecycle mWakefullnessLifcycle;
+ @Mock
+ private CaptioningManager mCaptioningManager;
@Before
@@ -109,7 +112,7 @@
mVolumeController = new TestableVolumeDialogControllerImpl(mContext,
mBroadcastDispatcher, mRingerModeTracker, mThreadFactory, mAudioManager,
mNotificationManager, mVibrator, mIAudioService, mAccessibilityManager,
- mPackageManager, mWakefullnessLifcycle, mCallback);
+ mPackageManager, mWakefullnessLifcycle, mCaptioningManager, mCallback);
mVolumeController.setEnableDialogs(true, true);
}
@@ -184,10 +187,11 @@
AccessibilityManager accessibilityManager,
PackageManager packageManager,
WakefulnessLifecycle wakefulnessLifecycle,
+ CaptioningManager captioningManager,
C callback) {
super(context, broadcastDispatcher, ringerModeTracker, theadFactory, audioManager,
notificationManager, optionalVibrator, iAudioService, accessibilityManager,
- packageManager, wakefulnessLifecycle);
+ packageManager, wakefulnessLifecycle, captioningManager);
mCallbacks = callback;
ArgumentCaptor<WakefulnessLifecycle.Observer> observerCaptor =
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 4bc4e6e..82880fe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -50,8 +50,10 @@
import android.app.INotificationManager;
import android.app.Notification;
import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
@@ -197,6 +199,11 @@
private ArgumentCaptor<NotificationRemoveInterceptor> mRemoveInterceptorCaptor;
@Captor
private ArgumentCaptor<List<Bubble>> mBubbleListCaptor;
+ @Captor
+ private ArgumentCaptor<IntentFilter> mFilterArgumentCaptor;
+ @Captor
+ private ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverArgumentCaptor;
+
private BubblesManager mBubblesManager;
// TODO(178618782): Move tests on the controller directly to the shell
@@ -1214,7 +1221,7 @@
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);
@@ -1357,6 +1364,66 @@
assertStackCollapsed();
}
+ @Test
+ public void testRegisterUnregisterBroadcastListener() {
+ spyOn(mContext);
+ mBubbleController.updateBubble(mBubbleEntry);
+ verify(mContext).registerReceiver(mBroadcastReceiverArgumentCaptor.capture(),
+ mFilterArgumentCaptor.capture());
+ assertThat(mFilterArgumentCaptor.getValue().getAction(0)).isEqualTo(
+ Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+ assertThat(mFilterArgumentCaptor.getValue().getAction(1)).isEqualTo(
+ Intent.ACTION_SCREEN_OFF);
+
+ mBubbleData.dismissBubbleWithKey(mBubbleEntry.getKey(), REASON_APP_CANCEL);
+ // TODO: not certain why this isn't called normally when tests are run, perhaps because
+ // it's after an animation in BSV. This calls BubbleController#removeFromWindowManagerMaybe
+ mBubbleController.onAllBubblesAnimatedOut();
+
+ verify(mContext).unregisterReceiver(eq(mBroadcastReceiverArgumentCaptor.getValue()));
+ }
+
+ @Test
+ public void testBroadcastReceiverCloseDialogs_notGestureNav() {
+ spyOn(mContext);
+ mBubbleController.updateBubble(mBubbleEntry);
+ mBubbleData.setExpanded(true);
+ verify(mContext).registerReceiver(mBroadcastReceiverArgumentCaptor.capture(),
+ mFilterArgumentCaptor.capture());
+ Intent i = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+ mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, i);
+
+ assertStackExpanded();
+ }
+
+ @Test
+ public void testBroadcastReceiverCloseDialogs_reasonGestureNav() {
+ spyOn(mContext);
+ mBubbleController.updateBubble(mBubbleEntry);
+ mBubbleData.setExpanded(true);
+
+ verify(mContext).registerReceiver(mBroadcastReceiverArgumentCaptor.capture(),
+ mFilterArgumentCaptor.capture());
+ Intent i = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+ i.putExtra("reason", "gestureNav");
+ mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, i);
+ assertStackCollapsed();
+ }
+
+ @Test
+ public void testBroadcastReceiver_screenOff() {
+ spyOn(mContext);
+ mBubbleController.updateBubble(mBubbleEntry);
+ mBubbleData.setExpanded(true);
+
+ verify(mContext).registerReceiver(mBroadcastReceiverArgumentCaptor.capture(),
+ mFilterArgumentCaptor.capture());
+
+ Intent i = new Intent(Intent.ACTION_SCREEN_OFF);
+ mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, i);
+ assertStackCollapsed();
+ }
+
/** Creates a bubble using the userId and package. */
private Bubble createBubble(int userId, String pkg) {
final UserHandle userHandle = new UserHandle(userId);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
index 75d8453..cc848bc3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
@@ -46,6 +46,9 @@
import android.app.INotificationManager;
import android.app.Notification;
import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.LauncherApps;
import android.hardware.display.AmbientDisplayConfiguration;
import android.os.Handler;
@@ -179,6 +182,10 @@
private ArgumentCaptor<NotifCollectionListener> mNotifListenerCaptor;
@Captor
private ArgumentCaptor<List<Bubble>> mBubbleListCaptor;
+ @Captor
+ private ArgumentCaptor<IntentFilter> mFilterArgumentCaptor;
+ @Captor
+ private ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverArgumentCaptor;
private BubblesManager mBubblesManager;
private TestableBubbleController mBubbleController;
@@ -1176,6 +1183,67 @@
assertStackCollapsed();
}
+
+ @Test
+ public void testRegisterUnregisterBroadcastListener() {
+ spyOn(mContext);
+ mBubbleController.updateBubble(mBubbleEntry);
+ verify(mContext).registerReceiver(mBroadcastReceiverArgumentCaptor.capture(),
+ mFilterArgumentCaptor.capture());
+ assertThat(mFilterArgumentCaptor.getValue().getAction(0)).isEqualTo(
+ Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+ assertThat(mFilterArgumentCaptor.getValue().getAction(1)).isEqualTo(
+ Intent.ACTION_SCREEN_OFF);
+
+ mBubbleData.dismissBubbleWithKey(mBubbleEntry.getKey(), REASON_APP_CANCEL);
+ // TODO: not certain why this isn't called normally when tests are run, perhaps because
+ // it's after an animation in BSV. This calls BubbleController#removeFromWindowManagerMaybe
+ mBubbleController.onAllBubblesAnimatedOut();
+
+ verify(mContext).unregisterReceiver(eq(mBroadcastReceiverArgumentCaptor.getValue()));
+ }
+
+ @Test
+ public void testBroadcastReceiverCloseDialogs_notGestureNav() {
+ spyOn(mContext);
+ mBubbleController.updateBubble(mBubbleEntry);
+ mBubbleData.setExpanded(true);
+ verify(mContext).registerReceiver(mBroadcastReceiverArgumentCaptor.capture(),
+ mFilterArgumentCaptor.capture());
+ Intent i = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+ mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, i);
+
+ assertStackExpanded();
+ }
+
+ @Test
+ public void testBroadcastReceiverCloseDialogs_reasonGestureNav() {
+ spyOn(mContext);
+ mBubbleController.updateBubble(mBubbleEntry);
+ mBubbleData.setExpanded(true);
+
+ verify(mContext).registerReceiver(mBroadcastReceiverArgumentCaptor.capture(),
+ mFilterArgumentCaptor.capture());
+ Intent i = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+ i.putExtra("reason", "gestureNav");
+ mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, i);
+ assertStackCollapsed();
+ }
+
+ @Test
+ public void testBroadcastReceiver_screenOff() {
+ spyOn(mContext);
+ mBubbleController.updateBubble(mBubbleEntry);
+ mBubbleData.setExpanded(true);
+
+ verify(mContext).registerReceiver(mBroadcastReceiverArgumentCaptor.capture(),
+ mFilterArgumentCaptor.capture());
+
+ Intent i = new Intent(Intent.ACTION_SCREEN_OFF);
+ mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, i);
+ assertStackCollapsed();
+ }
+
/**
* Sets the bubble metadata flags for this entry. These flags are normally set by
* NotificationManagerService when the notification is sent, however, these tests do not
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
index 6593823..7726938 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
@@ -39,7 +39,6 @@
import com.android.wm.shell.compatui.CompatUI;
import com.android.wm.shell.draganddrop.DragAndDrop;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.onehanded.OneHandedEventCallback;
import com.android.wm.shell.onehanded.OneHandedTransitionCallback;
@@ -72,7 +71,6 @@
@Mock ScreenLifecycle mScreenLifecycle;
@Mock SysUiState mSysUiState;
@Mock Pip mPip;
- @Mock LegacySplitScreen mLegacySplitScreen;
@Mock SplitScreen mSplitScreen;
@Mock OneHanded mOneHanded;
@Mock HideDisplayCutout mHideDisplayCutout;
@@ -88,7 +86,7 @@
public void setUp() {
MockitoAnnotations.initMocks(this);
- mWMShell = new WMShell(mContext, Optional.of(mPip), Optional.of(mLegacySplitScreen),
+ mWMShell = new WMShell(mContext, Optional.of(mPip),
Optional.of(mSplitScreen), Optional.of(mOneHanded), Optional.of(mHideDisplayCutout),
Optional.of(mShellCommandHandler), Optional.of(mCompatUI),
Optional.of(mDragAndDrop),
@@ -105,13 +103,6 @@
}
@Test
- public void initLegacySplitScreen_registersCallbacks() {
- mWMShell.initLegacySplitScreen(mLegacySplitScreen);
-
- verify(mKeyguardUpdateMonitor).registerCallback(any(KeyguardUpdateMonitorCallback.class));
- }
-
- @Test
public void initSplitScreen_registersCallbacks() {
mWMShell.initSplitScreen(mSplitScreen);
diff --git a/proto/src/camera.proto b/proto/src/camera.proto
index 2d62f32..4082118 100644
--- a/proto/src/camera.proto
+++ b/proto/src/camera.proto
@@ -64,7 +64,7 @@
repeated int64 histogram_counts = 13;
// The dynamic range profile of the stream
- optional int32 dynamic_range_profile = 14;
+ optional int64 dynamic_range_profile = 14;
// The stream use case
optional int32 stream_use_case = 15;
}
diff --git a/services/Android.bp b/services/Android.bp
index 2e4405f..dfc88f1 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -88,7 +88,6 @@
":services.appwidget-sources",
":services.autofill-sources",
":services.backup-sources",
- ":services.bluetooth-sources", // TODO(b/214988855) : Remove once apex/service-bluetooth jar is ready
":backuplib-sources",
":services.cloudsearch-sources",
":services.companion-sources",
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
index 59c1461..aba32ec 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
@@ -667,6 +667,10 @@
return null;
}
+ // Don't need to add the embedded hierarchy windows into the accessibility windows list.
+ if (mHostEmbeddedMap.size() > 0 && isEmbeddedHierarchyWindowsLocked(windowId)) {
+ return null;
+ }
final AccessibilityWindowInfo reportedWindow = AccessibilityWindowInfo.obtain();
reportedWindow.setId(windowId);
@@ -699,6 +703,21 @@
return reportedWindow;
}
+ private boolean isEmbeddedHierarchyWindowsLocked(int windowId) {
+ final IBinder leashToken = mWindowIdMap.get(windowId);
+ if (leashToken == null) {
+ return false;
+ }
+
+ for (int i = 0; i < mHostEmbeddedMap.size(); i++) {
+ if (mHostEmbeddedMap.keyAt(i).equals(leashToken)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
private int getTypeForWindowManagerWindowType(int windowType) {
switch (windowType) {
case WindowManager.LayoutParams.TYPE_APPLICATION:
diff --git a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
index 2b7b977..bf8b18c 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.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 @@
// 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/CompanionApplicationController.java b/services/companion/java/com/android/server/companion/CompanionApplicationController.java
index c39b59a..ec4bfe0 100644
--- a/services/companion/java/com/android/server/companion/CompanionApplicationController.java
+++ b/services/companion/java/com/android/server/companion/CompanionApplicationController.java
@@ -118,13 +118,14 @@
serviceConnectors = CollectionUtils.map(companionServices, componentName ->
new CompanionDeviceServiceConnector(mContext, userId, componentName));
- mBoundCompanionApplications.setValueForPackage(userId, packageName, serviceConnectors);
- }
- if (serviceConnectors.isEmpty()) {
- Slog.e(TAG, "Can't find CompanionDeviceService implementer in package: "
- + packageName + ". Please check if they are correctly declared.");
- return;
+ if (serviceConnectors.isEmpty()) {
+ Slog.e(TAG, "Can't find CompanionDeviceService implementer in package: "
+ + packageName + ". Please check if they are correctly declared.");
+ return;
+ }
+
+ mBoundCompanionApplications.setValueForPackage(userId, packageName, serviceConnectors);
}
// The first connector in the list is always the primary connector: set a listener to it.
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 bc1f28d..b991ba8 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.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 @@
@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 @@
* @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 @@
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/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
index c0a904f..dbb48ae 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -505,6 +505,7 @@
getAllowedUserHandles(),
mParams.getAllowedActivities(),
mParams.getBlockedActivities(),
+ mParams.getDefaultActivityPolicy(),
createListenerAdapter(displayId),
activityInfo -> onActivityBlocked(displayId, activityInfo));
mWindowPolicyControllers.put(displayId, dwpc);
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 561009f..a2b289c 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -103,7 +103,6 @@
":android.hardware.biometrics.face-V2-java-source",
":statslog-art-java-gen",
":statslog-contexthub-java-gen",
- ":services.bluetooth-sources", // TODO(b/214988855) : Remove once apex is ready
":services.core-sources",
":services.core.protologsrc",
":dumpstate_aidl",
diff --git a/services/core/java/com/android/server/SystemServiceManager.java b/services/core/java/com/android/server/SystemServiceManager.java
index 12e438d..78df983 100644
--- a/services/core/java/com/android/server/SystemServiceManager.java
+++ b/services/core/java/com/android/server/SystemServiceManager.java
@@ -21,6 +21,8 @@
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
import android.content.pm.UserInfo;
import android.os.Environment;
import android.os.SystemClock;
@@ -38,6 +40,7 @@
import com.android.server.SystemService.TargetUser;
import com.android.server.SystemService.UserCompletedEventType;
import com.android.server.am.EventLogTags;
+import com.android.server.pm.ApexManager;
import com.android.server.pm.UserManagerInternal;
import com.android.server.utils.TimingsTraceAndSlog;
@@ -47,6 +50,8 @@
import java.io.PrintWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -147,12 +152,31 @@
* @return The service instance.
*/
public SystemService startServiceFromJar(String className, String path) {
- PathClassLoader pathClassLoader = SystemServerClassLoaderFactory.getOrCreateClassLoader(
- path, this.getClass().getClassLoader());
+ PathClassLoader pathClassLoader =
+ SystemServerClassLoaderFactory.getOrCreateClassLoader(
+ path, this.getClass().getClassLoader(), isJarInTestApex(path));
final Class<SystemService> serviceClass = loadClassFromLoader(className, pathClassLoader);
return startService(serviceClass);
}
+ /**
+ * Returns true if the jar is in a test APEX.
+ */
+ private static boolean isJarInTestApex(String pathStr) {
+ Path path = Paths.get(pathStr);
+ if (path.getNameCount() >= 2 && path.getName(0).toString().equals("apex")) {
+ String apexModuleName = path.getName(1).toString();
+ ApexManager apexManager = ApexManager.getInstance();
+ String packageName = apexManager.getActivePackageNameForApexModuleName(apexModuleName);
+ PackageInfo packageInfo = apexManager.getPackageInfo(
+ packageName, ApexManager.MATCH_ACTIVE_PACKAGE);
+ if (packageInfo != null) {
+ return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_TEST_ONLY) != 0;
+ }
+ }
+ return false;
+ }
+
/*
* Loads and initializes a class from the given classLoader. Returns the class.
*/
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index efbc4de..40ab0c0 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -651,100 +651,102 @@
}
private void onMultiSimConfigChanged() {
- int oldNumPhones = mNumPhones;
- mNumPhones = getTelephonyManager().getActiveModemCount();
- if (oldNumPhones == mNumPhones) return;
+ synchronized (mRecords) {
+ int oldNumPhones = mNumPhones;
+ mNumPhones = getTelephonyManager().getActiveModemCount();
+ if (oldNumPhones == mNumPhones) return;
- if (DBG) {
- log("TelephonyRegistry: activeModemCount changed from " + oldNumPhones
- + " to " + mNumPhones);
- }
- mCallState = copyOf(mCallState, mNumPhones);
- mDataActivity = copyOf(mCallState, mNumPhones);
- mDataConnectionState = copyOf(mCallState, mNumPhones);
- mDataConnectionNetworkType = copyOf(mCallState, mNumPhones);
- mCallIncomingNumber = copyOf(mCallIncomingNumber, mNumPhones);
- mServiceState = copyOf(mServiceState, mNumPhones);
- mVoiceActivationState = copyOf(mVoiceActivationState, mNumPhones);
- mDataActivationState = copyOf(mDataActivationState, mNumPhones);
- mUserMobileDataState = copyOf(mUserMobileDataState, mNumPhones);
- if (mSignalStrength != null) {
- mSignalStrength = copyOf(mSignalStrength, mNumPhones);
- } else {
- mSignalStrength = new SignalStrength[mNumPhones];
- }
- mMessageWaiting = copyOf(mMessageWaiting, mNumPhones);
- mCallForwarding = copyOf(mCallForwarding, mNumPhones);
- mCellIdentity = copyOf(mCellIdentity, mNumPhones);
- mSrvccState = copyOf(mSrvccState, mNumPhones);
- mPreciseCallState = copyOf(mPreciseCallState, mNumPhones);
- mForegroundCallState = copyOf(mForegroundCallState, mNumPhones);
- mBackgroundCallState = copyOf(mBackgroundCallState, mNumPhones);
- mRingingCallState = copyOf(mRingingCallState, mNumPhones);
- mCallDisconnectCause = copyOf(mCallDisconnectCause, mNumPhones);
- mCallPreciseDisconnectCause = copyOf(mCallPreciseDisconnectCause, mNumPhones);
- mCallQuality = copyOf(mCallQuality, mNumPhones);
- mCallNetworkType = copyOf(mCallNetworkType, mNumPhones);
- mCallAttributes = copyOf(mCallAttributes, mNumPhones);
- mOutgoingCallEmergencyNumber = copyOf(mOutgoingCallEmergencyNumber, mNumPhones);
- mOutgoingSmsEmergencyNumber = copyOf(mOutgoingSmsEmergencyNumber, mNumPhones);
- mTelephonyDisplayInfos = copyOf(mTelephonyDisplayInfos, mNumPhones);
- mCarrierNetworkChangeState = copyOf(mCarrierNetworkChangeState, mNumPhones);
- mIsDataEnabled= copyOf(mIsDataEnabled, mNumPhones);
- mDataEnabledReason = copyOf(mDataEnabledReason, mNumPhones);
- mAllowedNetworkTypeReason = copyOf(mAllowedNetworkTypeReason, mNumPhones);
- mAllowedNetworkTypeValue = copyOf(mAllowedNetworkTypeValue, mNumPhones);
+ if (DBG) {
+ log("TelephonyRegistry: activeModemCount changed from " + oldNumPhones
+ + " to " + mNumPhones);
+ }
+ mCallState = copyOf(mCallState, mNumPhones);
+ mDataActivity = copyOf(mCallState, mNumPhones);
+ mDataConnectionState = copyOf(mCallState, mNumPhones);
+ mDataConnectionNetworkType = copyOf(mCallState, mNumPhones);
+ mCallIncomingNumber = copyOf(mCallIncomingNumber, mNumPhones);
+ mServiceState = copyOf(mServiceState, mNumPhones);
+ mVoiceActivationState = copyOf(mVoiceActivationState, mNumPhones);
+ mDataActivationState = copyOf(mDataActivationState, mNumPhones);
+ mUserMobileDataState = copyOf(mUserMobileDataState, mNumPhones);
+ if (mSignalStrength != null) {
+ mSignalStrength = copyOf(mSignalStrength, mNumPhones);
+ } else {
+ mSignalStrength = new SignalStrength[mNumPhones];
+ }
+ mMessageWaiting = copyOf(mMessageWaiting, mNumPhones);
+ mCallForwarding = copyOf(mCallForwarding, mNumPhones);
+ mCellIdentity = copyOf(mCellIdentity, mNumPhones);
+ mSrvccState = copyOf(mSrvccState, mNumPhones);
+ mPreciseCallState = copyOf(mPreciseCallState, mNumPhones);
+ mForegroundCallState = copyOf(mForegroundCallState, mNumPhones);
+ mBackgroundCallState = copyOf(mBackgroundCallState, mNumPhones);
+ mRingingCallState = copyOf(mRingingCallState, mNumPhones);
+ mCallDisconnectCause = copyOf(mCallDisconnectCause, mNumPhones);
+ mCallPreciseDisconnectCause = copyOf(mCallPreciseDisconnectCause, mNumPhones);
+ mCallQuality = copyOf(mCallQuality, mNumPhones);
+ mCallNetworkType = copyOf(mCallNetworkType, mNumPhones);
+ mCallAttributes = copyOf(mCallAttributes, mNumPhones);
+ mOutgoingCallEmergencyNumber = copyOf(mOutgoingCallEmergencyNumber, mNumPhones);
+ mOutgoingSmsEmergencyNumber = copyOf(mOutgoingSmsEmergencyNumber, mNumPhones);
+ mTelephonyDisplayInfos = copyOf(mTelephonyDisplayInfos, mNumPhones);
+ mCarrierNetworkChangeState = copyOf(mCarrierNetworkChangeState, mNumPhones);
+ mIsDataEnabled = copyOf(mIsDataEnabled, mNumPhones);
+ mDataEnabledReason = copyOf(mDataEnabledReason, mNumPhones);
+ mAllowedNetworkTypeReason = copyOf(mAllowedNetworkTypeReason, mNumPhones);
+ mAllowedNetworkTypeValue = copyOf(mAllowedNetworkTypeValue, mNumPhones);
- // ds -> ss switch.
- if (mNumPhones < oldNumPhones) {
- cutListToSize(mCellInfo, mNumPhones);
- cutListToSize(mImsReasonInfo, mNumPhones);
- cutListToSize(mPreciseDataConnectionStates, mNumPhones);
- cutListToSize(mBarringInfo, mNumPhones);
- cutListToSize(mPhysicalChannelConfigs, mNumPhones);
- cutListToSize(mLinkCapacityEstimateLists, mNumPhones);
- cutListToSize(mCarrierPrivilegeStates, mNumPhones);
- return;
- }
+ // ds -> ss switch.
+ if (mNumPhones < oldNumPhones) {
+ cutListToSize(mCellInfo, mNumPhones);
+ cutListToSize(mImsReasonInfo, mNumPhones);
+ cutListToSize(mPreciseDataConnectionStates, mNumPhones);
+ cutListToSize(mBarringInfo, mNumPhones);
+ cutListToSize(mPhysicalChannelConfigs, mNumPhones);
+ cutListToSize(mLinkCapacityEstimateLists, mNumPhones);
+ cutListToSize(mCarrierPrivilegeStates, mNumPhones);
+ return;
+ }
- // mNumPhones > oldNumPhones: ss -> ds switch
- for (int i = oldNumPhones; i < mNumPhones; i++) {
- mCallState[i] = TelephonyManager.CALL_STATE_IDLE;
- mDataActivity[i] = TelephonyManager.DATA_ACTIVITY_NONE;
- mDataConnectionState[i] = TelephonyManager.DATA_UNKNOWN;
- mVoiceActivationState[i] = TelephonyManager.SIM_ACTIVATION_STATE_UNKNOWN;
- mDataActivationState[i] = TelephonyManager.SIM_ACTIVATION_STATE_UNKNOWN;
- mCallIncomingNumber[i] = "";
- mServiceState[i] = new ServiceState();
- mSignalStrength[i] = null;
- mUserMobileDataState[i] = false;
- mMessageWaiting[i] = false;
- mCallForwarding[i] = false;
- mCellIdentity[i] = null;
- mCellInfo.add(i, null);
- mImsReasonInfo.add(i, null);
- mSrvccState[i] = TelephonyManager.SRVCC_STATE_HANDOVER_NONE;
- mCallDisconnectCause[i] = DisconnectCause.NOT_VALID;
- mCallPreciseDisconnectCause[i] = PreciseDisconnectCause.NOT_VALID;
- mCallQuality[i] = createCallQuality();
- mCallAttributes[i] = new CallAttributes(createPreciseCallState(),
- TelephonyManager.NETWORK_TYPE_UNKNOWN, createCallQuality());
- mCallNetworkType[i] = TelephonyManager.NETWORK_TYPE_UNKNOWN;
- mPreciseCallState[i] = createPreciseCallState();
- mRingingCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
- mForegroundCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
- mBackgroundCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
- mPreciseDataConnectionStates.add(new ArrayMap<>());
- mBarringInfo.add(i, new BarringInfo());
- mCarrierNetworkChangeState[i] = false;
- mTelephonyDisplayInfos[i] = null;
- mIsDataEnabled[i] = false;
- mDataEnabledReason[i] = TelephonyManager.DATA_ENABLED_REASON_USER;
- mPhysicalChannelConfigs.add(i, new ArrayList<>());
- mAllowedNetworkTypeReason[i] = -1;
- mAllowedNetworkTypeValue[i] = -1;
- mLinkCapacityEstimateLists.add(i, INVALID_LCE_LIST);
- mCarrierPrivilegeStates.add(i, new Pair<>(Collections.emptyList(), new int[0]));
+ // mNumPhones > oldNumPhones: ss -> ds switch
+ for (int i = oldNumPhones; i < mNumPhones; i++) {
+ mCallState[i] = TelephonyManager.CALL_STATE_IDLE;
+ mDataActivity[i] = TelephonyManager.DATA_ACTIVITY_NONE;
+ mDataConnectionState[i] = TelephonyManager.DATA_UNKNOWN;
+ mVoiceActivationState[i] = TelephonyManager.SIM_ACTIVATION_STATE_UNKNOWN;
+ mDataActivationState[i] = TelephonyManager.SIM_ACTIVATION_STATE_UNKNOWN;
+ mCallIncomingNumber[i] = "";
+ mServiceState[i] = new ServiceState();
+ mSignalStrength[i] = null;
+ mUserMobileDataState[i] = false;
+ mMessageWaiting[i] = false;
+ mCallForwarding[i] = false;
+ mCellIdentity[i] = null;
+ mCellInfo.add(i, null);
+ mImsReasonInfo.add(i, null);
+ mSrvccState[i] = TelephonyManager.SRVCC_STATE_HANDOVER_NONE;
+ mCallDisconnectCause[i] = DisconnectCause.NOT_VALID;
+ mCallPreciseDisconnectCause[i] = PreciseDisconnectCause.NOT_VALID;
+ mCallQuality[i] = createCallQuality();
+ mCallAttributes[i] = new CallAttributes(createPreciseCallState(),
+ TelephonyManager.NETWORK_TYPE_UNKNOWN, createCallQuality());
+ mCallNetworkType[i] = TelephonyManager.NETWORK_TYPE_UNKNOWN;
+ mPreciseCallState[i] = createPreciseCallState();
+ mRingingCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
+ mForegroundCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
+ mBackgroundCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
+ mPreciseDataConnectionStates.add(new ArrayMap<>());
+ mBarringInfo.add(i, new BarringInfo());
+ mCarrierNetworkChangeState[i] = false;
+ mTelephonyDisplayInfos[i] = null;
+ mIsDataEnabled[i] = false;
+ mDataEnabledReason[i] = TelephonyManager.DATA_ENABLED_REASON_USER;
+ mPhysicalChannelConfigs.add(i, new ArrayList<>());
+ mAllowedNetworkTypeReason[i] = -1;
+ mAllowedNetworkTypeValue[i] = -1;
+ mLinkCapacityEstimateLists.add(i, INVALID_LCE_LIST);
+ mCarrierPrivilegeStates.add(i, new Pair<>(Collections.emptyList(), new int[0]));
+ }
}
}
@@ -2802,11 +2804,11 @@
+ " callback=" + callback
+ " callback.asBinder=" + callback.asBinder());
}
- if (!validatePhoneId(phoneId)) {
- throw new IllegalArgumentException("Invalid slot index: " + phoneId);
- }
synchronized (mRecords) {
+ if (!validatePhoneId(phoneId)) {
+ throw new IllegalArgumentException("Invalid slot index: " + phoneId);
+ }
Record r = add(
callback.asBinder(), Binder.getCallingUid(), Binder.getCallingPid(), false);
@@ -2851,7 +2853,6 @@
if (!checkNotifyPermission("notifyCarrierPrivilegesChanged")) {
return;
}
- if (!validatePhoneId(phoneId)) return;
if (VDBG) {
log(
"notifyCarrierPrivilegesChanged: phoneId=" + phoneId
@@ -2859,6 +2860,9 @@
+ ", uids=" + Arrays.toString(privilegedUids) + ">");
}
synchronized (mRecords) {
+ if (!validatePhoneId(phoneId)) {
+ throw new IllegalArgumentException("Invalid slot index: " + phoneId);
+ }
mCarrierPrivilegeStates.set(
phoneId, new Pair<>(privilegedPackageNames, privilegedUids));
for (Record r : mRecords) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 6813f3f8..20a8509 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -694,12 +694,6 @@
return (isFg) ? mFgBroadcastQueue : mBgBroadcastQueue;
}
- /**
- * The package name of the DeviceOwner. This package is not permitted to have its data cleared.
- * <p>Not actually used</p>
- */
- private volatile String mDeviceOwnerName;
-
private volatile int mDeviceOwnerUid = INVALID_UID;
/**
@@ -6238,17 +6232,6 @@
}
@Override
- public void updateDeviceOwner(String packageName) {
- final int callingUid = Binder.getCallingUid();
- if (callingUid != 0 && callingUid != SYSTEM_UID) {
- throw new SecurityException("updateDeviceOwner called from non-system process");
- }
- synchronized (this) {
- mDeviceOwnerName = packageName;
- }
- }
-
- @Override
public void updateLockTaskPackages(int userId, String[] packages) {
mActivityTaskManager.updateLockTaskPackages(userId, packages);
}
@@ -9172,10 +9155,14 @@
}
mComponentAliasResolver.dump(pw);
}
- if (dumpAll) {
- pw.println("-------------------------------------------------------------------------------");
- mAppRestrictionController.dump(pw, "");
- }
+ }
+
+ /**
+ * Dump the app restriction controller, it's required not to hold the global lock here.
+ */
+ private void dumpAppRestrictionController(PrintWriter pw) {
+ pw.println("-------------------------------------------------------------------------------");
+ mAppRestrictionController.dump(pw, "");
}
/**
@@ -9193,6 +9180,7 @@
boolean dumpVisibleStacksOnly = false;
boolean dumpFocusedStackOnly = false;
String dumpPackage = null;
+ int dumpUserId = UserHandle.USER_ALL;
int opti = 0;
while (opti < args.length) {
@@ -9224,6 +9212,17 @@
dumpCheckinFormat = true;
} else if ("--normal-priority".equals(opt)) {
dumpNormalPriority = true;
+ } else if ("--user".equals(opt)) {
+ if (opti < args.length) {
+ dumpUserId = UserHandle.parseUserArg(args[opti]);
+ if (dumpUserId == UserHandle.USER_CURRENT) {
+ dumpUserId = mUserController.getCurrentUserId();
+ }
+ opti++;
+ } else {
+ pw.println("Error: --user option requires user id argument");
+ return;
+ }
} else if ("-h".equals(opt)) {
ActivityManagerShellCommand.dumpHelp(pw, true);
return;
@@ -9414,29 +9413,17 @@
} else if ("service".equals(cmd)) {
String[] newArgs;
String name;
- int[] users = null;
if (opti >= args.length) {
name = null;
newArgs = EMPTY_STRING_ARRAY;
} else {
name = args[opti];
opti++;
- if ("--user".equals(name) && opti < args.length) {
- int userId = UserHandle.parseUserArg(args[opti]);
- opti++;
- if (userId != UserHandle.USER_ALL) {
- if (userId == UserHandle.USER_CURRENT) {
- userId = getCurrentUser().id;
- }
- users = new int[] { userId };
- }
- name = args[opti];
- opti++;
- }
newArgs = new String[args.length - opti];
if (args.length > 2) System.arraycopy(args, opti, newArgs, 0,
args.length - opti);
}
+ int[] users = dumpUserId == UserHandle.USER_ALL ? null : new int[] { dumpUserId };
if (!mServices.dumpService(fd, pw, name, users, newArgs, 0, dumpAll)) {
pw.println("No services match: " + name);
pw.println("Use -h for help.");
@@ -9497,7 +9484,7 @@
} else {
// Dumping a single activity?
if (!mAtmInternal.dumpActivity(fd, pw, cmd, args, opti, dumpAll,
- dumpVisibleStacksOnly, dumpFocusedStackOnly)) {
+ dumpVisibleStacksOnly, dumpFocusedStackOnly, dumpUserId)) {
ActivityManagerShellCommand shell = new ActivityManagerShellCommand(this, true);
int res = shell.exec(this, null, fd, null, args, null,
new ResultReceiver(null));
@@ -9531,6 +9518,9 @@
dumpNormalPriority, dumpAppId, false /* dumpProxies */);
}
}
+ if (dumpAll) {
+ dumpAppRestrictionController(pw);
+ }
}
Binder.restoreCallingIdentity(origId);
}
@@ -14347,7 +14337,8 @@
int match = mContext.getPackageManager().checkSignatures(
ii.targetPackage, ii.packageName);
if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
- if (Build.IS_DEBUGGABLE && (flags & INSTR_FLAG_ALWAYS_CHECK_SIGNATURE) == 0) {
+ if (Build.IS_DEBUGGABLE && (callingUid == Process.ROOT_UID)
+ && (flags & INSTR_FLAG_ALWAYS_CHECK_SIGNATURE) == 0) {
Slog.w(TAG, "Instrumentation test " + ii.packageName
+ " doesn't have a signature matching the target " + ii.targetPackage
+ ", which would not be allowed on the production Android builds");
@@ -15623,24 +15614,20 @@
}
for (int i = 0, size = processes.size(); i < size; i++) {
ProcessRecord app = processes.get(i);
- pw.println(String.format("------ DUMP RESOURCES %s (%s) ------",
+ pw.println(String.format("Resources History for %s (%s)",
app.processName,
app.info.packageName));
pw.flush();
try {
- TransferPipe tp = new TransferPipe();
+ TransferPipe tp = new TransferPipe(" ");
try {
IApplicationThread thread = app.getThread();
if (thread != null) {
app.getThread().dumpResources(tp.getWriteFd(), null);
tp.go(fd.getFileDescriptor(), 2000);
- pw.println(String.format("------ END DUMP RESOURCES %s (%s) ------",
- app.processName,
- app.info.packageName));
- pw.flush();
} else {
pw.println(String.format(
- "------ DUMP RESOURCES %s (%s) failed, no thread ------",
+ " Resources history for %s (%s) failed, no thread",
app.processName,
app.info.packageName));
}
@@ -15648,11 +15635,7 @@
tp.kill();
}
} catch (IOException e) {
- pw.println(String.format(
- "------ EXCEPTION DUMPING RESOURCES for %s (%s): %s ------",
- app.processName,
- app.info.packageName,
- e.getMessage()));
+ pw.println(" " + e.getMessage());
pw.flush();
}
diff --git a/services/core/java/com/android/server/am/AppBatteryTracker.java b/services/core/java/com/android/server/am/AppBatteryTracker.java
index 655e309..7579d2b 100644
--- a/services/core/java/com/android/server/am/AppBatteryTracker.java
+++ b/services/core/java/com/android/server/am/AppBatteryTracker.java
@@ -1531,7 +1531,7 @@
if (excessive) {
if (DEBUG_BACKGROUND_BATTERY_TRACKER) {
- Slog.i(TAG, "Excessive background current drain " + uid
+ Slog.i(TAG, "Excessive background current drain " + uid + " "
+ usage + " (" + usage.percentageToString() + " ) over "
+ TimeUtils.formatDuration(mBgCurrentDrainWindowMs));
}
@@ -1542,7 +1542,7 @@
}
} else {
if (DEBUG_BACKGROUND_BATTERY_TRACKER) {
- Slog.i(TAG, "Background current drain backs to normal " + uid
+ Slog.i(TAG, "Background current drain backs to normal " + uid + " "
+ usage + " (" + usage.percentageToString() + " ) over "
+ TimeUtils.formatDuration(mBgCurrentDrainWindowMs));
}
diff --git a/services/core/java/com/android/server/am/AppRestrictionController.java b/services/core/java/com/android/server/am/AppRestrictionController.java
index 2ffd487..561c10b9 100644
--- a/services/core/java/com/android/server/am/AppRestrictionController.java
+++ b/services/core/java/com/android/server/am/AppRestrictionController.java
@@ -87,7 +87,6 @@
import android.app.ActivityManager.RestrictionLevel;
import android.app.ActivityManagerInternal;
import android.app.ActivityManagerInternal.AppBackgroundRestrictionListener;
-import android.app.ActivityThread;
import android.app.AppOpsManager;
import android.app.IActivityManager;
import android.app.IUidObserver;
@@ -192,7 +191,7 @@
// 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 =
@@ -202,7 +201,7 @@
* 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.
@@ -219,6 +218,7 @@
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;
@@ -257,12 +257,95 @@
final ActivityManagerService mActivityManagerService;
+ private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ switch (intent.getAction()) {
+ case Intent.ACTION_PACKAGE_ADDED: {
+ if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+ final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+ if (uid >= 0) {
+ onUidAdded(uid);
+ }
+ }
+ }
+ // fall through.
+ case Intent.ACTION_PACKAGE_CHANGED: {
+ final String pkgName = intent.getData().getSchemeSpecificPart();
+ final String[] cmpList = intent.getStringArrayExtra(
+ Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST);
+ // If this is PACKAGE_ADDED (cmpList == null), or if it's a whole-package
+ // enable/disable event (cmpList is just the package name itself), drop
+ // our carrier privileged app & system-app caches and let them refresh
+ if (cmpList == null
+ || (cmpList.length == 1 && pkgName.equals(cmpList[0]))) {
+ clearCarrierPrivilegedApps();
+ }
+ } break;
+ case Intent.ACTION_PACKAGE_FULLY_REMOVED: {
+ final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+ final Uri data = intent.getData();
+ String ssp;
+ if (uid >= 0 && data != null
+ && (ssp = data.getSchemeSpecificPart()) != null) {
+ onPackageRemoved(ssp, uid);
+ }
+ } break;
+ case Intent.ACTION_UID_REMOVED: {
+ if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+ final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+ if (uid >= 0) {
+ onUidRemoved(uid);
+ }
+ }
+ } break;
+ case Intent.ACTION_USER_ADDED: {
+ final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+ if (userId >= 0) {
+ onUserAdded(userId);
+ }
+ } break;
+ case Intent.ACTION_USER_STARTED: {
+ final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+ if (userId >= 0) {
+ onUserStarted(userId);
+ }
+ } break;
+ case Intent.ACTION_USER_STOPPED: {
+ final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+ if (userId >= 0) {
+ onUserStopped(userId);
+ }
+ } break;
+ case Intent.ACTION_USER_REMOVED: {
+ final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+ if (userId >= 0) {
+ onUserRemoved(userId);
+ }
+ } break;
+ }
+ }
+ };
+
+ private final BroadcastReceiver mBootReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ switch (intent.getAction()) {
+ case Intent.ACTION_LOCKED_BOOT_COMPLETED: {
+ onLockedBootCompleted();
+ } break;
+ }
+ }
+ };
+
/**
* The restriction levels that each package is on, the levels here are defined in
* {@link android.app.ActivityManager.RESTRICTION_LEVEL_*}.
*/
final class RestrictionSettings {
- @GuardedBy("mLock")
+ @GuardedBy("mSettingsLock")
final SparseArrayMap<String, PkgSettings> mRestrictionLevels = new SparseArrayMap();
final class PkgSettings {
@@ -283,6 +366,7 @@
mCurrentRestrictionLevel = mLastRestrictionLevel = RESTRICTION_LEVEL_UNKNOWN;
}
+ @GuardedBy("mSettingsLock")
@RestrictionLevel int update(@RestrictionLevel int level, int reason, int subReason) {
if (level != mCurrentRestrictionLevel) {
mLastRestrictionLevel = mCurrentRestrictionLevel;
@@ -296,6 +380,7 @@
}
@Override
+ @GuardedBy("mSettingsLock")
public String toString() {
final StringBuilder sb = new StringBuilder(128);
sb.append("RestrictionLevel{");
@@ -313,6 +398,7 @@
return sb.toString();
}
+ @GuardedBy("mSettingsLock")
void dump(PrintWriter pw, @ElapsedRealtimeLong long nowElapsed) {
pw.print(toString());
if (mLastRestrictionLevel != RESTRICTION_LEVEL_UNKNOWN) {
@@ -344,18 +430,22 @@
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) {
@@ -364,6 +454,7 @@
return mLastNotificationShownTimeElapsed[notificationType];
}
+ @GuardedBy("mSettingsLock")
void setLastNotificationTime(@NotificationHelper.NotificationType int notificationType,
@ElapsedRealtimeLong long timestamp) {
if (mLastNotificationShownTimeElapsed == null) {
@@ -373,6 +464,7 @@
mLastNotificationShownTimeElapsed[notificationType] = timestamp;
}
+ @GuardedBy("mSettingsLock")
int getNotificationId(@NotificationHelper.NotificationType int notificationType) {
if (mNotificationId == null) {
return 0;
@@ -380,6 +472,7 @@
return mNotificationId[notificationType];
}
+ @GuardedBy("mSettingsLock")
void setNotificationId(@NotificationHelper.NotificationType int notificationType,
int notificationId) {
if (mNotificationId == null) {
@@ -396,7 +489,7 @@
*/
@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);
@@ -410,7 +503,7 @@
* @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);
@@ -418,7 +511,7 @@
}
@RestrictionLevel int getRestrictionLevel(int uid) {
- synchronized (mLock) {
+ synchronized (mSettingsLock) {
final int uidKeyIndex = mRestrictionLevels.indexOfKey(uid);
if (uidKeyIndex < 0) {
return RESTRICTION_LEVEL_UNKNOWN;
@@ -440,7 +533,7 @@
}
@RestrictionLevel int getRestrictionLevel(int uid, String packageName) {
- synchronized (mLock) {
+ synchronized (mSettingsLock) {
final PkgSettings settings = getRestrictionSettingsLocked(uid, packageName);
return settings == null
? getRestrictionLevel(uid) : settings.getCurrentRestrictionLevel();
@@ -454,14 +547,14 @@
}
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);
@@ -476,20 +569,20 @@
}
}
- @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) {
@@ -501,25 +594,25 @@
}
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")
+ @GuardedBy("mSettingsLock")
void dumpLocked(PrintWriter pw, String prefix) {
final ArrayList<PkgSettings> settings = new ArrayList<>();
mRestrictionLevels.forEach(setting -> settings.add(setting));
@@ -804,7 +897,7 @@
void onSystemReady() {
DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
- ActivityThread.currentApplication().getMainExecutor(), mConstantsObserver);
+ mBgExecutor, mConstantsObserver);
mConstantsObserver.start();
initBgRestrictionExemptioFromSysConfig();
initRestrictionStates();
@@ -826,10 +919,19 @@
@VisibleForTesting
void resetRestrictionSettings() {
- mRestrictionSettings.reset();
+ synchronized (mSettingsLock) {
+ mRestrictionSettings.reset();
+ }
initRestrictionStates();
}
+ @VisibleForTesting
+ void tearDown() {
+ DeviceConfig.removeOnPropertiesChangedListener(mConstantsObserver);
+ unregisterForUidObservers();
+ unregisterForSystemBroadcasts();
+ }
+
private void initBgRestrictionExemptioFromSysConfig() {
mBgRestrictionExemptioFromSysConfig =
SystemConfig.getInstance().getBgRestrictionExemption();
@@ -912,6 +1014,14 @@
}
}
+ private void unregisterForUidObservers() {
+ try {
+ mInjector.getIActivityManager().unregisterUidObserver(mUidObserver);
+ } catch (RemoteException e) {
+ // Intra-process call, it won't happen.
+ }
+ }
+
/**
* Called when initializing a user.
*/
@@ -1212,9 +1322,11 @@
prefix = " " + prefix;
pw.print(prefix);
pw.println("BACKGROUND RESTRICTION LEVEL SETTINGS");
- synchronized (mLock) {
+ /*
+ synchronized (mSettingsLock) {
mRestrictionSettings.dumpLocked(pw, " " + prefix);
}
+ */
mConstantsObserver.dump(pw, " " + prefix);
for (int i = 0, size = mAppStateTrackers.size(); i < size; i++) {
pw.println();
@@ -1226,7 +1338,7 @@
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.
@@ -1264,7 +1376,7 @@
|| 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.
@@ -1282,7 +1394,7 @@
&& 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);
@@ -1340,7 +1452,7 @@
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) {
@@ -1434,6 +1546,7 @@
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() {
@@ -1454,7 +1567,7 @@
}
};
- @GuardedBy("mLock")
+ @GuardedBy("mSettingsLock")
private int mNotificationIDStepper = SUMMARY_NOTIFICATION_ID + 1;
NotificationHelper(AppRestrictionController controller) {
@@ -1462,6 +1575,7 @@
mInjector = controller.mInjector;
mNotificationManager = mInjector.getNotificationManager();
mLock = controller.mLock;
+ mSettingsLock = controller.mSettingsLock;
mContext = mInjector.getContext();
}
@@ -1540,7 +1654,7 @@
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) {
@@ -1644,7 +1758,7 @@
}
void cancelRequestBgRestrictedIfNecessary(String packageName, int uid) {
- synchronized (mLock) {
+ synchronized (mSettingsLock) {
final RestrictionSettings.PkgSettings settings = mBgController.mRestrictionSettings
.getRestrictionSettingsLocked(uid, packageName);
if (settings != null) {
@@ -1658,7 +1772,7 @@
}
void cancelLongRunningFGSNotificationIfNecessary(String packageName, int uid) {
- synchronized (mLock) {
+ synchronized (mSettingsLock) {
final RestrictionSettings.PkgSettings settings = mBgController.mRestrictionSettings
.getRestrictionSettingsLocked(uid, packageName);
if (settings != null) {
@@ -1674,7 +1788,7 @@
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;
@@ -1695,7 +1809,7 @@
}
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) -> {
@@ -2147,104 +2261,28 @@
}
private void registerForSystemBroadcasts() {
- final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- switch (intent.getAction()) {
- case Intent.ACTION_PACKAGE_ADDED: {
- if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
- final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
- if (uid >= 0) {
- onUidAdded(uid);
- }
- }
- }
- // fall through.
- case Intent.ACTION_PACKAGE_CHANGED: {
- final String pkgName = intent.getData().getSchemeSpecificPart();
- final String[] cmpList = intent.getStringArrayExtra(
- Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST);
- // If this is PACKAGE_ADDED (cmpList == null), or if it's a whole-package
- // enable/disable event (cmpList is just the package name itself), drop
- // our carrier privileged app & system-app caches and let them refresh
- if (cmpList == null
- || (cmpList.length == 1 && pkgName.equals(cmpList[0]))) {
- clearCarrierPrivilegedApps();
- }
- } break;
- case Intent.ACTION_PACKAGE_FULLY_REMOVED: {
- final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
- final Uri data = intent.getData();
- String ssp;
- if (uid >= 0 && data != null
- && (ssp = data.getSchemeSpecificPart()) != null) {
- onPackageRemoved(ssp, uid);
- }
- } break;
- case Intent.ACTION_UID_REMOVED: {
- if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
- final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
- if (uid >= 0) {
- onUidRemoved(uid);
- }
- }
- } break;
- case Intent.ACTION_USER_ADDED: {
- final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
- if (userId >= 0) {
- onUserAdded(userId);
- }
- } break;
- case Intent.ACTION_USER_STARTED: {
- final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
- if (userId >= 0) {
- onUserStarted(userId);
- }
- } break;
- case Intent.ACTION_USER_STOPPED: {
- final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
- if (userId >= 0) {
- onUserStopped(userId);
- }
- } break;
- case Intent.ACTION_USER_REMOVED: {
- final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
- if (userId >= 0) {
- onUserRemoved(userId);
- }
- } break;
- }
- }
- };
final IntentFilter packageFilter = new IntentFilter();
packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
packageFilter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
packageFilter.addDataScheme("package");
- mContext.registerReceiverForAllUsers(broadcastReceiver, packageFilter, null, mBgHandler);
+ mContext.registerReceiverForAllUsers(mBroadcastReceiver, packageFilter, null, mBgHandler);
final IntentFilter userFilter = new IntentFilter();
userFilter.addAction(Intent.ACTION_USER_ADDED);
userFilter.addAction(Intent.ACTION_USER_REMOVED);
userFilter.addAction(Intent.ACTION_UID_REMOVED);
- mContext.registerReceiverForAllUsers(broadcastReceiver, userFilter, null, mBgHandler);
- final BroadcastReceiver bootReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- switch (intent.getAction()) {
- case Intent.ACTION_LOCKED_BOOT_COMPLETED: {
- onLockedBootCompleted();
- } break;
- }
- }
- };
+ mContext.registerReceiverForAllUsers(mBroadcastReceiver, userFilter, null, mBgHandler);
final IntentFilter bootFilter = new IntentFilter();
bootFilter.addAction(Intent.ACTION_LOCKED_BOOT_COMPLETED);
- mContext.registerReceiverAsUser(bootReceiver, UserHandle.SYSTEM,
+ mContext.registerReceiverAsUser(mBootReceiver, UserHandle.SYSTEM,
bootFilter, null, mBgHandler);
}
+ private void unregisterForSystemBroadcasts() {
+ mContext.unregisterReceiver(mBroadcastReceiver);
+ mContext.unregisterReceiver(mBootReceiver);
+ }
+
void forEachTracker(Consumer<BaseAppStateTracker> sink) {
for (int i = 0, size = mAppStateTrackers.size(); i < size; i++) {
sink.accept(mAppStateTrackers.get(i));
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 8d77eda..6a211d3 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -1499,7 +1499,6 @@
int adj;
int schedGroup;
int procState;
- int cachedAdjSeq;
int capability = cycleReEval ? app.mState.getCurCapability() : 0;
boolean foregroundActivities = false;
diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java
index b813bc4..0edbea0 100644
--- a/services/core/java/com/android/server/app/GameManagerService.java
+++ b/services/core/java/com/android/server/app/GameManagerService.java
@@ -90,6 +90,7 @@
import com.android.internal.compat.CompatibilityOverrideConfig;
import com.android.internal.compat.IPlatformCompat;
import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.FrameworkStatsLog;
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemService;
@@ -268,16 +269,34 @@
break;
}
case SET_GAME_STATE: {
- if (mPowerManagerInternal == null) {
- final Bundle data = msg.getData();
- Slog.d(TAG, "Error setting loading mode for package "
- + data.getString(PACKAGE_NAME_MSG_KEY)
- + " and userId " + data.getInt(USER_ID_MSG_KEY));
- break;
- }
final GameState gameState = (GameState) msg.obj;
final boolean isLoading = gameState.isLoading();
- mPowerManagerInternal.setPowerMode(Mode.GAME_LOADING, isLoading);
+ final Bundle data = msg.getData();
+ final String packageName = data.getString(PACKAGE_NAME_MSG_KEY);
+ final int userId = data.getInt(USER_ID_MSG_KEY);
+
+ // Restrict to games only. Requires performance mode to be enabled.
+ final boolean boostEnabled =
+ getGameMode(packageName, userId) == GameManager.GAME_MODE_PERFORMANCE;
+ int uid;
+ try {
+ uid = mPackageManager.getPackageUidAsUser(packageName, userId);
+ } catch (NameNotFoundException e) {
+ Slog.v(TAG, "Failed to get package metadata");
+ uid = -1;
+ }
+ FrameworkStatsLog.write(FrameworkStatsLog.GAME_STATE_CHANGED, packageName, uid,
+ boostEnabled, gameStateModeToStatsdGameState(gameState.getMode()),
+ isLoading, gameState.getLabel(), gameState.getQuality());
+
+ if (boostEnabled) {
+ if (mPowerManagerInternal == null) {
+ Slog.d(TAG, "Error setting loading mode for package " + packageName
+ + " and userId " + userId);
+ break;
+ }
+ mPowerManagerInternal.setPowerMode(Mode.GAME_LOADING, isLoading);
+ }
break;
}
}
@@ -387,12 +406,6 @@
// Restrict to games only.
return;
}
-
- if (getGameMode(packageName, userId) != GameManager.GAME_MODE_PERFORMANCE) {
- // Requires performance mode to be enabled.
- return;
- }
-
final Message msg = mHandler.obtainMessage(SET_GAME_STATE);
final Bundle data = new Bundle();
data.putString(PACKAGE_NAME_MSG_KEY, packageName);
@@ -1543,6 +1556,22 @@
return out.toString();
}
+ private static int gameStateModeToStatsdGameState(int mode) {
+ switch (mode) {
+ case GameState.MODE_NONE:
+ return FrameworkStatsLog.GAME_STATE_CHANGED__STATE__MODE_NONE;
+ case GameState.MODE_GAMEPLAY_INTERRUPTIBLE:
+ return FrameworkStatsLog.GAME_STATE_CHANGED__STATE__MODE_GAMEPLAY_INTERRUPTIBLE;
+ case GameState.MODE_GAMEPLAY_UNINTERRUPTIBLE:
+ return FrameworkStatsLog.GAME_STATE_CHANGED__STATE__MODE_GAMEPLAY_UNINTERRUPTIBLE;
+ case GameState.MODE_CONTENT:
+ return FrameworkStatsLog.GAME_STATE_CHANGED__STATE__MODE_CONTENT;
+ case GameState.MODE_UNKNOWN:
+ default:
+ return FrameworkStatsLog.GAME_STATE_CHANGED__STATE__MODE_UNKNOWN;
+ }
+ }
+
private static ServiceThread createServiceThread() {
ServiceThread handlerThread = new ServiceThread(TAG,
Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index 3491cd5..49a935e 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -479,6 +479,8 @@
}
if (profile == BluetoothProfile.A2DP) {
mA2dp = (BluetoothA2dp) proxy;
+ } else if (profile == BluetoothProfile.HEARING_AID) {
+ mHearingAid = (BluetoothHearingAid) proxy;
} else if (profile == BluetoothProfile.LE_AUDIO) {
mLeAudio = (BluetoothLeAudio) proxy;
}
diff --git a/services/core/java/com/android/server/audio/TEST_MAPPING b/services/core/java/com/android/server/audio/TEST_MAPPING
index 5a6c6a5..f3a73f0 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/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index f5001102..9bfdd68 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -204,8 +204,8 @@
private static final String PROP_DEFAULT_DISPLAY_TOP_INSET = "persist.sys.displayinset.top";
private static final long WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT = 10000;
// This value needs to be in sync with the threshold
- // in RefreshRateConfigs::getFrameRateDivider.
- private static final float THRESHOLD_FOR_REFRESH_RATES_DIVIDERS = 0.0009f;
+ // in RefreshRateConfigs::getFrameRateDivisor.
+ private static final float THRESHOLD_FOR_REFRESH_RATES_DIVISORS = 0.0009f;
private static final int MSG_REGISTER_DEFAULT_DISPLAY_ADAPTERS = 1;
private static final int MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS = 2;
@@ -895,13 +895,13 @@
return info;
}
- // Override the refresh rate only if it is a divider of the current
+ // Override the refresh rate only if it is a divisor of the current
// refresh rate. This calculation needs to be in sync with the native code
- // in RefreshRateConfigs::getFrameRateDivider
+ // in RefreshRateConfigs::getFrameRateDivisor
Display.Mode currentMode = info.getMode();
float numPeriods = currentMode.getRefreshRate() / frameRateHz;
float numPeriodsRound = Math.round(numPeriods);
- if (Math.abs(numPeriods - numPeriodsRound) > THRESHOLD_FOR_REFRESH_RATES_DIVIDERS) {
+ if (Math.abs(numPeriods - numPeriodsRound) > THRESHOLD_FOR_REFRESH_RATES_DIVISORS) {
return info;
}
frameRateHz = currentMode.getRefreshRate() / numPeriodsRound;
@@ -913,9 +913,9 @@
continue;
}
- if (mode.getRefreshRate() >= frameRateHz - THRESHOLD_FOR_REFRESH_RATES_DIVIDERS
+ if (mode.getRefreshRate() >= frameRateHz - THRESHOLD_FOR_REFRESH_RATES_DIVISORS
&& mode.getRefreshRate()
- <= frameRateHz + THRESHOLD_FOR_REFRESH_RATES_DIVIDERS) {
+ <= frameRateHz + THRESHOLD_FOR_REFRESH_RATES_DIVISORS) {
if (DEBUG) {
Slog.d(TAG, "found matching modeId " + mode.getModeId());
}
@@ -2463,7 +2463,7 @@
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 d233c5e..7a0cf4b 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -255,10 +255,9 @@
public boolean updateDisplayPropertiesLocked(SurfaceControl.StaticDisplayInfo staticInfo,
SurfaceControl.DynamicDisplayInfo dynamicInfo,
SurfaceControl.DesiredDisplayModeSpecs modeSpecs) {
- boolean changed =
- updateSystemPreferredDisplayMode(dynamicInfo.preferredBootDisplayMode);
- changed |= updateDisplayModesLocked(
- dynamicInfo.supportedDisplayModes, dynamicInfo.activeDisplayModeId, modeSpecs);
+ boolean changed = updateDisplayModesLocked(
+ dynamicInfo.supportedDisplayModes, dynamicInfo.preferredBootDisplayMode,
+ dynamicInfo.activeDisplayModeId, modeSpecs);
changed |= updateStaticInfo(staticInfo);
changed |= updateColorModesLocked(dynamicInfo.supportedColorModes,
dynamicInfo.activeColorMode);
@@ -273,10 +272,12 @@
}
public boolean updateDisplayModesLocked(
- SurfaceControl.DisplayMode[] displayModes, int activeDisplayModeId,
- SurfaceControl.DesiredDisplayModeSpecs modeSpecs) {
+ SurfaceControl.DisplayMode[] displayModes, int preferredSfDisplayModeId,
+ int activeSfDisplayModeId, SurfaceControl.DesiredDisplayModeSpecs modeSpecs) {
mSfDisplayModes = Arrays.copyOf(displayModes, displayModes.length);
- mActiveSfDisplayMode = getModeById(displayModes, activeDisplayModeId);
+ mActiveSfDisplayMode = getModeById(displayModes, activeSfDisplayModeId);
+ SurfaceControl.DisplayMode preferredSfDisplayMode =
+ getModeById(displayModes, preferredSfDisplayModeId);
// Build an updated list of all existing modes.
ArrayList<DisplayModeRecord> records = new ArrayList<>();
@@ -335,6 +336,27 @@
}
}
+ boolean preferredModeChanged = false;
+
+ if (preferredSfDisplayModeId != INVALID_MODE_ID && preferredSfDisplayMode != null) {
+ DisplayModeRecord preferredRecord = null;
+ for (DisplayModeRecord record : records) {
+ if (record.hasMatchingMode(preferredSfDisplayMode)) {
+ preferredRecord = record;
+ break;
+ }
+ }
+
+ if (preferredRecord != null) {
+ int preferredModeId = preferredRecord.mMode.getModeId();
+ if (mSurfaceControlProxy.getBootDisplayModeSupport()
+ && mSystemPreferredModeId != preferredModeId) {
+ mSystemPreferredModeId = preferredModeId;
+ preferredModeChanged = true;
+ }
+ }
+ }
+
boolean activeModeChanged = false;
// Check whether SurfaceFlinger or the display device changed the active mode out from
@@ -373,7 +395,7 @@
boolean recordsChanged = records.size() != mSupportedModes.size() || modesAdded;
// If the records haven't changed then we're done here.
if (!recordsChanged) {
- return activeModeChanged;
+ return activeModeChanged || preferredModeChanged;
}
mSupportedModes.clear();
@@ -386,14 +408,14 @@
mDefaultModeId = mSystemPreferredModeId != INVALID_MODE_ID
? mSystemPreferredModeId : activeRecord.mMode.getModeId();
mDefaultModeGroup = mSystemPreferredModeId != INVALID_MODE_ID
- ? getModeById(mSfDisplayModes, mSystemPreferredModeId).group
+ ? preferredSfDisplayMode.group
: mActiveSfDisplayMode.group;
} else if (modesAdded && activeModeChanged) {
Slog.d(TAG, "New display modes are added and the active mode has changed, "
+ "use active mode as default mode.");
mDefaultModeId = activeRecord.mMode.getModeId();
mDefaultModeGroup = mActiveSfDisplayMode.group;
- } else if (findDisplayModeIdLocked(mDefaultModeId, mDefaultModeGroup) < 0) {
+ } else if (findSfDisplayModeIdLocked(mDefaultModeId, mDefaultModeGroup) < 0) {
Slog.w(TAG, "Default display mode no longer available, using currently"
+ " active mode as default.");
mDefaultModeId = activeRecord.mMode.getModeId();
@@ -545,15 +567,6 @@
return true;
}
- private boolean updateSystemPreferredDisplayMode(int modeId) {
- if (!mSurfaceControlProxy.getBootDisplayModeSupport()
- || mSystemPreferredModeId == modeId) {
- return false;
- }
- mSystemPreferredModeId = modeId;
- return true;
- }
-
private SurfaceControl.DisplayMode getModeById(SurfaceControl.DisplayMode[] supportedModes,
int modeId) {
for (SurfaceControl.DisplayMode mode : supportedModes) {
@@ -871,24 +884,32 @@
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(
+ mUserPreferredMode.getModeId(), mDefaultModeGroup);
mSurfaceControlProxy.setBootDisplayMode(getDisplayTokenLocked(),
- mUserPreferredMode.getModeId());
+ preferredSfDisplayModeId);
}
}
@@ -923,9 +944,9 @@
// mode based on vendor requirements.
// Note: We prefer the default mode group over the current one as this is the mode
// group the vendor prefers.
- int baseModeId = findDisplayModeIdLocked(displayModeSpecs.baseModeId,
+ int baseSfModeId = findSfDisplayModeIdLocked(displayModeSpecs.baseModeId,
mDefaultModeGroup);
- if (baseModeId < 0) {
+ if (baseSfModeId < 0) {
// When a display is hotplugged, it's possible for a mode to be removed that was
// previously valid. Because of the way display changes are propagated through the
// framework, and the caching of the display mode specs in LogicalDisplay, it's
@@ -943,7 +964,7 @@
getHandler().sendMessage(PooledLambda.obtainMessage(
LocalDisplayDevice::setDesiredDisplayModeSpecsAsync, this,
getDisplayTokenLocked(),
- new SurfaceControl.DesiredDisplayModeSpecs(baseModeId,
+ new SurfaceControl.DesiredDisplayModeSpecs(baseSfModeId,
mDisplayModeSpecs.allowGroupSwitching,
mDisplayModeSpecs.primaryRefreshRateRange.min,
mDisplayModeSpecs.primaryRefreshRateRange.max,
@@ -1090,14 +1111,14 @@
pw.println("mDisplayDeviceConfig=" + mDisplayDeviceConfig);
}
- private int findDisplayModeIdLocked(int modeId, int modeGroup) {
- int matchingModeId = INVALID_MODE_ID;
- DisplayModeRecord record = mSupportedModes.get(modeId);
+ private int findSfDisplayModeIdLocked(int displayModeId, int modeGroup) {
+ int matchingSfDisplayModeId = INVALID_MODE_ID;
+ DisplayModeRecord record = mSupportedModes.get(displayModeId);
if (record != null) {
for (SurfaceControl.DisplayMode mode : mSfDisplayModes) {
if (record.hasMatchingMode(mode)) {
- if (matchingModeId == INVALID_MODE_ID) {
- matchingModeId = mode.id;
+ if (matchingSfDisplayModeId == INVALID_MODE_ID) {
+ matchingSfDisplayModeId = mode.id;
}
// Prefer to return a mode that matches the modeGroup
@@ -1107,7 +1128,7 @@
}
}
}
- return matchingModeId;
+ return matchingSfDisplayModeId;
}
// Returns a mode with id = modeId.
diff --git a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java
index fb36dc7..d04b5a2 100644
--- a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java
+++ b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java
@@ -346,6 +346,7 @@
writer.println("DisplayWhiteBalanceController");
writer.println(" mLoggingEnabled=" + mLoggingEnabled);
writer.println(" mEnabled=" + mEnabled);
+ writer.println(" mStrongModeEnabled=" + mStrongModeEnabled);
writer.println(" mDisplayPowerControllerCallbacks=" + mDisplayPowerControllerCallbacks);
mBrightnessSensor.dump(writer);
mBrightnessFilter.dump(writer);
diff --git a/services/core/java/com/android/server/dreams/DreamController.java b/services/core/java/com/android/server/dreams/DreamController.java
index 76754d3..4a1a950 100644
--- a/services/core/java/com/android/server/dreams/DreamController.java
+++ b/services/core/java/com/android/server/dreams/DreamController.java
@@ -104,7 +104,7 @@
pw.println(" mCurrentDream:");
pw.println(" mToken=" + mCurrentDream.mToken);
pw.println(" mName=" + mCurrentDream.mName);
- pw.println(" mIsTest=" + mCurrentDream.mIsTest);
+ pw.println(" mIsPreviewMode=" + mCurrentDream.mIsPreviewMode);
pw.println(" mCanDoze=" + mCurrentDream.mCanDoze);
pw.println(" mUserId=" + mCurrentDream.mUserId);
pw.println(" mBound=" + mCurrentDream.mBound);
@@ -117,7 +117,7 @@
}
public void startDream(Binder token, ComponentName name,
- boolean isTest, boolean canDoze, int userId, PowerManager.WakeLock wakeLock,
+ boolean isPreviewMode, boolean canDoze, int userId, PowerManager.WakeLock wakeLock,
ComponentName overlayComponentName) {
stopDream(true /*immediate*/, "starting new dream");
@@ -127,10 +127,10 @@
mContext.sendBroadcastAsUser(mCloseNotificationShadeIntent, UserHandle.ALL);
Slog.i(TAG, "Starting dream: name=" + name
- + ", isTest=" + isTest + ", canDoze=" + canDoze
+ + ", isPreviewMode=" + isPreviewMode + ", canDoze=" + canDoze
+ ", userId=" + userId);
- mCurrentDream = new DreamRecord(token, name, isTest, canDoze, userId, wakeLock);
+ mCurrentDream = new DreamRecord(token, name, isPreviewMode, canDoze, userId, wakeLock);
mDreamStartTime = SystemClock.elapsedRealtime();
MetricsLogger.visible(mContext,
@@ -140,6 +140,7 @@
intent.setComponent(name);
intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
intent.putExtra(DreamService.EXTRA_DREAM_OVERLAY_COMPONENT, overlayComponentName);
+ intent.putExtra(DreamService.EXTRA_IS_PREVIEW, isPreviewMode);
try {
if (!mContext.bindServiceAsUser(intent, mCurrentDream,
Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
@@ -190,7 +191,8 @@
final DreamRecord oldDream = mCurrentDream;
mCurrentDream = null;
Slog.i(TAG, "Stopping dream: name=" + oldDream.mName
- + ", isTest=" + oldDream.mIsTest + ", canDoze=" + oldDream.mCanDoze
+ + ", isPreviewMode=" + oldDream.mIsPreviewMode
+ + ", canDoze=" + oldDream.mCanDoze
+ ", userId=" + oldDream.mUserId
+ ", reason='" + reason + "'"
+ (mSavedStopReason == null ? "" : "(from '" + mSavedStopReason + "')"));
@@ -247,7 +249,7 @@
mCurrentDream.mService = service;
- if (!mCurrentDream.mIsTest) {
+ if (!mCurrentDream.mIsPreviewMode) {
mContext.sendBroadcastAsUser(mDreamingStartedIntent, UserHandle.ALL);
mCurrentDream.mSentStartBroadcast = true;
}
@@ -263,7 +265,7 @@
private final class DreamRecord implements DeathRecipient, ServiceConnection {
public final Binder mToken;
public final ComponentName mName;
- public final boolean mIsTest;
+ public final boolean mIsPreviewMode;
public final boolean mCanDoze;
public final int mUserId;
@@ -275,11 +277,11 @@
public boolean mWakingGently;
- public DreamRecord(Binder token, ComponentName name,
- boolean isTest, boolean canDoze, int userId, PowerManager.WakeLock wakeLock) {
+ DreamRecord(Binder token, ComponentName name, boolean isPreviewMode,
+ boolean canDoze, int userId, PowerManager.WakeLock wakeLock) {
mToken = token;
mName = name;
- mIsTest = isTest;
+ mIsPreviewMode = isPreviewMode;
mCanDoze = canDoze;
mUserId = userId;
mWakeLock = wakeLock;
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index f0a6af3..22d32a6 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -87,7 +87,7 @@
private Binder mCurrentDreamToken;
private ComponentName mCurrentDreamName;
private int mCurrentDreamUserId;
- private boolean mCurrentDreamIsTest;
+ private boolean mCurrentDreamIsPreview;
private boolean mCurrentDreamCanDoze;
private boolean mCurrentDreamIsDozing;
private boolean mCurrentDreamIsWaking;
@@ -169,7 +169,7 @@
pw.println("mCurrentDreamToken=" + mCurrentDreamToken);
pw.println("mCurrentDreamName=" + mCurrentDreamName);
pw.println("mCurrentDreamUserId=" + mCurrentDreamUserId);
- pw.println("mCurrentDreamIsTest=" + mCurrentDreamIsTest);
+ pw.println("mCurrentDreamIsPreview=" + mCurrentDreamIsPreview);
pw.println("mCurrentDreamCanDoze=" + mCurrentDreamCanDoze);
pw.println("mCurrentDreamIsDozing=" + mCurrentDreamIsDozing);
pw.println("mCurrentDreamIsWaking=" + mCurrentDreamIsWaking);
@@ -190,7 +190,7 @@
private boolean isDreamingInternal() {
synchronized (mLock) {
- return mCurrentDreamToken != null && !mCurrentDreamIsTest
+ return mCurrentDreamToken != null && !mCurrentDreamIsPreview
&& !mCurrentDreamIsWaking;
}
}
@@ -235,7 +235,7 @@
private void testDreamInternal(ComponentName dream, int userId) {
synchronized (mLock) {
- startDreamLocked(dream, true /*isTest*/, false /*canDoze*/, userId);
+ startDreamLocked(dream, true /*isPreviewMode*/, false /*canDoze*/, userId);
}
}
@@ -244,7 +244,7 @@
final ComponentName dream = chooseDreamForUser(doze, userId);
if (dream != null) {
synchronized (mLock) {
- startDreamLocked(dream, false /*isTest*/, doze, userId);
+ startDreamLocked(dream, false /*isPreviewMode*/, doze, userId);
}
}
}
@@ -395,10 +395,10 @@
}
private void startDreamLocked(final ComponentName name,
- final boolean isTest, final boolean canDoze, final int userId) {
+ final boolean isPreviewMode, final boolean canDoze, final int userId) {
if (!mCurrentDreamIsWaking
&& Objects.equals(mCurrentDreamName, name)
- && mCurrentDreamIsTest == isTest
+ && mCurrentDreamIsPreview == isPreviewMode
&& mCurrentDreamCanDoze == canDoze
&& mCurrentDreamUserId == userId) {
Slog.i(TAG, "Already in target dream.");
@@ -412,7 +412,7 @@
final Binder newToken = new Binder();
mCurrentDreamToken = newToken;
mCurrentDreamName = name;
- mCurrentDreamIsTest = isTest;
+ mCurrentDreamIsPreview = isPreviewMode;
mCurrentDreamCanDoze = canDoze;
mCurrentDreamUserId = userId;
@@ -424,7 +424,7 @@
.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "startDream");
mHandler.post(wakeLock.wrap(() -> {
mAtmInternal.notifyDreamStateChanged(true);
- mController.startDream(newToken, name, isTest, canDoze, userId, wakeLock,
+ mController.startDream(newToken, name, isPreviewMode, canDoze, userId, wakeLock,
mDreamOverlayServiceName);
}));
}
@@ -457,7 +457,7 @@
}
mCurrentDreamToken = null;
mCurrentDreamName = null;
- mCurrentDreamIsTest = false;
+ mCurrentDreamIsPreview = false;
mCurrentDreamCanDoze = false;
mCurrentDreamUserId = 0;
mCurrentDreamIsWaking = false;
diff --git a/services/core/java/com/android/server/inputmethod/ImePlatformCompatUtils.java b/services/core/java/com/android/server/inputmethod/ImePlatformCompatUtils.java
new file mode 100644
index 0000000..83ca16d
--- /dev/null
+++ b/services/core/java/com/android/server/inputmethod/ImePlatformCompatUtils.java
@@ -0,0 +1,64 @@
+/*
+ * 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.inputmethod;
+
+import static android.inputmethodservice.InputMethodService.FINISH_INPUT_NO_FALLBACK_CONNECTION;
+import static android.view.inputmethod.InputMethodManager.CLEAR_SHOW_FORCED_FLAG_WHEN_LEAVING;
+
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+import com.android.internal.compat.IPlatformCompat;
+
+/**
+ * A utility class used by {@link InputMethodManagerService} to manage the platform
+ * compatibility changes on IMF (Input Method Framework) side.
+ */
+final class ImePlatformCompatUtils {
+ private final IPlatformCompat mPlatformCompat = IPlatformCompat.Stub.asInterface(
+ ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
+
+ /**
+ * Whether to finish the {@link android.view.inputmethod.InputConnection} when the device
+ * becomes {@link android.os.PowerManager#isInteractive non-interactive}.
+ *
+ * @param imeUid The uid of the IME application
+ */
+ public boolean shouldFinishInputWithReportToIme(int imeUid) {
+ return isChangeEnabledByUid(FINISH_INPUT_NO_FALLBACK_CONNECTION, imeUid);
+ }
+
+ /**
+ * Whether to clear {@link android.view.inputmethod.InputMethodManager#SHOW_FORCED} flag
+ * when the next IME focused application changed.
+ *
+ * @param clientUid The uid of the app
+ */
+ public boolean shouldClearShowForcedFlag(int clientUid) {
+ return isChangeEnabledByUid(CLEAR_SHOW_FORCED_FLAG_WHEN_LEAVING, clientUid);
+ }
+
+ private boolean isChangeEnabledByUid(long changeFlag, int uid) {
+ boolean result = false;
+ try {
+ result = mPlatformCompat.isChangeEnabledByUid(changeFlag, uid);
+ } catch (RemoteException e) {
+ }
+ return result;
+ }
+}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
index b2f500a..d2d80ff 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
@@ -408,6 +408,11 @@
@GuardedBy("ImfLock.class")
@NonNull
InputBindResult bindCurrentMethod() {
+ if (mSelectedMethodId == null) {
+ Slog.e(TAG, "mSelectedMethodId is null!");
+ return InputBindResult.NO_IME;
+ }
+
InputMethodInfo info = mMethodMap.get(mSelectedMethodId);
if (info == null) {
throw new IllegalArgumentException("Unknown id: " + mSelectedMethodId);
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 0b7e391..eb1de2a 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -15,7 +15,6 @@
package com.android.server.inputmethod;
-import static android.inputmethodservice.InputMethodService.FINISH_INPUT_NO_FALLBACK_CONNECTION;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
import static android.os.IServiceManager.DUMP_FLAG_PROTO;
@@ -148,7 +147,6 @@
import android.view.inputmethod.InputMethodSubtype;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.compat.IPlatformCompat;
import com.android.internal.content.PackageMonitor;
import com.android.internal.infra.AndroidFuture;
import com.android.internal.inputmethod.DirectBootAwareness;
@@ -279,6 +277,7 @@
final WindowManagerInternal mWindowManagerInternal;
final PackageManagerInternal mPackageManagerInternal;
final InputManagerInternal mInputManagerInternal;
+ final ImePlatformCompatUtils mImePlatformCompatUtils;
final boolean mHasFeature;
private final ArrayMap<String, List<InputMethodSubtype>> mAdditionalSubtypeMap =
new ArrayMap<>();
@@ -691,8 +690,6 @@
*/
boolean mIsInteractive = true;
- private final IPlatformCompat mPlatformCompat;
-
int mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
/**
@@ -1627,6 +1624,7 @@
mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
+ mImePlatformCompatUtils = new ImePlatformCompatUtils();
mImeDisplayValidator = mWindowManagerInternal::getDisplayImePolicy;
mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
mUserManager = mContext.getSystemService(UserManager.class);
@@ -1634,8 +1632,7 @@
mAccessibilityManager = AccessibilityManager.getInstance(context);
mHasFeature = context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_INPUT_METHODS);
- mPlatformCompat = IPlatformCompat.Stub.asInterface(
- ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
+
mSlotIme = mContext.getString(com.android.internal.R.string.status_bar_ime);
Bundle extras = new Bundle();
@@ -3620,6 +3617,14 @@
return InputBindResult.INVALID_USER;
}
+ final boolean shouldClearFlag = mImePlatformCompatUtils.shouldClearShowForcedFlag(cs.uid);
+ // In case mShowForced flag affects the next client to keep IME visible, when the current
+ // client is leaving due to the next focused client, we clear mShowForced flag when the
+ // next client's targetSdkVersion is T or higher.
+ if (mCurFocusedWindow != windowToken && mShowForced && shouldClearFlag) {
+ mShowForced = false;
+ }
+
// cross-profile access is always allowed here to allow profile-switching.
if (!mSettings.isCurrentProfile(userId)) {
Slog.w(TAG, "A background user is requesting window. Hiding IME.");
@@ -4728,14 +4733,9 @@
// Inform the current client of the change in active status
if (mCurClient != null && mCurClient.client != null) {
- boolean reportToImeController = false;
- try {
- reportToImeController = mPlatformCompat.isChangeEnabledByUid(
- FINISH_INPUT_NO_FALLBACK_CONNECTION, getCurMethodUidLocked());
- } catch (RemoteException e) {
- }
scheduleSetActiveToClient(mCurClient, mIsInteractive, mInFullscreenMode,
- reportToImeController);
+ mImePlatformCompatUtils.shouldFinishInputWithReportToIme(
+ getCurMethodUidLocked()));
}
}
}
diff --git a/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java b/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java
index a290eb3..ea3a3d5 100644
--- a/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java
+++ b/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java
@@ -168,6 +168,7 @@
switch (key) {
case AtomicFormula.PACKAGE_NAME:
case AtomicFormula.APP_CERTIFICATE:
+ case AtomicFormula.APP_CERTIFICATE_LINEAGE:
case AtomicFormula.INSTALLER_NAME:
case AtomicFormula.INSTALLER_CERTIFICATE:
case AtomicFormula.STAMP_CERTIFICATE_HASH:
diff --git a/services/core/java/com/android/server/locales/LocaleManagerBackupHelper.java b/services/core/java/com/android/server/locales/LocaleManagerBackupHelper.java
index 01aee7b..db81393 100644
--- a/services/core/java/com/android/server/locales/LocaleManagerBackupHelper.java
+++ b/services/core/java/com/android/server/locales/LocaleManagerBackupHelper.java
@@ -34,7 +34,6 @@
import android.os.Binder;
import android.os.HandlerThread;
import android.os.LocaleList;
-import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
import android.text.TextUtils;
@@ -45,7 +44,6 @@
import android.util.Xml;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.content.PackageMonitor;
import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
@@ -89,32 +87,24 @@
// SparseArray because it is more memory-efficient than a HashMap.
private final SparseArray<StagedData> mStagedData;
- private final PackageMonitor mPackageMonitor;
private final BroadcastReceiver mUserMonitor;
LocaleManagerBackupHelper(LocaleManagerService localeManagerService,
- PackageManagerInternal pmInternal) {
+ PackageManagerInternal pmInternal, HandlerThread broadcastHandlerThread) {
this(localeManagerService.mContext, localeManagerService, pmInternal, Clock.systemUTC(),
- new SparseArray<>());
+ new SparseArray<>(), broadcastHandlerThread);
}
@VisibleForTesting LocaleManagerBackupHelper(Context context,
LocaleManagerService localeManagerService,
- PackageManagerInternal pmInternal, Clock clock, SparseArray<StagedData> stagedData) {
+ PackageManagerInternal pmInternal, Clock clock, SparseArray<StagedData> stagedData,
+ HandlerThread broadcastHandlerThread) {
mContext = context;
mLocaleManagerService = localeManagerService;
mPackageManagerInternal = pmInternal;
mClock = clock;
mStagedData = stagedData;
- HandlerThread broadcastHandlerThread = new HandlerThread(TAG,
- Process.THREAD_PRIORITY_BACKGROUND);
- broadcastHandlerThread.start();
-
- mPackageMonitor = new PackageMonitorImpl();
- mPackageMonitor.register(context, broadcastHandlerThread.getLooper(),
- UserHandle.ALL,
- true);
mUserMonitor = new UserMonitor();
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_USER_REMOVED);
@@ -127,11 +117,6 @@
return mUserMonitor;
}
- @VisibleForTesting
- PackageMonitor getPackageMonitor() {
- return mPackageMonitor;
- }
-
/**
* @see LocaleManagerInternal#getBackupPayload(int userId)
*/
@@ -267,6 +252,53 @@
BackupManager.dataChanged(SYSTEM_BACKUP_PACKAGE_KEY);
}
+ /**
+ * <p><b>Note:</b> This is invoked by service's common monitor
+ * {@link LocaleManagerServicePackageMonitor#onPackageAdded} when a new package is
+ * added on device.
+ */
+ void onPackageAdded(String packageName, int uid) {
+ try {
+ synchronized (mStagedDataLock) {
+ cleanStagedDataForOldEntriesLocked();
+
+ int userId = UserHandle.getUserId(uid);
+ if (mStagedData.contains(userId)) {
+ // Perform lazy restore only if the staged data exists.
+ doLazyRestoreLocked(packageName, userId);
+ }
+ }
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception in onPackageAdded.", e);
+ }
+ }
+
+ /**
+ * <p><b>Note:</b> This is invoked by service's common monitor
+ * {@link LocaleManagerServicePackageMonitor#onPackageDataCleared} when a package's data
+ * is cleared.
+ */
+ void onPackageDataCleared() {
+ try {
+ notifyBackupManager();
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception in onPackageDataCleared.", e);
+ }
+ }
+
+ /**
+ * <p><b>Note:</b> This is invoked by service's common monitor
+ * {@link LocaleManagerServicePackageMonitor#onPackageRemoved} when a package is removed
+ * from device.
+ */
+ void onPackageRemoved() {
+ try {
+ notifyBackupManager();
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception in onPackageRemoved.", e);
+ }
+ }
+
private boolean isPackageInstalledForUser(String packageName, int userId) {
PackageInfo pkgInfo = null;
try {
@@ -395,48 +427,6 @@
}
/**
- * Helper to monitor package states.
- *
- * <p>We're interested in package added, package data cleared and package removed events.
- */
- private final class PackageMonitorImpl extends PackageMonitor {
- @Override
- public void onPackageAdded(String packageName, int uid) {
- try {
- synchronized (mStagedDataLock) {
- cleanStagedDataForOldEntriesLocked();
-
- int userId = UserHandle.getUserId(uid);
- if (mStagedData.contains(userId)) {
- // Perform lazy restore only if the staged data exists.
- doLazyRestoreLocked(packageName, userId);
- }
- }
- } catch (Exception e) {
- Slog.e(TAG, "Exception in onPackageAdded.", e);
- }
- }
-
- @Override
- public void onPackageDataCleared(String packageName, int uid) {
- try {
- notifyBackupManager();
- } catch (Exception e) {
- Slog.e(TAG, "Exception in onPackageDataCleared.", e);
- }
- }
-
- @Override
- public void onPackageRemoved(String packageName, int uid) {
- try {
- notifyBackupManager();
- } catch (Exception e) {
- Slog.e(TAG, "Exception in onPackageRemoved.", e);
- }
- }
- }
-
- /**
* Performs lazy restore from the staged data.
*
* <p>This is invoked by the package monitor on the package added callback.
diff --git a/services/core/java/com/android/server/locales/LocaleManagerService.java b/services/core/java/com/android/server/locales/LocaleManagerService.java
index d459f8d..176c08c 100644
--- a/services/core/java/com/android/server/locales/LocaleManagerService.java
+++ b/services/core/java/com/android/server/locales/LocaleManagerService.java
@@ -29,6 +29,7 @@
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.os.Binder;
+import android.os.HandlerThread;
import android.os.LocaleList;
import android.os.Process;
import android.os.RemoteException;
@@ -38,14 +39,13 @@
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.DumpUtils;
+import com.android.internal.content.PackageMonitor;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.wm.ActivityTaskManagerInternal;
import java.io.FileDescriptor;
-import java.io.PrintWriter;
/**
* The implementation of ILocaleManager.aidl.
@@ -62,6 +62,8 @@
private LocaleManagerBackupHelper mBackupHelper;
+ private final PackageMonitor mPackageMonitor;
+
public static final boolean DEBUG = false;
public LocaleManagerService(Context context) {
@@ -71,15 +73,36 @@
mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
+
+ HandlerThread broadcastHandlerThread = new HandlerThread(TAG,
+ 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);
+ mPackageManagerInternal, broadcastHandlerThread);
+
+ mPackageMonitor = new LocaleManagerServicePackageMonitor(mBackupHelper,
+ systemAppUpdateTracker);
+ mPackageMonitor.register(context, broadcastHandlerThread.getLooper(),
+ UserHandle.ALL,
+ true);
}
@VisibleForTesting
LocaleManagerService(Context context, ActivityTaskManagerInternal activityTaskManagerInternal,
ActivityManagerInternal activityManagerInternal,
PackageManagerInternal packageManagerInternal,
- LocaleManagerBackupHelper localeManagerBackupHelper) {
+ LocaleManagerBackupHelper localeManagerBackupHelper,
+ PackageMonitor packageMonitor) {
super(context);
mContext = context;
mBinderService = new LocaleManagerBinderService();
@@ -87,6 +110,7 @@
mActivityManagerInternal = activityManagerInternal;
mPackageManagerInternal = packageManagerInternal;
mBackupHelper = localeManagerBackupHelper;
+ mPackageMonitor = packageMonitor;
}
@Override
@@ -130,11 +154,6 @@
}
@Override
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- LocaleManagerService.this.dump(fd, pw, args);
- }
-
- @Override
public void onShellCommand(FileDescriptor in, FileDescriptor out,
FileDescriptor err, String[] args, ShellCallback callback,
ResultReceiver resultReceiver) {
@@ -237,7 +256,7 @@
* <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) {
@@ -262,7 +281,7 @@
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)
@@ -397,7 +416,7 @@
}
@Nullable
- private String getInstallingPackageName(String packageName) {
+ String getInstallingPackageName(String packageName) {
try {
return mContext.getPackageManager()
.getInstallSourceInfo(packageName).getInstallingPackageName();
@@ -407,14 +426,6 @@
return null;
}
- /**
- * Dumps useful info related to service.
- */
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
- // TODO(b/201766221): Implement when there is state.
- }
-
private void logMetric(@NonNull AppLocaleChangedAtomRecord atomRecordForMetrics) {
FrameworkStatsLog.write(FrameworkStatsLog.APPLICATION_LOCALES_CHANGED,
atomRecordForMetrics.mCallingUid,
diff --git a/services/core/java/com/android/server/locales/LocaleManagerServicePackageMonitor.java b/services/core/java/com/android/server/locales/LocaleManagerServicePackageMonitor.java
new file mode 100644
index 0000000..32080ef
--- /dev/null
+++ b/services/core/java/com/android/server/locales/LocaleManagerServicePackageMonitor.java
@@ -0,0 +1,63 @@
+/*
+ * 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 com.android.internal.content.PackageMonitor;
+
+/**
+ * Helper to monitor package states inside {@link LocaleManagerService}.
+ *
+ * <p> These listeners forward the call to different aspects of locale service that
+ * handle the business logic.
+ * <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,
+ SystemAppUpdateTracker systemAppUpdateTracker) {
+ mBackupHelper = localeManagerBackupHelper;
+ mSystemAppUpdateTracker = systemAppUpdateTracker;
+ }
+
+ @Override
+ public void onPackageAdded(String packageName, int uid) {
+ mBackupHelper.onPackageAdded(packageName, uid);
+ }
+
+ @Override
+ public void onPackageDataCleared(String packageName, int uid) {
+ mBackupHelper.onPackageDataCleared();
+ }
+
+ @Override
+ 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 0000000..d13b1f4
--- /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/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index 45d9822..fac5106 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -1127,7 +1127,7 @@
if (provider != null && !provider.equals(manager.getName())) {
continue;
}
- CallerIdentity identity = manager.getIdentity();
+ CallerIdentity identity = manager.getProviderIdentity();
if (identity == null) {
continue;
}
@@ -1149,7 +1149,7 @@
return Collections.emptyList();
}
- CallerIdentity identity = manager.getIdentity();
+ CallerIdentity identity = manager.getProviderIdentity();
if (identity == null) {
return Collections.emptyList();
}
@@ -1536,7 +1536,7 @@
if (!enabled) {
PackageTagsList.Builder builder = new PackageTagsList.Builder();
for (LocationProviderManager manager : mProviderManagers) {
- CallerIdentity identity = manager.getIdentity();
+ CallerIdentity identity = manager.getProviderIdentity();
if (identity != null) {
builder.add(identity.getPackageName(), identity.getAttributionTag());
}
@@ -1624,7 +1624,7 @@
if (provider != null && !provider.equals(manager.getName())) {
continue;
}
- if (identity.equals(manager.getIdentity())) {
+ if (identity.equals(manager.getProviderIdentity())) {
return true;
}
}
@@ -1665,7 +1665,7 @@
if (listener != null) {
ArraySet<Integer> uids = new ArraySet<>(mProviderManagers.size());
for (LocationProviderManager manager : mProviderManagers) {
- CallerIdentity identity = manager.getIdentity();
+ CallerIdentity identity = manager.getProviderIdentity();
if (identity != null) {
uids.add(identity.getUid());
}
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubServiceUtil.java b/services/core/java/com/android/server/location/contexthub/ContextHubServiceUtil.java
index 8fdde24..e9bf90f 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubServiceUtil.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubServiceUtil.java
@@ -16,8 +16,6 @@
package com.android.server.location.contexthub;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-
import android.Manifest;
import android.content.Context;
import android.hardware.contexthub.V1_0.AsyncEventType;
@@ -297,19 +295,14 @@
}
/**
- * Checks for location hardware permissions.
+ * Checks for ACCESS_CONTEXT_HUB permissions.
*
* @param context the context of the service
*/
/* package */
static void checkPermissions(Context context) {
- boolean hasAccessContextHubPermission = (context.checkCallingPermission(
- CONTEXT_HUB_PERMISSION) == PERMISSION_GRANTED);
-
- if (!hasAccessContextHubPermission) {
- throw new SecurityException(
- "ACCESS_CONTEXT_HUB permission required to use Context Hub");
- }
+ context.enforceCallingOrSelfPermission(CONTEXT_HUB_PERMISSION,
+ "ACCESS_CONTEXT_HUB permission required to use Context Hub");
}
/**
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 d42e2c6..acbee11 100644
--- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
@@ -1468,7 +1468,7 @@
return mProvider.getState();
}
- public @Nullable CallerIdentity getIdentity() {
+ public @Nullable CallerIdentity getProviderIdentity() {
return mProvider.getState().identity;
}
@@ -1607,6 +1607,8 @@
public @Nullable Location getLastLocation(LastLocationRequest request,
CallerIdentity identity, @PermissionLevel int permissionLevel) {
+ request = calculateLastLocationRequest(request, identity);
+
if (!isActive(request.isBypass(), identity)) {
return null;
}
@@ -1634,6 +1636,39 @@
return location;
}
+ private LastLocationRequest calculateLastLocationRequest(LastLocationRequest baseRequest,
+ CallerIdentity identity) {
+ LastLocationRequest.Builder builder = new LastLocationRequest.Builder(baseRequest);
+
+ boolean locationSettingsIgnored = baseRequest.isLocationSettingsIgnored();
+ if (locationSettingsIgnored) {
+ // if we are not currently allowed use location settings ignored, disable it
+ if (!mSettingsHelper.getIgnoreSettingsAllowlist().contains(
+ identity.getPackageName(), identity.getAttributionTag())
+ && !mLocationManagerInternal.isProvider(null, identity)) {
+ locationSettingsIgnored = false;
+ }
+
+ builder.setLocationSettingsIgnored(locationSettingsIgnored);
+ }
+
+ boolean adasGnssBypass = baseRequest.isAdasGnssBypass();
+ if (adasGnssBypass) {
+ // if we are not currently allowed use adas gnss bypass, disable it
+ if (!GPS_PROVIDER.equals(mName)) {
+ Log.e(TAG, "adas gnss bypass request received in non-gps provider");
+ adasGnssBypass = false;
+ } else if (!mLocationSettings.getUserSettings(
+ identity.getUserId()).isAdasGnssLocationEnabled()) {
+ adasGnssBypass = false;
+ }
+
+ builder.setAdasGnssBypass(adasGnssBypass);
+ }
+
+ return builder.build();
+ }
+
/**
* This function does not perform any permissions or safety checks, by calling it you are
* committing to performing all applicable checks yourself. This always returns a "fine"
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 96391ac..92703ec 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -61,6 +61,7 @@
import java.util.Collection;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.NoSuchElementException;
/**
* This is the system implementation of a Session. Apps will interact with the
@@ -647,18 +648,17 @@
if (mDestroyed) {
return;
}
- toSend = new ArrayList<>();
- if (mQueue != null) {
- toSend.ensureCapacity(mQueue.size());
- toSend.addAll(mQueue);
- }
+ toSend = mQueue == null ? null : new ArrayList<>(mQueue);
}
Collection<ISessionControllerCallbackHolder> deadCallbackHolders = null;
for (ISessionControllerCallbackHolder holder : mControllerCallbackHolders) {
- ParceledListSlice<QueueItem> parcelableQueue = new ParceledListSlice<>(toSend);
- // Limit the size of initial Parcel to prevent binder buffer overflow
- // as onQueueChanged is an async binder call.
- parcelableQueue.setInlineCountLimit(1);
+ ParceledListSlice<QueueItem> parcelableQueue = null;
+ if (toSend != null) {
+ parcelableQueue = new ParceledListSlice<>(toSend);
+ // Limit the size of initial Parcel to prevent binder buffer overflow
+ // as onQueueChanged is an async binder call.
+ parcelableQueue.setInlineCountLimit(1);
+ }
try {
holder.mCallback.onQueueChanged(parcelableQueue);
@@ -793,7 +793,10 @@
}
for (ISessionControllerCallbackHolder holder : mControllerCallbackHolders) {
try {
+ holder.mCallback.asBinder().unlinkToDeath(holder.mDeathMonitor, 0);
holder.mCallback.onSessionDestroyed();
+ } catch (NoSuchElementException e) {
+ logCallbackException("error unlinking to binder death", holder, e);
} catch (DeadObjectException e) {
logCallbackException("Removing dead callback in pushSessionDestroyed", holder, e);
} catch (RemoteException e) {
@@ -1376,12 +1379,22 @@
return;
}
if (getControllerHolderIndexForCb(cb) < 0) {
- mControllerCallbackHolders.add(new ISessionControllerCallbackHolder(cb,
- packageName, Binder.getCallingUid()));
+ ISessionControllerCallbackHolder holder = new ISessionControllerCallbackHolder(
+ cb, packageName, Binder.getCallingUid(), () -> unregisterCallback(cb));
+ mControllerCallbackHolders.add(holder);
if (DEBUG) {
Log.d(TAG, "registering controller callback " + cb + " from controller"
+ packageName);
}
+ // Avoid callback leaks
+ try {
+ // cb is not referenced outside of the MediaSessionRecord, so the death
+ // handler won't prevent MediaSessionRecord to be garbage collected.
+ cb.asBinder().linkToDeath(holder.mDeathMonitor, 0);
+ } catch (RemoteException e) {
+ unregisterCallback(cb);
+ Log.w(TAG, "registerCallback failed to linkToDeath", e);
+ }
}
}
}
@@ -1391,6 +1404,12 @@
synchronized (mLock) {
int index = getControllerHolderIndexForCb(cb);
if (index != -1) {
+ try {
+ cb.asBinder().unlinkToDeath(
+ mControllerCallbackHolders.get(index).mDeathMonitor, 0);
+ } catch (NoSuchElementException e) {
+ Log.w(TAG, "error unlinking to binder death", e);
+ }
mControllerCallbackHolders.remove(index);
}
if (DEBUG) {
@@ -1601,12 +1620,14 @@
private final ISessionControllerCallback mCallback;
private final String mPackageName;
private final int mUid;
+ private final IBinder.DeathRecipient mDeathMonitor;
ISessionControllerCallbackHolder(ISessionControllerCallback callback, String packageName,
- int uid) {
+ int uid, IBinder.DeathRecipient deathMonitor) {
mCallback = callback;
mPackageName = packageName;
mUid = uid;
+ mDeathMonitor = deathMonitor;
}
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyLogger.java b/services/core/java/com/android/server/net/NetworkPolicyLogger.java
index 33ac6cd..c963154 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyLogger.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyLogger.java
@@ -77,6 +77,8 @@
private static final int EVENT_FIREWALL_CHAIN_ENABLED = 12;
private static final int EVENT_UPDATE_METERED_RESTRICTED_PKGS = 13;
private static final int EVENT_APP_IDLE_WL_CHANGED = 14;
+ private static final int EVENT_METERED_ALLOWLIST_CHANGED = 15;
+ private static final int EVENT_METERED_DENYLIST_CHANGED = 16;
private final LogBuffer mNetworkBlockedBuffer = new LogBuffer(MAX_NETWORK_BLOCKED_LOG_SIZE);
private final LogBuffer mUidStateChangeBuffer = new LogBuffer(MAX_LOG_SIZE);
@@ -89,7 +91,7 @@
void networkBlocked(int uid, @Nullable UidBlockedState uidBlockedState) {
synchronized (mLock) {
if (LOGD || uid == mDebugUid) {
- Slog.d(TAG, "Blocked state of uid: " + uidBlockedState.toString());
+ Slog.d(TAG, "Blocked state of " + uid + ": " + uidBlockedState.toString());
}
if (uidBlockedState == null) {
mNetworkBlockedBuffer.networkBlocked(uid, BLOCKED_REASON_NONE, ALLOWED_REASON_NONE,
@@ -245,6 +247,24 @@
}
}
+ void meteredAllowlistChanged(int uid, boolean added) {
+ synchronized (mLock) {
+ if (LOGD || mDebugUid == uid) {
+ Slog.d(TAG, getMeteredAllowlistChangedLog(uid, added));
+ }
+ mEventsBuffer.meteredAllowlistChanged(uid, added);
+ }
+ }
+
+ void meteredDenylistChanged(int uid, boolean added) {
+ synchronized (mLock) {
+ if (LOGD || mDebugUid == uid) {
+ Slog.d(TAG, getMeteredDenylistChangedLog(uid, added));
+ }
+ mEventsBuffer.meteredDenylistChanged(uid, added);
+ }
+ }
+
void setDebugUid(int uid) {
mDebugUid = uid;
}
@@ -320,6 +340,14 @@
return "Firewall chain " + getFirewallChainName(chain) + " state: " + enabled;
}
+ private static String getMeteredAllowlistChangedLog(int uid, boolean added) {
+ return "metered-allowlist for " + uid + " changed to " + added;
+ }
+
+ private static String getMeteredDenylistChangedLog(int uid, boolean added) {
+ return "metered-denylist for " + uid + " changed to " + added;
+ }
+
private static String getFirewallChainName(int chain) {
switch (chain) {
case FIREWALL_CHAIN_DOZABLE:
@@ -520,6 +548,28 @@
data.timeStamp = System.currentTimeMillis();
}
+ public void meteredAllowlistChanged(int uid, boolean added) {
+ final Data data = getNextSlot();
+ if (data == null) return;
+
+ data.reset();
+ data.type = EVENT_METERED_ALLOWLIST_CHANGED;
+ data.ifield1 = uid;
+ data.bfield1 = added;
+ data.timeStamp = System.currentTimeMillis();
+ }
+
+ public void meteredDenylistChanged(int uid, boolean added) {
+ final Data data = getNextSlot();
+ if (data == null) return;
+
+ data.reset();
+ data.type = EVENT_METERED_DENYLIST_CHANGED;
+ data.ifield1 = uid;
+ data.bfield1 = added;
+ data.timeStamp = System.currentTimeMillis();
+ }
+
public void reverseDump(IndentingPrintWriter pw) {
final Data[] allData = toArray();
for (int i = allData.length - 1; i >= 0; --i) {
@@ -567,6 +617,10 @@
return getUidFirewallRuleChangedLog(data.ifield1, data.ifield2, data.ifield3);
case EVENT_FIREWALL_CHAIN_ENABLED:
return getFirewallChainEnabledLog(data.ifield1, data.bfield1);
+ case EVENT_METERED_ALLOWLIST_CHANGED:
+ return getMeteredAllowlistChangedLog(data.ifield1, data.bfield1);
+ case EVENT_METERED_DENYLIST_CHANGED:
+ return getMeteredDenylistChangedLog(data.ifield1, data.bfield1);
default:
return String.valueOf(data.type);
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 60962b1..48ad22c 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -4864,7 +4864,7 @@
+ ", isAllowed=" + isAllowed
+ ", isRestrictedByAdmin=" + isRestrictedByAdmin
+ ", oldBlockedState=" + previousUidBlockedState.toString()
- + ", newBlockedState="
+ + ", newBlockedState=" + uidBlockedState.toString()
+ ", oldBlockedMeteredReasons=" + NetworkPolicyManager.blockedReasonsToString(
uidBlockedState.blockedReasons & BLOCKED_METERED_REASON_MASK)
+ ", oldBlockedMeteredEffectiveReasons="
@@ -5420,6 +5420,7 @@
if (LOGV) Slog.v(TAG, "setMeteredNetworkDenylist " + uid + ": " + enable);
try {
mNetworkManager.setUidOnMeteredNetworkDenylist(uid, enable);
+ mLogger.meteredAllowlistChanged(uid, enable);
} catch (IllegalStateException e) {
Log.wtf(TAG, "problem setting denylist (" + enable + ") rules for " + uid, e);
} catch (RemoteException e) {
@@ -5431,6 +5432,7 @@
if (LOGV) Slog.v(TAG, "setMeteredNetworkAllowlist " + uid + ": " + enable);
try {
mNetworkManager.setUidOnMeteredNetworkAllowlist(uid, enable);
+ mLogger.meteredDenylistChanged(uid, enable);
} catch (IllegalStateException e) {
Log.wtf(TAG, "problem setting allowlist (" + enable + ") rules for " + uid, e);
} catch (RemoteException e) {
@@ -5563,7 +5565,9 @@
.setFirewallUidRule(FIREWALL_CHAIN_LOW_POWER_STANDBY, uid,
FIREWALL_RULE_DEFAULT);
mNetworkManager.setUidOnMeteredNetworkAllowlist(uid, false);
+ mLogger.meteredAllowlistChanged(uid, false);
mNetworkManager.setUidOnMeteredNetworkDenylist(uid, false);
+ mLogger.meteredDenylistChanged(uid, false);
} catch (IllegalStateException e) {
Log.wtf(TAG, "problem resetting firewall uid rules for " + uid, e);
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 16b5fb1..a711b44 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -775,7 +775,7 @@
ArraySet<String> defaultDnds = mConditionProviders.getDefaultPackages();
for (int i = 0; i < defaultDnds.size(); i++) {
- allowDndPackage(defaultDnds.valueAt(i));
+ allowDndPackage(userId, defaultDnds.valueAt(i));
}
setDefaultAssistantForUser(userId);
@@ -875,9 +875,9 @@
}
}
- private void allowDndPackage(String packageName) {
+ private void allowDndPackage(int userId, String packageName) {
try {
- getBinderService().setNotificationPolicyAccessGranted(packageName, true);
+ getBinderService().setNotificationPolicyAccessGrantedForUser(packageName, userId, true);
} catch (RemoteException e) {
e.printStackTrace();
}
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 66c7c50..bbdea32 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -478,6 +478,7 @@
pw.println(prefix + "opPkg=" + getSbn().getOpPkg());
pw.println(prefix + "icon=" + notification.getSmallIcon());
pw.println(prefix + "flags=0x" + Integer.toHexString(notification.flags));
+ pw.println(prefix + "originalFlags=0x" + Integer.toHexString(mOriginalFlags));
pw.println(prefix + "pri=" + notification.priority);
pw.println(prefix + "key=" + getSbn().getKey());
pw.println(prefix + "seen=" + mStats.hasSeen());
@@ -544,6 +545,7 @@
if (notification == null) {
pw.println(prefix + "None");
return;
+
}
pw.println(prefix + "fullscreenIntent=" + notification.fullScreenIntent);
pw.println(prefix + "contentIntent=" + notification.contentIntent);
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 9b10058..6a2b2d5 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -348,6 +348,13 @@
public abstract String getApexModuleNameForPackageName(String apexPackageName);
/**
+ * Returns the package name of the active APEX whose name is {@code apexModuleName}. If not
+ * found, returns {@code null}.
+ */
+ @Nullable
+ public abstract String getActivePackageNameForApexModuleName(String apexModuleName);
+
+ /**
* Copies the CE apex data directory for the given {@code userId} to a backup location, for use
* in case of rollback.
*
@@ -485,6 +492,12 @@
private ArrayMap<String, String> mPackageNameToApexModuleName;
/**
+ * Reverse mapping of {@link #mPackageNameToApexModuleName}, for active packages only.
+ */
+ @GuardedBy("mLock")
+ private ArrayMap<String, String> mApexModuleNameToActivePackageName;
+
+ /**
* Whether an APEX package is active or not.
*
* @param packageInfo the package to check
@@ -552,6 +565,7 @@
try {
mAllPackagesCache = new ArrayList<>();
mPackageNameToApexModuleName = new ArrayMap<>();
+ mApexModuleNameToActivePackageName = new ArrayMap<>();
allPkgs = waitForApexService().getAllPackages();
} catch (RemoteException re) {
Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString());
@@ -634,6 +648,13 @@
+ packageInfo.packageName);
}
activePackagesSet.add(packageInfo.packageName);
+ if (mApexModuleNameToActivePackageName.containsKey(ai.moduleName)) {
+ throw new IllegalStateException(
+ "Two active packages have the same APEX module name: "
+ + ai.moduleName);
+ }
+ mApexModuleNameToActivePackageName.put(
+ ai.moduleName, packageInfo.packageName);
}
if (ai.isFactory) {
// Don't throw when the duplicating APEX is VNDK APEX
@@ -967,6 +988,16 @@
}
@Override
+ @Nullable
+ public String getActivePackageNameForApexModuleName(String apexModuleName) {
+ synchronized (mLock) {
+ Preconditions.checkState(mApexModuleNameToActivePackageName != null,
+ "APEX packages have not been scanned");
+ return mApexModuleNameToActivePackageName.get(apexModuleName);
+ }
+ }
+
+ @Override
public boolean snapshotCeData(int userId, int rollbackId, String apexPackageName) {
String apexModuleName;
synchronized (mLock) {
@@ -1391,6 +1422,12 @@
}
@Override
+ @Nullable
+ public String getActivePackageNameForApexModuleName(String apexModuleName) {
+ return null;
+ }
+
+ @Override
public boolean snapshotCeData(int userId, int rollbackId, String apexPackageName) {
throw new UnsupportedOperationException();
}
diff --git a/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java b/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java
index 06405ae..6dbe9b6 100644
--- a/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java
@@ -30,7 +30,6 @@
import static com.android.server.pm.PackageManagerService.SCAN_REQUIRE_KNOWN;
import static com.android.server.pm.PackageManagerService.SYSTEM_PARTITIONS;
import static com.android.server.pm.PackageManagerService.TAG;
-import static com.android.server.pm.pkg.parsing.ParsingPackageUtils.PARSE_FRAMEWORK_RES_SPLITS;
import android.annotation.Nullable;
import android.content.pm.parsing.ApkLiteParseUtils;
@@ -278,9 +277,8 @@
packageParser, executorService);
}
- List<File> frameworkSplits = getFrameworkResApkSplitFiles();
- scanDirTracedLI(frameworkDir, frameworkSplits,
- mSystemParseFlags | PARSE_FRAMEWORK_RES_SPLITS,
+ scanDirTracedLI(frameworkDir, null,
+ mSystemParseFlags,
mSystemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED, 0,
packageParser, executorService);
if (!mPm.mPackages.containsKey("android")) {
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index c09c904..54c2019 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -183,7 +183,6 @@
import java.util.Collections;
import java.util.List;
import java.util.Map;
-import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ExecutorService;
@@ -1596,18 +1595,23 @@
parsedPackage.setRestrictUpdateHash(oldPackage.getRestrictUpdateHash());
}
- // Check for shared user id changes
- if (!Objects.equals(oldPackage.getSharedUserId(),
- parsedPackage.getSharedUserId())
- // Don't mark as invalid if the app is trying to
- // leave a sharedUserId
- && parsedPackage.getSharedUserId() != null) {
+ // APK should not change its sharedUserId declarations
+ final var oldSharedUid = oldPackage.getSharedUserId() != null
+ ? oldPackage.getSharedUserId() : "<nothing>";
+ final var newSharedUid = parsedPackage.getSharedUserId() != null
+ ? parsedPackage.getSharedUserId() : "<nothing>";
+ if (!oldSharedUid.equals(newSharedUid)) {
throw new PrepareFailure(INSTALL_FAILED_UID_CHANGED,
"Package " + parsedPackage.getPackageName()
+ " shared user changed from "
- + (oldPackage.getSharedUserId() != null
- ? oldPackage.getSharedUserId() : "<nothing>")
- + " to " + parsedPackage.getSharedUserId());
+ + oldSharedUid + " to " + newSharedUid);
+ }
+
+ // APK should not re-join shared UID
+ if (oldPackage.isLeavingSharedUid() && !parsedPackage.isLeavingSharedUid()) {
+ throw new PrepareFailure(INSTALL_FAILED_UID_CHANGED,
+ "Package " + parsedPackage.getPackageName()
+ + " attempting to rejoin " + newSharedUid);
}
// In case of rollback, remember per-user/profile install state
@@ -3696,10 +3700,13 @@
}
disabledPkgSetting = mPm.mSettings.getDisabledSystemPkgLPr(
parsedPackage.getPackageName());
- sharedUserSetting = (parsedPackage.getSharedUserId() != null)
- ? mPm.mSettings.getSharedUserLPw(parsedPackage.getSharedUserId(),
- 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true)
- : null;
+ if (parsedPackage.getSharedUserId() != null && !parsedPackage.isLeavingSharedUid()) {
+ sharedUserSetting = mPm.mSettings.getSharedUserLPw(
+ parsedPackage.getSharedUserId(),
+ 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true /*create*/);
+ } else {
+ sharedUserSetting = null;
+ }
if (DEBUG_PACKAGE_SCANNING
&& (parseFlags & ParsingPackageUtils.PARSE_CHATTY) != 0
&& sharedUserSetting != null) {
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
index cdc2b12..f6f9faf 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
@@ -290,6 +290,9 @@
/** @see R#styleable.AndroidManifest_inheritKeyStoreKeys */
ParsingPackage setInheritKeyStoreKeys(boolean inheritKeyStoreKeys);
+ /** @see R#styleable.AndroidManifest_sharedUserMaxSdkVersion */
+ ParsingPackage setLeavingSharedUid(boolean leavingSharedUid);
+
ParsingPackage setLabelRes(int labelRes);
ParsingPackage setLargestWidthLimitDp(int largestWidthLimitDp);
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
index 177eaca..6767027 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
@@ -549,6 +549,7 @@
private static final long SDK_LIBRARY = 1L << 49;
private static final long INHERIT_KEYSTORE_KEYS = 1L << 50;
private static final long ENABLE_ON_BACK_INVOKED_CALLBACK = 1L << 51;
+ private static final long LEAVING_SHARED_UID = 1L << 52;
}
private ParsingPackageImpl setBoolean(@Booleans.Values long flag, boolean value) {
@@ -2403,6 +2404,11 @@
}
@Override
+ public boolean isLeavingSharedUid() {
+ return getBoolean(Booleans.LEAVING_SHARED_UID);
+ }
+
+ @Override
public ParsingPackageImpl setBaseRevisionCode(int value) {
baseRevisionCode = value;
return this;
@@ -2551,6 +2557,11 @@
}
@Override
+ public ParsingPackageImpl setLeavingSharedUid(boolean value) {
+ return setBoolean(Booleans.LEAVING_SHARED_UID, value);
+ }
+
+ @Override
public ParsingPackageImpl setLabelRes(int value) {
labelRes = value;
return this;
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageRead.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageRead.java
index 428374f..50033f6 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageRead.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageRead.java
@@ -360,4 +360,11 @@
* @see R.styleable.AndroidManifestApplication_enableOnBackInvokedCallback
*/
boolean isOnBackInvokedCallbackEnabled();
+
+ /**
+ * Returns true if R.styleable#AndroidManifest_sharedUserMaxSdkVersion is set to a value
+ * smaller than the current SDK version.
+ * @see R.styleable#AndroidManifest_sharedUserMaxSdkVersion
+ */
+ boolean isLeavingSharedUid();
}
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
index f30daa9..ed1ab01 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
@@ -1032,11 +1032,6 @@
private static ParseResult<ParsingPackage> parseSharedUser(ParseInput input,
ParsingPackage pkg, TypedArray sa) {
- int maxSdkVersion = anInteger(0, R.styleable.AndroidManifest_sharedUserMaxSdkVersion, sa);
- if ((maxSdkVersion != 0) && maxSdkVersion < Build.VERSION.RESOURCES_SDK_INT) {
- return input.success(pkg);
- }
-
String str = nonConfigString(0, R.styleable.AndroidManifest_sharedUserId, sa);
if (TextUtils.isEmpty(str)) {
return input.success(pkg);
@@ -1052,7 +1047,11 @@
}
}
+ int maxSdkVersion = anInteger(0, R.styleable.AndroidManifest_sharedUserMaxSdkVersion, sa);
+ boolean leaving = (maxSdkVersion != 0) && (maxSdkVersion < Build.VERSION.RESOURCES_SDK_INT);
+
return input.success(pkg
+ .setLeavingSharedUid(leaving)
.setSharedUserId(str.intern())
.setSharedUserLabel(resId(R.styleable.AndroidManifest_sharedUserLabel, sa)));
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 4387249..cc93d4c 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -330,6 +330,7 @@
static public final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
static public final String SYSTEM_DIALOG_REASON_ASSIST = "assist";
static public final String SYSTEM_DIALOG_REASON_SCREENSHOT = "screenshot";
+ static public final String SYSTEM_DIALOG_REASON_GESTURE_NAV = "gestureNav";
private static final String TALKBACK_LABEL = "TalkBack";
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 0000000..3543e93
--- /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 243efb5..863f2d1 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 @@
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 @@
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 @@
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 0000000..0f8be5a
--- /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/sensorprivacy/SensorPrivacyService.java b/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java
index a8e2d43..2f68f56 100644
--- a/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java
+++ b/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java
@@ -918,7 +918,6 @@
*/
@Override
public void addToggleSensorPrivacyListener(ISensorPrivacyListener listener) {
- Log.d("evan", "trying to add from " + Binder.getCallingUid());
enforceObserveSensorPrivacyPermission();
if (listener == null) {
throw new IllegalArgumentException("listener cannot be null");
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Compat.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Compat.java
index c638201..9bbae4b 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Compat.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Compat.java
@@ -29,7 +29,9 @@
import android.os.IHwBinder;
import android.os.RemoteException;
import android.system.OsConstants;
+import android.util.Log;
+import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
@@ -54,6 +56,8 @@
* </ul>
*/
final class SoundTriggerHw2Compat implements ISoundTriggerHal {
+ private static final String TAG = "SoundTriggerHw2Compat";
+
private final @NonNull Runnable mRebootRunnable;
private final @NonNull IHwBinder mBinder;
private @NonNull android.hardware.soundtrigger.V2_0.ISoundTriggerHw mUnderlying_2_0;
@@ -226,6 +230,16 @@
return handle.get();
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
+ } finally {
+ // TODO(b/219825762): We should be able to use the entire object in a try-with-resources
+ // clause, instead of having to explicitly close internal fields.
+ if (hidlModel.data != null) {
+ try {
+ hidlModel.data.close();
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to close file", e);
+ }
+ }
}
}
@@ -252,6 +266,16 @@
return handle.get();
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
+ } finally {
+ // TODO(b/219825762): We should be able to use the entire object in a try-with-resources
+ // clause, instead of having to explicitly close internal fields.
+ if (hidlModel.common.data != null) {
+ try {
+ hidlModel.common.data.close();
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to close file", e);
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 66904b1..e4a969b 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -18,9 +18,9 @@
import static android.app.StatusBarManager.DISABLE2_GLOBAL_ACTIONS;
import static android.app.StatusBarManager.DISABLE2_NOTIFICATION_SHADE;
-import static android.app.StatusBarManager.NAV_BAR_MODE_OVERRIDE_KIDS;
-import static android.app.StatusBarManager.NAV_BAR_MODE_OVERRIDE_NONE;
-import static android.app.StatusBarManager.NavBarModeOverride;
+import static android.app.StatusBarManager.NAV_BAR_MODE_DEFAULT;
+import static android.app.StatusBarManager.NAV_BAR_MODE_KIDS;
+import static android.app.StatusBarManager.NavBarMode;
import static android.app.StatusBarManager.SessionFlags;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY;
@@ -1945,26 +1945,25 @@
}
/**
- * Sets or removes the navigation bar mode override.
+ * Sets or removes the navigation bar mode.
*
- * @param navBarModeOverride the mode of the navigation bar override to be set.
+ * @param navBarMode the mode of the navigation bar to be set.
*/
- public void setNavBarModeOverride(@NavBarModeOverride int navBarModeOverride) {
+ public void setNavBarMode(@NavBarMode int navBarMode) {
enforceStatusBar();
- if (navBarModeOverride != NAV_BAR_MODE_OVERRIDE_NONE
- && navBarModeOverride != NAV_BAR_MODE_OVERRIDE_KIDS) {
+ if (navBarMode != NAV_BAR_MODE_DEFAULT && navBarMode != NAV_BAR_MODE_KIDS) {
throw new UnsupportedOperationException(
- "Supplied navBarModeOverride not supported: " + navBarModeOverride);
+ "Supplied navBarMode not supported: " + navBarMode);
}
final int userId = mCurrentUserId;
final long userIdentity = Binder.clearCallingIdentity();
try {
Settings.Secure.putIntForUser(mContext.getContentResolver(),
- Settings.Secure.NAV_BAR_KIDS_MODE, navBarModeOverride, userId);
+ Settings.Secure.NAV_BAR_KIDS_MODE, navBarMode, userId);
IOverlayManager overlayManager = getOverlayManager();
- if (overlayManager != null && navBarModeOverride == NAV_BAR_MODE_OVERRIDE_KIDS
+ if (overlayManager != null && navBarMode == NAV_BAR_MODE_KIDS
&& isPackageSupported(NAV_BAR_MODE_3BUTTON_OVERLAY)) {
overlayManager.setEnabledExclusiveInCategory(NAV_BAR_MODE_3BUTTON_OVERLAY, userId);
}
@@ -1976,14 +1975,14 @@
}
/**
- * Gets the navigation bar mode override. Returns default value if no override is set.
+ * Gets the navigation bar mode. Returns default value if no mode is set.
*
* @hide
*/
- public @NavBarModeOverride int getNavBarModeOverride() {
+ public @NavBarMode int getNavBarMode() {
enforceStatusBar();
- int navBarKidsMode = NAV_BAR_MODE_OVERRIDE_NONE;
+ int navBarKidsMode = NAV_BAR_MODE_DEFAULT;
final int userId = mCurrentUserId;
final long userIdentity = Binder.clearCallingIdentity();
try {
diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
index 1dea3d7..fa243c0 100644
--- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java
+++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
@@ -17,6 +17,7 @@
package com.android.server.trust;
import static android.service.trust.TrustAgentService.FLAG_GRANT_TRUST_DISPLAY_MESSAGE;
+import static android.service.trust.TrustAgentService.FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE;
import android.annotation.TargetApi;
import android.app.AlarmManager;
@@ -158,7 +159,7 @@
mMessage = (CharSequence) msg.obj;
int flags = msg.arg1;
mDisplayTrustGrantedMessage = (flags & FLAG_GRANT_TRUST_DISPLAY_MESSAGE) != 0;
- if ((flags & TrustAgentService.FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE) != 0) {
+ if ((flags & FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE) != 0) {
mWaitingForTrustableDowngrade = true;
} else {
mWaitingForTrustableDowngrade = false;
@@ -638,6 +639,11 @@
return mTrustable && mManagingTrust && !mTrustDisabledByDpm;
}
+ /** Set the trustagent as not trustable */
+ public void setUntrustable() {
+ mTrustable = false;
+ }
+
public boolean isManagingTrust() {
return mManagingTrust && !mTrustDisabledByDpm;
}
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index b4c54f9..bd4b8d1 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -16,6 +16,8 @@
package com.android.server.trust;
+import static android.service.trust.TrustAgentService.FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE;
+
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -127,13 +129,16 @@
private static final int MSG_DISPATCH_UNLOCK_LOCKOUT = 13;
private static final int MSG_REFRESH_DEVICE_LOCKED_FOR_USER = 14;
private static final int MSG_SCHEDULE_TRUST_TIMEOUT = 15;
- public static final int MSG_USER_REQUESTED_UNLOCK = 16;
+ private static final int MSG_USER_REQUESTED_UNLOCK = 16;
+ private static final int MSG_REFRESH_TRUSTABLE_TIMERS_AFTER_AUTH = 17;
private static final String REFRESH_DEVICE_LOCKED_EXCEPT_USER = "except";
private static final int TRUST_USUALLY_MANAGED_FLUSH_DELAY = 2 * 60 * 1000;
private static final String TRUST_TIMEOUT_ALARM_TAG = "TrustManagerService.trustTimeoutForUser";
private static final long TRUST_TIMEOUT_IN_MILLIS = 4 * 60 * 60 * 1000;
+ private static final long TRUSTABLE_IDLE_TIMEOUT_IN_MILLIS = 8 * 60 * 60 * 1000;
+ private static final long TRUSTABLE_TIMEOUT_IN_MILLIS = 24 * 60 * 60 * 1000;
private static final String PRIV_NAMESPACE = "http://schemas.android.com/apk/prv/res/android";
@@ -203,9 +208,18 @@
@GuardedBy("mUsersUnlockedByBiometric")
private final SparseBooleanArray mUsersUnlockedByBiometric = new SparseBooleanArray();
- private final ArrayMap<Integer, TrustTimeoutAlarmListener> mTrustTimeoutAlarmListenerForUser =
+ private enum TimeoutType {
+ TRUSTED,
+ TRUSTABLE
+ }
+ private final ArrayMap<Integer, TrustedTimeoutAlarmListener> mTrustTimeoutAlarmListenerForUser =
new ArrayMap<>();
+ private final SparseArray<TrustableTimeoutAlarmListener> mTrustableTimeoutAlarmListenerForUser =
+ new SparseArray<>();
+ private final SparseArray<TrustableTimeoutAlarmListener>
+ mIdleTrustableTimeoutAlarmListenerForUser = new SparseArray<>();
private AlarmManager mAlarmManager;
+ private final Object mAlarmLock = new Object();
private final SettingsObserver mSettingsObserver;
private final StrongAuthTracker mStrongAuthTracker;
@@ -258,7 +272,7 @@
private final boolean mIsAutomotive;
private final ContentResolver mContentResolver;
- private boolean mTrustAgentsExtendUnlock;
+ private boolean mTrustAgentsNonrenewableTrust;
private boolean mLockWhenTrustLost;
/**
@@ -295,11 +309,11 @@
@Override
public void onChange(boolean selfChange, Uri uri) {
if (TRUST_AGENTS_EXTEND_UNLOCK.equals(uri)) {
- // Smart lock should only extend unlock. The only exception is for automotive,
- // where it can actively unlock the head unit.
+ // Smart lock should only grant non-renewable trust. The only exception is for
+ // automotive, where it can actively unlock the head unit.
int defaultValue = mIsAutomotive ? 0 : 1;
- mTrustAgentsExtendUnlock =
+ mTrustAgentsNonrenewableTrust =
Settings.Secure.getIntForUser(
mContentResolver,
Settings.Secure.TRUST_AGENTS_EXTEND_UNLOCK,
@@ -315,8 +329,8 @@
}
}
- boolean getTrustAgentsExtendUnlock() {
- return mTrustAgentsExtendUnlock;
+ boolean getTrustAgentsNonrenewableTrust() {
+ return mTrustAgentsNonrenewableTrust;
}
boolean getLockWhenTrustLost() {
@@ -339,36 +353,53 @@
// If active unlocking is not allowed, cancel any pending trust timeouts because the
// screen is already locked.
- TrustTimeoutAlarmListener alarm = mTrustTimeoutAlarmListenerForUser.get(userId);
- if (alarm != null && mSettingsObserver.getTrustAgentsExtendUnlock()) {
+ TrustedTimeoutAlarmListener alarm = mTrustTimeoutAlarmListenerForUser.get(userId);
+ if (alarm != null && mSettingsObserver.getTrustAgentsNonrenewableTrust()) {
mAlarmManager.cancel(alarm);
alarm.setQueued(false /* isQueued */);
}
}
}
- private void scheduleTrustTimeout(int userId, boolean override) {
+ private void scheduleTrustTimeout(boolean override, boolean isTrustableTimeout) {
int shouldOverride = override ? 1 : 0;
- if (override) {
- shouldOverride = 1;
- }
- mHandler.obtainMessage(MSG_SCHEDULE_TRUST_TIMEOUT, userId, shouldOverride).sendToTarget();
+ int trustableTimeout = isTrustableTimeout ? 1 : 0;
+ mHandler.obtainMessage(MSG_SCHEDULE_TRUST_TIMEOUT, shouldOverride,
+ trustableTimeout).sendToTarget();
}
- private void handleScheduleTrustTimeout(int userId, int shouldOverride) {
+ private void handleScheduleTrustTimeout(boolean shouldOverride, TimeoutType timeoutType) {
+ int userId = mCurrentUser;
+ if (timeoutType == TimeoutType.TRUSTABLE) {
+ // don't override the hard timeout unless biometric or knowledge factor authentication
+ // occurs which isn't where this is called from. Override the idle timeout what the
+ // calling function has determined.
+ handleScheduleTrustableTimeouts(userId, shouldOverride,
+ false /* overrideHardTimeout */);
+ } else {
+ handleScheduleTrustedTimeout(userId, shouldOverride);
+ }
+ }
+
+ /* Override both the idle and hard trustable timeouts */
+ private void refreshTrustableTimers(int userId) {
+ handleScheduleTrustableTimeouts(userId, true /* overrideIdleTimeout */,
+ true /* overrideHardTimeout */);
+ }
+
+ private void handleScheduleTrustedTimeout(int userId, boolean shouldOverride) {
long when = SystemClock.elapsedRealtime() + TRUST_TIMEOUT_IN_MILLIS;
- userId = mCurrentUser;
- TrustTimeoutAlarmListener alarm = mTrustTimeoutAlarmListenerForUser.get(userId);
+ TrustedTimeoutAlarmListener alarm = mTrustTimeoutAlarmListenerForUser.get(userId);
// Cancel existing trust timeouts for this user if needed.
if (alarm != null) {
- if (shouldOverride == 0 && alarm.isQueued()) {
+ if (!shouldOverride && alarm.isQueued()) {
if (DEBUG) Slog.d(TAG, "Found existing trust timeout alarm. Skipping.");
return;
}
mAlarmManager.cancel(alarm);
} else {
- alarm = new TrustTimeoutAlarmListener(userId);
+ alarm = new TrustedTimeoutAlarmListener(userId);
mTrustTimeoutAlarmListenerForUser.put(userId, alarm);
}
@@ -379,6 +410,59 @@
mHandler);
}
+ private void handleScheduleTrustableTimeouts(int userId, boolean overrideIdleTimeout,
+ boolean overrideHardTimeout) {
+ setUpIdleTimeout(userId, overrideIdleTimeout);
+ setUpHardTimeout(userId, overrideHardTimeout);
+ }
+
+ private void setUpIdleTimeout(int userId, boolean overrideIdleTimeout) {
+ long when = SystemClock.elapsedRealtime() + TRUSTABLE_IDLE_TIMEOUT_IN_MILLIS;
+ TrustableTimeoutAlarmListener alarm = mIdleTrustableTimeoutAlarmListenerForUser.get(userId);
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.SCHEDULE_EXACT_ALARM, null);
+
+ // Cancel existing trustable timeouts for this user if needed.
+ if (alarm != null) {
+ if (!overrideIdleTimeout && alarm.isQueued()) {
+ if (DEBUG) Slog.d(TAG, "Found existing trustable timeout alarm. Skipping.");
+ return;
+ }
+ mAlarmManager.cancel(alarm);
+ } else {
+ alarm = new TrustableTimeoutAlarmListener(userId);
+ mIdleTrustableTimeoutAlarmListenerForUser.put(userId, alarm);
+ }
+
+ if (DEBUG) Slog.d(TAG, "\tSetting up trustable idle timeout alarm");
+ alarm.setQueued(true /* isQueued */);
+ mAlarmManager.setExact(
+ AlarmManager.ELAPSED_REALTIME_WAKEUP, when, TRUST_TIMEOUT_ALARM_TAG, alarm,
+ mHandler);
+ }
+
+ private void setUpHardTimeout(int userId, boolean overrideHardTimeout) {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.SCHEDULE_EXACT_ALARM, null);
+ TrustableTimeoutAlarmListener alarm = mTrustableTimeoutAlarmListenerForUser.get(userId);
+
+ // if the alarm doesn't exist, or hasn't been queued, or needs to be overridden we need to
+ // set it
+ if (alarm == null || !alarm.isQueued() || overrideHardTimeout) {
+ // schedule hard limit on renewable trust use
+ long when = SystemClock.elapsedRealtime() + TRUSTABLE_TIMEOUT_IN_MILLIS;
+ if (alarm == null) {
+ alarm = new TrustableTimeoutAlarmListener(userId);
+ mTrustableTimeoutAlarmListenerForUser.put(userId, alarm);
+ } else if (overrideHardTimeout) {
+ mAlarmManager.cancel(alarm);
+ }
+ if (DEBUG) Slog.d(TAG, "\tSetting up trustable hard timeout alarm");
+ alarm.setQueued(true /* isQueued */);
+ mAlarmManager.setExact(
+ AlarmManager.ELAPSED_REALTIME_WAKEUP, when, TRUST_TIMEOUT_ALARM_TAG, alarm,
+ mHandler);
+ }
+ }
+
// Agent management
private static final class AgentInfo {
@@ -419,11 +503,11 @@
if (ENABLE_ACTIVE_UNLOCK_FLAG) {
updateTrustWithRenewableUnlock(userId, flags, isFromUnlock);
} else {
- updateTrustWithExtendUnlock(userId, flags, isFromUnlock);
+ updateTrustWithNonrenewableTrust(userId, flags, isFromUnlock);
}
}
- private void updateTrustWithExtendUnlock(int userId, int flags, boolean isFromUnlock) {
+ private void updateTrustWithNonrenewableTrust(int userId, int flags, boolean isFromUnlock) {
boolean managed = aggregateIsTrustManaged(userId);
dispatchOnTrustManagedChanged(managed, userId);
if (mStrongAuthTracker.isTrustAllowedForUser(userId)
@@ -441,8 +525,8 @@
boolean changed;
synchronized (mUserIsTrusted) {
- if (mSettingsObserver.getTrustAgentsExtendUnlock()) {
- // In extend unlock trust agents can only set the device to trusted if it already
+ if (mSettingsObserver.getTrustAgentsNonrenewableTrust()) {
+ // For non-renewable trust agents can only set the device to trusted if it already
// trusted or the device is unlocked. Attempting to set the device as trusted
// when the device is locked will be ignored.
changed = mUserIsTrusted.get(userId) != trusted;
@@ -464,7 +548,7 @@
if (!trusted) {
maybeLockScreen(userId);
} else {
- scheduleTrustTimeout(userId, false /* override */);
+ scheduleTrustTimeout(false /* override */, false /* isTrustableTimeout*/);
}
}
}
@@ -522,7 +606,12 @@
if (!isNowTrusted) {
maybeLockScreen(userId);
} else {
- scheduleTrustTimeout(userId, false /* override */);
+ boolean isTrustableTimeout =
+ (flags & FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE) != 0;
+ // Every time we grant renewable trust we should override the idle trustable
+ // timeout. If this is for non-renewable trust, then we shouldn't override.
+ scheduleTrustTimeout(isTrustableTimeout /* override */,
+ isTrustableTimeout /* isTrustableTimeout */);
}
}
}
@@ -1102,8 +1191,9 @@
private void dispatchUnlockAttempt(boolean successful, int userId) {
if (successful) {
mStrongAuthTracker.allowTrustFromUnlock(userId);
- // Allow the presence of trust on a successful unlock attempt to extend unlock.
+ // Allow the presence of trust on a successful unlock attempt to extend unlock
updateTrust(userId, 0 /* flags */, true);
+ mHandler.obtainMessage(MSG_REFRESH_TRUSTABLE_TIMERS_AFTER_AUTH, userId).sendToTarget();
}
for (int i = 0; i < mActiveAgents.size(); i++) {
@@ -1520,11 +1610,12 @@
synchronized(mUsersUnlockedByBiometric) {
mUsersUnlockedByBiometric.put(userId, true);
}
- // In extend unlock mode we need to refresh trust state here, which will call
+ // In non-renewable trust mode we need to refresh trust state here, which will call
// refreshDeviceLockedForUser()
- int updateTrustOnUnlock = mSettingsObserver.getTrustAgentsExtendUnlock() ? 1 : 0;
+ int updateTrustOnUnlock = mSettingsObserver.getTrustAgentsNonrenewableTrust() ? 1 : 0;
mHandler.obtainMessage(MSG_REFRESH_DEVICE_LOCKED_FOR_USER, userId,
updateTrustOnUnlock).sendToTarget();
+ mHandler.obtainMessage(MSG_REFRESH_TRUSTABLE_TIMERS_AFTER_AUTH, userId).sendToTarget();
}
@Override
@@ -1643,7 +1734,13 @@
refreshDeviceLockedForUser(msg.arg1, unlockedUser);
break;
case MSG_SCHEDULE_TRUST_TIMEOUT:
- handleScheduleTrustTimeout(msg.arg1, msg.arg2);
+ boolean shouldOverride = msg.arg1 == 1 ? true : false;
+ TimeoutType timeoutType =
+ msg.arg2 == 1 ? TimeoutType.TRUSTABLE : TimeoutType.TRUSTED;
+ handleScheduleTrustTimeout(shouldOverride, timeoutType);
+ break;
+ case MSG_REFRESH_TRUSTABLE_TIMERS_AFTER_AUTH:
+ refreshTrustableTimers(msg.arg1);
break;
}
}
@@ -1759,10 +1856,11 @@
// Cancel pending alarms if we require some auth anyway.
if (!isTrustAllowedForUser(userId)) {
TrustTimeoutAlarmListener alarm = mTrustTimeoutAlarmListenerForUser.get(userId);
- if (alarm != null && alarm.isQueued()) {
- alarm.setQueued(false /* isQueued */);
- mAlarmManager.cancel(alarm);
- }
+ cancelPendingAlarm(alarm);
+ alarm = mTrustableTimeoutAlarmListenerForUser.get(userId);
+ cancelPendingAlarm(alarm);
+ alarm = mIdleTrustableTimeoutAlarmListenerForUser.get(userId);
+ cancelPendingAlarm(alarm);
}
refreshAgentList(userId);
@@ -1772,6 +1870,13 @@
updateTrust(userId, 0 /* flags */);
}
+ private void cancelPendingAlarm(@Nullable TrustTimeoutAlarmListener alarm) {
+ if (alarm != null && alarm.isQueued()) {
+ alarm.setQueued(false /* isQueued */);
+ mAlarmManager.cancel(alarm);
+ }
+ }
+
boolean canAgentsRunForUser(int userId) {
return mStartFromSuccessfulUnlock.get(userId)
|| super.isTrustAllowedForUser(userId);
@@ -1804,9 +1909,9 @@
}
}
- private class TrustTimeoutAlarmListener implements OnAlarmListener {
- private final int mUserId;
- private boolean mIsQueued = false;
+ private abstract class TrustTimeoutAlarmListener implements OnAlarmListener {
+ protected final int mUserId;
+ protected boolean mIsQueued = false;
TrustTimeoutAlarmListener(int userId) {
mUserId = userId;
@@ -1815,8 +1920,7 @@
@Override
public void onAlarm() {
mIsQueued = false;
- int strongAuthState = mStrongAuthTracker.getStrongAuthForUser(mUserId);
-
+ handleAlarm();
// Only fire if trust can unlock.
if (mStrongAuthTracker.isTrustAllowedForUser(mUserId)) {
if (DEBUG) Slog.d(TAG, "Revoking all trust because of trust timeout");
@@ -1826,12 +1930,98 @@
maybeLockScreen(mUserId);
}
- public void setQueued(boolean isQueued) {
- mIsQueued = isQueued;
- }
+ protected abstract void handleAlarm();
public boolean isQueued() {
return mIsQueued;
}
+
+ public void setQueued(boolean isQueued) {
+ mIsQueued = isQueued;
+ }
+ }
+
+ private class TrustedTimeoutAlarmListener extends TrustTimeoutAlarmListener {
+
+ TrustedTimeoutAlarmListener(int userId) {
+ super(userId);
+ }
+
+ @Override
+ public void handleAlarm() {
+ TrustableTimeoutAlarmListener otherAlarm;
+ boolean otherAlarmPresent;
+ if (ENABLE_ACTIVE_UNLOCK_FLAG) {
+ otherAlarm = mTrustableTimeoutAlarmListenerForUser.get(mUserId);
+ otherAlarmPresent = (otherAlarm != null) && otherAlarm.isQueued();
+ if (otherAlarmPresent) {
+ synchronized (mAlarmLock) {
+ disableNonrenewableTrustWhileRenewableTrustIsPresent();
+ }
+ return;
+ }
+ }
+ }
+
+ private void disableNonrenewableTrustWhileRenewableTrustIsPresent() {
+ synchronized (mUserTrustState) {
+ if (mUserTrustState.get(mUserId) == TrustState.TRUSTED) {
+ // if we're trusted and we have a trustable alarm, we need to
+ // downgrade to trustable
+ mUserTrustState.put(mUserId, TrustState.TRUSTABLE);
+ updateTrust(mUserId, 0 /* flags */);
+ }
+ }
+ }
+ }
+
+ private class TrustableTimeoutAlarmListener extends TrustTimeoutAlarmListener {
+
+ TrustableTimeoutAlarmListener(int userId) {
+ super(userId);
+ }
+
+ @Override
+ public void handleAlarm() {
+ TrustedTimeoutAlarmListener otherAlarm;
+ boolean otherAlarmPresent;
+ if (ENABLE_ACTIVE_UNLOCK_FLAG) {
+ cancelBothTrustableAlarms();
+ otherAlarm = mTrustTimeoutAlarmListenerForUser.get(mUserId);
+ otherAlarmPresent = (otherAlarm != null) && otherAlarm.isQueued();
+ if (otherAlarmPresent) {
+ synchronized (mAlarmLock) {
+ disableRenewableTrustWhileNonrenewableTrustIsPresent();
+ }
+ return;
+ }
+ }
+ }
+
+ private void cancelBothTrustableAlarms() {
+ TrustableTimeoutAlarmListener idleTimeout =
+ mIdleTrustableTimeoutAlarmListenerForUser.get(
+ mUserId);
+ TrustableTimeoutAlarmListener trustableTimeout =
+ mTrustableTimeoutAlarmListenerForUser.get(
+ mUserId);
+ if (idleTimeout != null && idleTimeout.isQueued()) {
+ idleTimeout.setQueued(false);
+ mAlarmManager.cancel(idleTimeout);
+ }
+ if (trustableTimeout != null && trustableTimeout.isQueued()) {
+ trustableTimeout.setQueued(false);
+ mAlarmManager.cancel(trustableTimeout);
+ }
+ }
+
+ private void disableRenewableTrustWhileNonrenewableTrustIsPresent() {
+ // if non-renewable trust is running, we need to temporarily prevent
+ // renewable trust from being used
+ for (AgentInfo agentInfo : mActiveAgents) {
+ agentInfo.agent.setUntrustable();
+ }
+ updateTrust(mUserId, 0 /* flags */);
+ }
}
}
diff --git a/services/core/java/com/android/server/vibrator/AbstractVibratorStep.java b/services/core/java/com/android/server/vibrator/AbstractVibratorStep.java
new file mode 100644
index 0000000..3550bda
--- /dev/null
+++ b/services/core/java/com/android/server/vibrator/AbstractVibratorStep.java
@@ -0,0 +1,148 @@
+/*
+ * 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.vibrator;
+
+import android.os.SystemClock;
+import android.os.VibrationEffect;
+import android.util.Slog;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Represent a step on a single vibrator that plays one or more segments from a
+ * {@link VibrationEffect.Composed} effect.
+ */
+abstract class AbstractVibratorStep extends Step {
+ public final VibratorController controller;
+ public final VibrationEffect.Composed effect;
+ public final int segmentIndex;
+ public final long previousStepVibratorOffTimeout;
+
+ long mVibratorOnResult;
+ boolean mVibratorCompleteCallbackReceived;
+
+ /**
+ * @param conductor The VibrationStepConductor for these steps.
+ * @param startTime The time to schedule this step in the
+ * {@link VibrationStepConductor}.
+ * @param controller The vibrator that is playing the effect.
+ * @param effect The effect being played in this step.
+ * @param index The index of the next segment to be played by this step
+ * @param previousStepVibratorOffTimeout The time the vibrator is expected to complete any
+ * previous vibration and turn off. This is used to allow this step to
+ * be triggered when the completion callback is received, and can
+ * be used to play effects back-to-back.
+ */
+ AbstractVibratorStep(VibrationStepConductor conductor, long startTime,
+ VibratorController controller, VibrationEffect.Composed effect, int index,
+ long previousStepVibratorOffTimeout) {
+ super(conductor, startTime);
+ this.controller = controller;
+ this.effect = effect;
+ this.segmentIndex = index;
+ this.previousStepVibratorOffTimeout = previousStepVibratorOffTimeout;
+ }
+
+ public int getVibratorId() {
+ return controller.getVibratorInfo().getId();
+ }
+
+ @Override
+ public long getVibratorOnDuration() {
+ return mVibratorOnResult;
+ }
+
+ @Override
+ public boolean acceptVibratorCompleteCallback(int vibratorId) {
+ boolean isSameVibrator = controller.getVibratorInfo().getId() == vibratorId;
+ mVibratorCompleteCallbackReceived |= isSameVibrator;
+ // Only activate this step if a timeout was set to wait for the vibration to complete,
+ // otherwise we are waiting for the correct time to play the next step.
+ return isSameVibrator && (previousStepVibratorOffTimeout > SystemClock.uptimeMillis());
+ }
+
+ @Override
+ public List<Step> cancel() {
+ return Arrays.asList(new CompleteEffectVibratorStep(conductor, SystemClock.uptimeMillis(),
+ /* cancelled= */ true, controller, previousStepVibratorOffTimeout));
+ }
+
+ @Override
+ public void cancelImmediately() {
+ if (previousStepVibratorOffTimeout > SystemClock.uptimeMillis()) {
+ // Vibrator might be running from previous steps, so turn it off while canceling.
+ stopVibrating();
+ }
+ }
+
+ protected void stopVibrating() {
+ if (VibrationThread.DEBUG) {
+ Slog.d(VibrationThread.TAG,
+ "Turning off vibrator " + getVibratorId());
+ }
+ controller.off();
+ }
+
+ protected void changeAmplitude(float amplitude) {
+ if (VibrationThread.DEBUG) {
+ Slog.d(VibrationThread.TAG,
+ "Amplitude changed on vibrator " + getVibratorId() + " to " + amplitude);
+ }
+ controller.setAmplitude(amplitude);
+ }
+
+ /**
+ * Return the {@link VibrationStepConductor#nextVibrateStep} with same timings, only jumping
+ * the segments.
+ */
+ protected List<Step> skipToNextSteps(int segmentsSkipped) {
+ return nextSteps(startTime, previousStepVibratorOffTimeout, segmentsSkipped);
+ }
+
+ /**
+ * Return the {@link VibrationStepConductor#nextVibrateStep} with same start and off timings
+ * calculated from {@link #getVibratorOnDuration()}, jumping all played segments.
+ *
+ * <p>This method has same behavior as {@link #skipToNextSteps(int)} when the vibrator
+ * result is non-positive, meaning the vibrator has either ignored or failed to turn on.
+ */
+ protected List<Step> nextSteps(int segmentsPlayed) {
+ if (mVibratorOnResult <= 0) {
+ // Vibration was not started, so just skip the played segments and keep timings.
+ return skipToNextSteps(segmentsPlayed);
+ }
+ long nextStartTime = SystemClock.uptimeMillis() + mVibratorOnResult;
+ long nextVibratorOffTimeout =
+ nextStartTime + VibrationStepConductor.CALLBACKS_EXTRA_TIMEOUT;
+ return nextSteps(nextStartTime, nextVibratorOffTimeout, segmentsPlayed);
+ }
+
+ /**
+ * Return the {@link VibrationStepConductor#nextVibrateStep} with given start and off timings,
+ * which might be calculated independently, jumping all played segments.
+ *
+ * <p>This should be used when the vibrator on/off state is not responsible for the steps
+ * execution timings, e.g. while playing the vibrator amplitudes.
+ */
+ protected List<Step> nextSteps(long nextStartTime, long vibratorOffTimeout,
+ int segmentsPlayed) {
+ Step nextStep = conductor.nextVibrateStep(nextStartTime, controller, effect,
+ segmentIndex + segmentsPlayed, vibratorOffTimeout);
+ return nextStep == null ? VibrationStepConductor.EMPTY_STEP_LIST : Arrays.asList(nextStep);
+ }
+}
diff --git a/services/core/java/com/android/server/vibrator/CompleteEffectVibratorStep.java b/services/core/java/com/android/server/vibrator/CompleteEffectVibratorStep.java
new file mode 100644
index 0000000..8585e34
--- /dev/null
+++ b/services/core/java/com/android/server/vibrator/CompleteEffectVibratorStep.java
@@ -0,0 +1,114 @@
+/*
+ * 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.vibrator;
+
+import android.os.SystemClock;
+import android.os.Trace;
+import android.os.VibrationEffect;
+import android.util.Slog;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Represents a step to complete a {@link VibrationEffect}.
+ *
+ * <p>This runs right at the time the vibration is considered to end and will update the pending
+ * vibrators count. This can turn off the vibrator or slowly ramp it down to zero amplitude.
+ */
+final class CompleteEffectVibratorStep extends AbstractVibratorStep {
+ private final boolean mCancelled;
+
+ CompleteEffectVibratorStep(VibrationStepConductor conductor, long startTime, boolean cancelled,
+ VibratorController controller, long previousStepVibratorOffTimeout) {
+ super(conductor, startTime, controller, /* effect= */ null, /* index= */ -1,
+ previousStepVibratorOffTimeout);
+ mCancelled = cancelled;
+ }
+
+ @Override
+ public boolean isCleanUp() {
+ // If the vibration was cancelled then this is just a clean up to ramp off the vibrator.
+ // Otherwise this step is part of the vibration.
+ return mCancelled;
+ }
+
+ @Override
+ public List<Step> cancel() {
+ if (mCancelled) {
+ // Double cancelling will just turn off the vibrator right away.
+ return Arrays.asList(
+ new TurnOffVibratorStep(conductor, SystemClock.uptimeMillis(), controller));
+ }
+ return super.cancel();
+ }
+
+ @Override
+ public List<Step> play() {
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "CompleteEffectVibratorStep");
+ try {
+ if (VibrationThread.DEBUG) {
+ Slog.d(VibrationThread.TAG,
+ "Running " + (mCancelled ? "cancel" : "complete") + " vibration"
+ + " step on vibrator " + controller.getVibratorInfo().getId());
+ }
+ if (mVibratorCompleteCallbackReceived) {
+ // Vibration completion callback was received by this step, just turn if off
+ // and skip any clean-up.
+ stopVibrating();
+ return VibrationStepConductor.EMPTY_STEP_LIST;
+ }
+
+ float currentAmplitude = controller.getCurrentAmplitude();
+ long remainingOnDuration =
+ previousStepVibratorOffTimeout - VibrationStepConductor.CALLBACKS_EXTRA_TIMEOUT
+ - SystemClock.uptimeMillis();
+ long rampDownDuration =
+ Math.min(remainingOnDuration,
+ conductor.vibrationSettings.getRampDownDuration());
+ long stepDownDuration = conductor.vibrationSettings.getRampStepDuration();
+ if (currentAmplitude < VibrationStepConductor.RAMP_OFF_AMPLITUDE_MIN
+ || rampDownDuration <= stepDownDuration) {
+ // No need to ramp down the amplitude, just wait to turn it off.
+ if (mCancelled) {
+ // Vibration is completing because it was cancelled, turn off right away.
+ stopVibrating();
+ return VibrationStepConductor.EMPTY_STEP_LIST;
+ } else {
+ return Arrays.asList(new TurnOffVibratorStep(
+ conductor, previousStepVibratorOffTimeout, controller));
+ }
+ }
+
+ if (VibrationThread.DEBUG) {
+ Slog.d(VibrationThread.TAG,
+ "Ramping down vibrator " + controller.getVibratorInfo().getId()
+ + " from amplitude " + currentAmplitude
+ + " for " + rampDownDuration + "ms");
+ }
+ float amplitudeDelta = currentAmplitude / (rampDownDuration / stepDownDuration);
+ float amplitudeTarget = currentAmplitude - amplitudeDelta;
+ long newVibratorOffTimeout =
+ mCancelled ? rampDownDuration : previousStepVibratorOffTimeout;
+ return Arrays.asList(
+ new RampOffVibratorStep(conductor, startTime, amplitudeTarget, amplitudeDelta,
+ controller, newVibratorOffTimeout));
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/vibrator/ComposePrimitivesVibratorStep.java b/services/core/java/com/android/server/vibrator/ComposePrimitivesVibratorStep.java
new file mode 100644
index 0000000..d1ea805
--- /dev/null
+++ b/services/core/java/com/android/server/vibrator/ComposePrimitivesVibratorStep.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vibrator;
+
+import android.os.Trace;
+import android.os.VibrationEffect;
+import android.os.vibrator.PrimitiveSegment;
+import android.os.vibrator.VibrationEffectSegment;
+import android.util.Slog;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents a step to turn the vibrator on using a composition of primitives.
+ *
+ * <p>This step will use the maximum supported number of consecutive segments of type
+ * {@link PrimitiveSegment} starting at the current index.
+ */
+final class ComposePrimitivesVibratorStep extends AbstractVibratorStep {
+
+ ComposePrimitivesVibratorStep(VibrationStepConductor conductor, long startTime,
+ VibratorController controller, VibrationEffect.Composed effect, int index,
+ long previousStepVibratorOffTimeout) {
+ // This step should wait for the last vibration to finish (with the timeout) and for the
+ // intended step start time (to respect the effect delays).
+ super(conductor, Math.max(startTime, previousStepVibratorOffTimeout), controller, effect,
+ index, previousStepVibratorOffTimeout);
+ }
+
+ @Override
+ public List<Step> play() {
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "ComposePrimitivesStep");
+ try {
+ // Load the next PrimitiveSegments to create a single compose call to the vibrator,
+ // limited to the vibrator composition maximum size.
+ int limit = controller.getVibratorInfo().getCompositionSizeMax();
+ int segmentCount = limit > 0
+ ? Math.min(effect.getSegments().size(), segmentIndex + limit)
+ : effect.getSegments().size();
+ List<PrimitiveSegment> primitives = new ArrayList<>();
+ for (int i = segmentIndex; i < segmentCount; i++) {
+ VibrationEffectSegment segment = effect.getSegments().get(i);
+ if (segment instanceof PrimitiveSegment) {
+ primitives.add((PrimitiveSegment) segment);
+ } else {
+ break;
+ }
+ }
+
+ if (primitives.isEmpty()) {
+ Slog.w(VibrationThread.TAG, "Ignoring wrong segment for a ComposePrimitivesStep: "
+ + effect.getSegments().get(segmentIndex));
+ return skipToNextSteps(/* segmentsSkipped= */ 1);
+ }
+
+ if (VibrationThread.DEBUG) {
+ Slog.d(VibrationThread.TAG, "Compose " + primitives + " primitives on vibrator "
+ + controller.getVibratorInfo().getId());
+ }
+ mVibratorOnResult = controller.on(
+ primitives.toArray(new PrimitiveSegment[primitives.size()]),
+ getVibration().id);
+
+ return nextSteps(/* segmentsPlayed= */ primitives.size());
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/vibrator/ComposePwleVibratorStep.java b/services/core/java/com/android/server/vibrator/ComposePwleVibratorStep.java
new file mode 100644
index 0000000..73bf933
--- /dev/null
+++ b/services/core/java/com/android/server/vibrator/ComposePwleVibratorStep.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vibrator;
+
+import android.os.Trace;
+import android.os.VibrationEffect;
+import android.os.vibrator.RampSegment;
+import android.os.vibrator.StepSegment;
+import android.os.vibrator.VibrationEffectSegment;
+import android.util.Slog;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents a step to turn the vibrator on using a composition of PWLE segments.
+ *
+ * <p>This step will use the maximum supported number of consecutive segments of type
+ * {@link StepSegment} or {@link RampSegment} starting at the current index.
+ */
+final class ComposePwleVibratorStep extends AbstractVibratorStep {
+
+ ComposePwleVibratorStep(VibrationStepConductor conductor, long startTime,
+ VibratorController controller, VibrationEffect.Composed effect, int index,
+ long previousStepVibratorOffTimeout) {
+ // This step should wait for the last vibration to finish (with the timeout) and for the
+ // intended step start time (to respect the effect delays).
+ super(conductor, Math.max(startTime, previousStepVibratorOffTimeout), controller, effect,
+ index, previousStepVibratorOffTimeout);
+ }
+
+ @Override
+ public List<Step> play() {
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "ComposePwleStep");
+ try {
+ // Load the next RampSegments to create a single composePwle call to the vibrator,
+ // limited to the vibrator PWLE maximum size.
+ int limit = controller.getVibratorInfo().getPwleSizeMax();
+ int segmentCount = limit > 0
+ ? Math.min(effect.getSegments().size(), segmentIndex + limit)
+ : effect.getSegments().size();
+ List<RampSegment> pwles = new ArrayList<>();
+ for (int i = segmentIndex; i < segmentCount; i++) {
+ VibrationEffectSegment segment = effect.getSegments().get(i);
+ if (segment instanceof RampSegment) {
+ pwles.add((RampSegment) segment);
+ } else {
+ break;
+ }
+ }
+
+ if (pwles.isEmpty()) {
+ Slog.w(VibrationThread.TAG, "Ignoring wrong segment for a ComposePwleStep: "
+ + effect.getSegments().get(segmentIndex));
+ return skipToNextSteps(/* segmentsSkipped= */ 1);
+ }
+
+ if (VibrationThread.DEBUG) {
+ Slog.d(VibrationThread.TAG, "Compose " + pwles + " PWLEs on vibrator "
+ + controller.getVibratorInfo().getId());
+ }
+ mVibratorOnResult = controller.on(pwles.toArray(new RampSegment[pwles.size()]),
+ getVibration().id);
+
+ return nextSteps(/* segmentsPlayed= */ pwles.size());
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/vibrator/FinishSequentialEffectStep.java b/services/core/java/com/android/server/vibrator/FinishSequentialEffectStep.java
new file mode 100644
index 0000000..bbbca02
--- /dev/null
+++ b/services/core/java/com/android/server/vibrator/FinishSequentialEffectStep.java
@@ -0,0 +1,73 @@
+/*
+ * 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.vibrator;
+
+import android.os.Trace;
+import android.util.Slog;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Finish a sync vibration started by a {@link StartSequentialEffectStep}.
+ *
+ * <p>This only plays after all active vibrators steps have finished, and adds a {@link
+ * StartSequentialEffectStep} to the queue if the sequential effect isn't finished yet.
+ */
+final class FinishSequentialEffectStep extends Step {
+ public final StartSequentialEffectStep startedStep;
+
+ FinishSequentialEffectStep(StartSequentialEffectStep startedStep) {
+ // No predefined startTime, just wait for all steps in the queue.
+ super(startedStep.conductor, Long.MAX_VALUE);
+ this.startedStep = startedStep;
+ }
+
+ @Override
+ public boolean isCleanUp() {
+ // This step only notes that all the vibrators has been turned off.
+ return true;
+ }
+
+ @Override
+ public List<Step> play() {
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "FinishSequentialEffectStep");
+ try {
+ if (VibrationThread.DEBUG) {
+ Slog.d(VibrationThread.TAG,
+ "FinishSequentialEffectStep for effect #" + startedStep.currentIndex);
+ }
+ conductor.vibratorManagerHooks.noteVibratorOff(conductor.getVibration().uid);
+ Step nextStep = startedStep.nextStep();
+ return nextStep == null ? VibrationStepConductor.EMPTY_STEP_LIST
+ : Arrays.asList(nextStep);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+ }
+ }
+
+ @Override
+ public List<Step> cancel() {
+ cancelImmediately();
+ return VibrationStepConductor.EMPTY_STEP_LIST;
+ }
+
+ @Override
+ public void cancelImmediately() {
+ conductor.vibratorManagerHooks.noteVibratorOff(conductor.getVibration().uid);
+ }
+}
diff --git a/services/core/java/com/android/server/vibrator/PerformPrebakedVibratorStep.java b/services/core/java/com/android/server/vibrator/PerformPrebakedVibratorStep.java
new file mode 100644
index 0000000..601ae97
--- /dev/null
+++ b/services/core/java/com/android/server/vibrator/PerformPrebakedVibratorStep.java
@@ -0,0 +1,103 @@
+/*
+ * 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.vibrator;
+
+import android.os.Trace;
+import android.os.VibrationEffect;
+import android.os.vibrator.PrebakedSegment;
+import android.os.vibrator.VibrationEffectSegment;
+import android.util.Slog;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents a step to turn the vibrator on with a single prebaked effect.
+ *
+ * <p>This step automatically falls back by replacing the prebaked segment with
+ * {@link VibrationSettings#getFallbackEffect(int)}, if available.
+ */
+final class PerformPrebakedVibratorStep extends AbstractVibratorStep {
+
+ PerformPrebakedVibratorStep(VibrationStepConductor conductor, long startTime,
+ VibratorController controller, VibrationEffect.Composed effect, int index,
+ long previousStepVibratorOffTimeout) {
+ // This step should wait for the last vibration to finish (with the timeout) and for the
+ // intended step start time (to respect the effect delays).
+ super(conductor, Math.max(startTime, previousStepVibratorOffTimeout), controller, effect,
+ index, previousStepVibratorOffTimeout);
+ }
+
+ @Override
+ public List<Step> play() {
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "PerformPrebakedVibratorStep");
+ try {
+ VibrationEffectSegment segment = effect.getSegments().get(segmentIndex);
+ if (!(segment instanceof PrebakedSegment)) {
+ Slog.w(VibrationThread.TAG, "Ignoring wrong segment for a "
+ + "PerformPrebakedVibratorStep: " + segment);
+ return skipToNextSteps(/* segmentsSkipped= */ 1);
+ }
+
+ PrebakedSegment prebaked = (PrebakedSegment) segment;
+ if (VibrationThread.DEBUG) {
+ Slog.d(VibrationThread.TAG, "Perform " + VibrationEffect.effectIdToString(
+ prebaked.getEffectId()) + " on vibrator "
+ + controller.getVibratorInfo().getId());
+ }
+
+ VibrationEffect fallback = getVibration().getFallback(prebaked.getEffectId());
+ mVibratorOnResult = controller.on(prebaked, getVibration().id);
+
+ if (mVibratorOnResult == 0 && prebaked.shouldFallback()
+ && (fallback instanceof VibrationEffect.Composed)) {
+ if (VibrationThread.DEBUG) {
+ Slog.d(VibrationThread.TAG, "Playing fallback for effect "
+ + VibrationEffect.effectIdToString(prebaked.getEffectId()));
+ }
+ AbstractVibratorStep fallbackStep = conductor.nextVibrateStep(startTime, controller,
+ replaceCurrentSegment((VibrationEffect.Composed) fallback),
+ segmentIndex, previousStepVibratorOffTimeout);
+ List<Step> fallbackResult = fallbackStep.play();
+ // Update the result with the fallback result so this step is seamlessly
+ // replaced by the fallback to any outer application of this.
+ mVibratorOnResult = fallbackStep.getVibratorOnDuration();
+ return fallbackResult;
+ }
+
+ return nextSteps(/* segmentsPlayed= */ 1);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+ }
+ }
+
+ /**
+ * Replace segment at {@link #segmentIndex} in {@link #effect} with given fallback segments.
+ *
+ * @return a copy of {@link #effect} with replaced segment.
+ */
+ private VibrationEffect.Composed replaceCurrentSegment(VibrationEffect.Composed fallback) {
+ List<VibrationEffectSegment> newSegments = new ArrayList<>(effect.getSegments());
+ int newRepeatIndex = effect.getRepeatIndex();
+ newSegments.remove(segmentIndex);
+ newSegments.addAll(segmentIndex, fallback.getSegments());
+ if (segmentIndex < effect.getRepeatIndex()) {
+ newRepeatIndex += fallback.getSegments().size() - 1;
+ }
+ return new VibrationEffect.Composed(newSegments, newRepeatIndex);
+ }
+}
diff --git a/services/core/java/com/android/server/vibrator/RampOffVibratorStep.java b/services/core/java/com/android/server/vibrator/RampOffVibratorStep.java
new file mode 100644
index 0000000..8cf5fb3
--- /dev/null
+++ b/services/core/java/com/android/server/vibrator/RampOffVibratorStep.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vibrator;
+
+import android.os.SystemClock;
+import android.os.Trace;
+import android.util.Slog;
+
+import java.util.Arrays;
+import java.util.List;
+
+/** Represents a step to ramp down the vibrator amplitude before turning it off. */
+final class RampOffVibratorStep extends AbstractVibratorStep {
+ private final float mAmplitudeTarget;
+ private final float mAmplitudeDelta;
+
+ RampOffVibratorStep(VibrationStepConductor conductor, long startTime, float amplitudeTarget,
+ float amplitudeDelta, VibratorController controller,
+ long previousStepVibratorOffTimeout) {
+ super(conductor, startTime, controller, /* effect= */ null, /* index= */ -1,
+ previousStepVibratorOffTimeout);
+ mAmplitudeTarget = amplitudeTarget;
+ mAmplitudeDelta = amplitudeDelta;
+ }
+
+ @Override
+ public boolean isCleanUp() {
+ return true;
+ }
+
+ @Override
+ public List<Step> cancel() {
+ return Arrays.asList(
+ new TurnOffVibratorStep(conductor, SystemClock.uptimeMillis(), controller));
+ }
+
+ @Override
+ public List<Step> play() {
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "RampOffVibratorStep");
+ try {
+ if (VibrationThread.DEBUG) {
+ long latency = SystemClock.uptimeMillis() - startTime;
+ Slog.d(VibrationThread.TAG, "Ramp down the vibrator amplitude, step with "
+ + latency + "ms latency.");
+ }
+ if (mVibratorCompleteCallbackReceived) {
+ // Vibration completion callback was received by this step, just turn if off
+ // and skip the rest of the steps to ramp down the vibrator amplitude.
+ stopVibrating();
+ return VibrationStepConductor.EMPTY_STEP_LIST;
+ }
+
+ changeAmplitude(mAmplitudeTarget);
+
+ float newAmplitudeTarget = mAmplitudeTarget - mAmplitudeDelta;
+ if (newAmplitudeTarget < VibrationStepConductor.RAMP_OFF_AMPLITUDE_MIN) {
+ // Vibrator amplitude cannot go further down, just turn it off.
+ return Arrays.asList(new TurnOffVibratorStep(
+ conductor, previousStepVibratorOffTimeout, controller));
+ }
+ return Arrays.asList(new RampOffVibratorStep(
+ conductor,
+ startTime + conductor.vibrationSettings.getRampStepDuration(),
+ newAmplitudeTarget, mAmplitudeDelta, controller,
+ previousStepVibratorOffTimeout));
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/vibrator/SetAmplitudeVibratorStep.java b/services/core/java/com/android/server/vibrator/SetAmplitudeVibratorStep.java
new file mode 100644
index 0000000..d5c1116
--- /dev/null
+++ b/services/core/java/com/android/server/vibrator/SetAmplitudeVibratorStep.java
@@ -0,0 +1,186 @@
+/*
+ * 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.vibrator;
+
+import android.os.SystemClock;
+import android.os.Trace;
+import android.os.VibrationEffect;
+import android.os.vibrator.StepSegment;
+import android.os.vibrator.VibrationEffectSegment;
+import android.util.Slog;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Represents a step to turn the vibrator on and change its amplitude.
+ *
+ * <p>This step ignores vibration completion callbacks and control the vibrator on/off state
+ * and amplitude to simulate waveforms represented by a sequence of {@link StepSegment}.
+ */
+final class SetAmplitudeVibratorStep extends AbstractVibratorStep {
+ private long mNextOffTime;
+
+ SetAmplitudeVibratorStep(VibrationStepConductor conductor, long startTime,
+ VibratorController controller, VibrationEffect.Composed effect, int index,
+ long previousStepVibratorOffTimeout) {
+ // This step has a fixed startTime coming from the timings of the waveform it's playing.
+ super(conductor, startTime, controller, effect, index, previousStepVibratorOffTimeout);
+ mNextOffTime = previousStepVibratorOffTimeout;
+ }
+
+ @Override
+ public boolean acceptVibratorCompleteCallback(int vibratorId) {
+ if (controller.getVibratorInfo().getId() == vibratorId) {
+ mVibratorCompleteCallbackReceived = true;
+ mNextOffTime = SystemClock.uptimeMillis();
+ }
+ // Timings are tightly controlled here, so only trigger this step if the vibrator was
+ // supposed to be ON but has completed prematurely, to turn it back on as soon as
+ // possible.
+ return mNextOffTime < startTime && controller.getCurrentAmplitude() > 0;
+ }
+
+ @Override
+ public List<Step> play() {
+ // TODO: consider separating the "on" steps at the start into a separate Step.
+ // TODO: consider instantiating the step with the required amplitude, rather than
+ // needing to dig into the effect.
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "SetAmplitudeVibratorStep");
+ try {
+ long now = SystemClock.uptimeMillis();
+ long latency = now - startTime;
+ if (VibrationThread.DEBUG) {
+ Slog.d(VibrationThread.TAG,
+ "Running amplitude step with " + latency + "ms latency.");
+ }
+
+ if (mVibratorCompleteCallbackReceived && latency < 0) {
+ // This step was run early because the vibrator turned off prematurely.
+ // Turn it back on and return this same step to run at the exact right time.
+ mNextOffTime = turnVibratorBackOn(/* remainingDuration= */ -latency);
+ return Arrays.asList(new SetAmplitudeVibratorStep(conductor, startTime, controller,
+ effect, segmentIndex, mNextOffTime));
+ }
+
+ VibrationEffectSegment segment = effect.getSegments().get(segmentIndex);
+ if (!(segment instanceof StepSegment)) {
+ Slog.w(VibrationThread.TAG,
+ "Ignoring wrong segment for a SetAmplitudeVibratorStep: " + segment);
+ return skipToNextSteps(/* segmentsSkipped= */ 1);
+ }
+
+ StepSegment stepSegment = (StepSegment) segment;
+ if (stepSegment.getDuration() == 0) {
+ // Skip waveform entries with zero timing.
+ return skipToNextSteps(/* segmentsSkipped= */ 1);
+ }
+
+ float amplitude = stepSegment.getAmplitude();
+ if (amplitude == 0) {
+ if (previousStepVibratorOffTimeout > now) {
+ // Amplitude cannot be set to zero, so stop the vibrator.
+ stopVibrating();
+ mNextOffTime = now;
+ }
+ } else {
+ if (startTime >= mNextOffTime) {
+ // Vibrator is OFF. Turn vibrator back on for the duration of another
+ // cycle before setting the amplitude.
+ long onDuration = getVibratorOnDuration(effect, segmentIndex);
+ if (onDuration > 0) {
+ mVibratorOnResult = startVibrating(onDuration);
+ mNextOffTime = now + onDuration
+ + VibrationStepConductor.CALLBACKS_EXTRA_TIMEOUT;
+ }
+ }
+ changeAmplitude(amplitude);
+ }
+
+ // Use original startTime to avoid propagating latencies to the waveform.
+ long nextStartTime = startTime + segment.getDuration();
+ return nextSteps(nextStartTime, mNextOffTime, /* segmentsPlayed= */ 1);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+ }
+ }
+
+ private long turnVibratorBackOn(long remainingDuration) {
+ long onDuration = getVibratorOnDuration(effect, segmentIndex);
+ if (onDuration <= 0) {
+ // Vibrator is supposed to go back off when this step starts, so just leave it off.
+ return previousStepVibratorOffTimeout;
+ }
+ onDuration += remainingDuration;
+ float expectedAmplitude = controller.getCurrentAmplitude();
+ mVibratorOnResult = startVibrating(onDuration);
+ if (mVibratorOnResult > 0) {
+ // Set the amplitude back to the value it was supposed to be playing at.
+ changeAmplitude(expectedAmplitude);
+ }
+ return SystemClock.uptimeMillis() + onDuration
+ + VibrationStepConductor.CALLBACKS_EXTRA_TIMEOUT;
+ }
+
+ private long startVibrating(long duration) {
+ if (VibrationThread.DEBUG) {
+ Slog.d(VibrationThread.TAG,
+ "Turning on vibrator " + controller.getVibratorInfo().getId() + " for "
+ + duration + "ms");
+ }
+ return controller.on(duration, getVibration().id);
+ }
+
+ /**
+ * Get the duration the vibrator will be on for a waveform, starting at {@code startIndex}
+ * until the next time it's vibrating amplitude is zero or a different type of segment is
+ * found.
+ */
+ private long getVibratorOnDuration(VibrationEffect.Composed effect, int startIndex) {
+ List<VibrationEffectSegment> segments = effect.getSegments();
+ int segmentCount = segments.size();
+ int repeatIndex = effect.getRepeatIndex();
+ int i = startIndex;
+ long timing = 0;
+ while (i < segmentCount) {
+ VibrationEffectSegment segment = segments.get(i);
+ if (!(segment instanceof StepSegment)
+ || ((StepSegment) segment).getAmplitude() == 0) {
+ break;
+ }
+ timing += segment.getDuration();
+ i++;
+ if (i == segmentCount && repeatIndex >= 0) {
+ i = repeatIndex;
+ // prevent infinite loop
+ repeatIndex = -1;
+ }
+ if (i == startIndex) {
+ // The repeating waveform keeps the vibrator ON all the time. Use a minimum
+ // of 1s duration to prevent short patterns from turning the vibrator ON too
+ // frequently.
+ return Math.max(timing, 1000);
+ }
+ }
+ if (i == segmentCount && effect.getRepeatIndex() < 0) {
+ // Vibration ending at non-zero amplitude, add extra timings to ramp down after
+ // vibration is complete.
+ timing += conductor.vibrationSettings.getRampDownDuration();
+ }
+ return timing;
+ }
+}
diff --git a/services/core/java/com/android/server/vibrator/StartSequentialEffectStep.java b/services/core/java/com/android/server/vibrator/StartSequentialEffectStep.java
new file mode 100644
index 0000000..080a36c
--- /dev/null
+++ b/services/core/java/com/android/server/vibrator/StartSequentialEffectStep.java
@@ -0,0 +1,370 @@
+/*
+ * 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.vibrator;
+
+import android.annotation.Nullable;
+import android.hardware.vibrator.IVibratorManager;
+import android.os.CombinedVibration;
+import android.os.SystemClock;
+import android.os.Trace;
+import android.os.VibrationEffect;
+import android.os.VibratorInfo;
+import android.os.vibrator.PrebakedSegment;
+import android.os.vibrator.PrimitiveSegment;
+import android.os.vibrator.StepSegment;
+import android.os.vibrator.VibrationEffectSegment;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Starts a sync vibration.
+ *
+ * <p>If this step has successfully started playing a vibration on any vibrator, it will always
+ * add a {@link FinishSequentialEffectStep} to the queue, to be played after all vibrators
+ * have finished all their individual steps.
+ *
+ * <p>If this step does not start any vibrator, it will add a {@link StartSequentialEffectStep} if
+ * the sequential effect isn't finished yet.
+ *
+ * <p>TODO: this step actually does several things: multiple HAL calls to sync the vibrators,
+ * as well as dispatching the underlying vibrator instruction calls (which need to be done before
+ * triggering the synced effects). This role/encapsulation could probably be improved to split up
+ * the grouped HAL calls here, as well as to clarify the role of dispatching VibratorSteps between
+ * this class and the controller.
+ */
+final class StartSequentialEffectStep extends Step {
+ public final CombinedVibration.Sequential sequentialEffect;
+ public final int currentIndex;
+
+ private long mVibratorsOnMaxDuration;
+
+ /** Start a sequential effect at the beginning. */
+ StartSequentialEffectStep(VibrationStepConductor conductor,
+ CombinedVibration.Sequential effect) {
+ this(conductor, SystemClock.uptimeMillis() + effect.getDelays().get(0), effect,
+ /* index= */ 0);
+ }
+
+ /** Continue a SequentialEffect from the specified index. */
+ private StartSequentialEffectStep(VibrationStepConductor conductor, long startTime,
+ CombinedVibration.Sequential effect, int index) {
+ super(conductor, startTime);
+ sequentialEffect = effect;
+ currentIndex = index;
+ }
+
+ @Override
+ public long getVibratorOnDuration() {
+ return mVibratorsOnMaxDuration;
+ }
+
+ @Override
+ public List<Step> play() {
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "StartSequentialEffectStep");
+ List<Step> nextSteps = new ArrayList<>();
+ mVibratorsOnMaxDuration = -1;
+ try {
+ if (VibrationThread.DEBUG) {
+ Slog.d(VibrationThread.TAG,
+ "StartSequentialEffectStep for effect #" + currentIndex);
+ }
+ CombinedVibration effect = sequentialEffect.getEffects().get(currentIndex);
+ DeviceEffectMap effectMapping = createEffectToVibratorMapping(effect);
+ if (effectMapping == null) {
+ // Unable to map effects to vibrators, ignore this step.
+ return nextSteps;
+ }
+
+ mVibratorsOnMaxDuration = startVibrating(effectMapping, nextSteps);
+ if (mVibratorsOnMaxDuration > 0) {
+ conductor.vibratorManagerHooks.noteVibratorOn(conductor.getVibration().uid,
+ mVibratorsOnMaxDuration);
+ }
+ } finally {
+ if (mVibratorsOnMaxDuration >= 0) {
+ // It least one vibrator was started then add a finish step to wait for all
+ // active vibrators to finish their individual steps before going to the next.
+ // Otherwise this step was ignored so just go to the next one.
+ Step nextStep =
+ mVibratorsOnMaxDuration > 0 ? new FinishSequentialEffectStep(this)
+ : nextStep();
+ if (nextStep != null) {
+ nextSteps.add(nextStep);
+ }
+ }
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+ }
+ return nextSteps;
+ }
+
+ @Override
+ public List<Step> cancel() {
+ return VibrationStepConductor.EMPTY_STEP_LIST;
+ }
+
+ @Override
+ public void cancelImmediately() {
+ }
+
+ /**
+ * Create the next {@link StartSequentialEffectStep} to play this sequential effect, starting at
+ * the time this method is called, or null if sequence is complete.
+ */
+ @Nullable
+ Step nextStep() {
+ int nextIndex = currentIndex + 1;
+ if (nextIndex >= sequentialEffect.getEffects().size()) {
+ return null;
+ }
+ long nextEffectDelay = sequentialEffect.getDelays().get(nextIndex);
+ long nextStartTime = SystemClock.uptimeMillis() + nextEffectDelay;
+ return new StartSequentialEffectStep(conductor, nextStartTime, sequentialEffect,
+ nextIndex);
+ }
+
+ /** Create a mapping of individual {@link VibrationEffect} to available vibrators. */
+ @Nullable
+ private DeviceEffectMap createEffectToVibratorMapping(
+ CombinedVibration effect) {
+ if (effect instanceof CombinedVibration.Mono) {
+ return new DeviceEffectMap((CombinedVibration.Mono) effect);
+ }
+ if (effect instanceof CombinedVibration.Stereo) {
+ return new DeviceEffectMap((CombinedVibration.Stereo) effect);
+ }
+ return null;
+ }
+
+ /**
+ * Starts playing effects on designated vibrators, in sync.
+ *
+ * @param effectMapping The {@link CombinedVibration} mapped to this device vibrators
+ * @param nextSteps An output list to accumulate the future {@link Step
+ * Steps} created
+ * by this method, typically one for each vibrator that has
+ * successfully started vibrating on this step.
+ * @return The duration, in millis, of the {@link CombinedVibration}. Repeating
+ * waveforms return {@link Long#MAX_VALUE}. Zero or negative values indicate the vibrators
+ * have ignored all effects.
+ */
+ private long startVibrating(
+ DeviceEffectMap effectMapping, List<Step> nextSteps) {
+ int vibratorCount = effectMapping.size();
+ if (vibratorCount == 0) {
+ // No effect was mapped to any available vibrator.
+ return 0;
+ }
+
+ AbstractVibratorStep[] steps = new AbstractVibratorStep[vibratorCount];
+ long vibrationStartTime = SystemClock.uptimeMillis();
+ for (int i = 0; i < vibratorCount; i++) {
+ steps[i] = conductor.nextVibrateStep(vibrationStartTime,
+ conductor.getVibrators().get(effectMapping.vibratorIdAt(i)),
+ effectMapping.effectAt(i),
+ /* segmentIndex= */ 0, /* vibratorOffTimeout= */ 0);
+ }
+
+ if (steps.length == 1) {
+ // No need to prepare and trigger sync effects on a single vibrator.
+ return startVibrating(steps[0], nextSteps);
+ }
+
+ // This synchronization of vibrators should be executed one at a time, even if we are
+ // vibrating different sets of vibrators in parallel. The manager can only prepareSynced
+ // one set of vibrators at a time.
+ // This property is guaranteed by there only being one thread (VibrationThread) executing
+ // one Step at a time, so there's no need to hold the state lock. Callbacks will be
+ // delivered asynchronously but enqueued until the step processing is finished.
+ boolean hasPrepared = false;
+ boolean hasTriggered = false;
+ long maxDuration = 0;
+ try {
+ hasPrepared = conductor.vibratorManagerHooks.prepareSyncedVibration(
+ effectMapping.getRequiredSyncCapabilities(),
+ effectMapping.getVibratorIds());
+
+ for (AbstractVibratorStep step : steps) {
+ long duration = startVibrating(step, nextSteps);
+ if (duration < 0) {
+ // One vibrator has failed, fail this entire sync attempt.
+ return maxDuration = -1;
+ }
+ maxDuration = Math.max(maxDuration, duration);
+ }
+
+ // Check if sync was prepared and if any step was accepted by a vibrator,
+ // otherwise there is nothing to trigger here.
+ if (hasPrepared && maxDuration > 0) {
+ hasTriggered = conductor.vibratorManagerHooks.triggerSyncedVibration(
+ getVibration().id);
+ }
+ return maxDuration;
+ } finally {
+ if (hasPrepared && !hasTriggered) {
+ // Trigger has failed or all steps were ignored by the vibrators.
+ conductor.vibratorManagerHooks.cancelSyncedVibration();
+ nextSteps.clear();
+ } else if (maxDuration < 0) {
+ // Some vibrator failed without being prepared so other vibrators might be
+ // active. Cancel and remove every pending step from output list.
+ for (int i = nextSteps.size() - 1; i >= 0; i--) {
+ nextSteps.remove(i).cancelImmediately();
+ }
+ }
+ }
+ }
+
+ private long startVibrating(AbstractVibratorStep step, List<Step> nextSteps) {
+ nextSteps.addAll(step.play());
+ long stepDuration = step.getVibratorOnDuration();
+ if (stepDuration < 0) {
+ // Step failed, so return negative duration to propagate failure.
+ return stepDuration;
+ }
+ // Return the longest estimation for the entire effect.
+ return Math.max(stepDuration, step.effect.getDuration());
+ }
+
+ /**
+ * Map a {@link CombinedVibration} to the vibrators available on the device.
+ *
+ * <p>This contains the logic to find the capabilities required from {@link IVibratorManager} to
+ * play all of the effects in sync.
+ */
+ final class DeviceEffectMap {
+ private final SparseArray<VibrationEffect.Composed> mVibratorEffects;
+ private final int[] mVibratorIds;
+ private final long mRequiredSyncCapabilities;
+
+ DeviceEffectMap(CombinedVibration.Mono mono) {
+ SparseArray<VibratorController> vibrators = conductor.getVibrators();
+ mVibratorEffects = new SparseArray<>(vibrators.size());
+ mVibratorIds = new int[vibrators.size()];
+ for (int i = 0; i < vibrators.size(); i++) {
+ int vibratorId = vibrators.keyAt(i);
+ VibratorInfo vibratorInfo = vibrators.valueAt(i).getVibratorInfo();
+ VibrationEffect effect = conductor.deviceEffectAdapter.apply(
+ mono.getEffect(), vibratorInfo);
+ if (effect instanceof VibrationEffect.Composed) {
+ mVibratorEffects.put(vibratorId, (VibrationEffect.Composed) effect);
+ mVibratorIds[i] = vibratorId;
+ }
+ }
+ mRequiredSyncCapabilities = calculateRequiredSyncCapabilities(mVibratorEffects);
+ }
+
+ DeviceEffectMap(CombinedVibration.Stereo stereo) {
+ SparseArray<VibratorController> vibrators = conductor.getVibrators();
+ SparseArray<VibrationEffect> stereoEffects = stereo.getEffects();
+ mVibratorEffects = new SparseArray<>();
+ for (int i = 0; i < stereoEffects.size(); i++) {
+ int vibratorId = stereoEffects.keyAt(i);
+ if (vibrators.contains(vibratorId)) {
+ VibratorInfo vibratorInfo = vibrators.valueAt(i).getVibratorInfo();
+ VibrationEffect effect = conductor.deviceEffectAdapter.apply(
+ stereoEffects.valueAt(i), vibratorInfo);
+ if (effect instanceof VibrationEffect.Composed) {
+ mVibratorEffects.put(vibratorId, (VibrationEffect.Composed) effect);
+ }
+ }
+ }
+ mVibratorIds = new int[mVibratorEffects.size()];
+ for (int i = 0; i < mVibratorEffects.size(); i++) {
+ mVibratorIds[i] = mVibratorEffects.keyAt(i);
+ }
+ mRequiredSyncCapabilities = calculateRequiredSyncCapabilities(mVibratorEffects);
+ }
+
+ /**
+ * Return the number of vibrators mapped to play the {@link CombinedVibration} on this
+ * device.
+ */
+ public int size() {
+ return mVibratorIds.length;
+ }
+
+ /**
+ * Return all capabilities required to play the {@link CombinedVibration} in
+ * between calls to {@link IVibratorManager#prepareSynced} and
+ * {@link IVibratorManager#triggerSynced}.
+ */
+ public long getRequiredSyncCapabilities() {
+ return mRequiredSyncCapabilities;
+ }
+
+ /** Return all vibrator ids mapped to play the {@link CombinedVibration}. */
+ public int[] getVibratorIds() {
+ return mVibratorIds;
+ }
+
+ /** Return the id of the vibrator at given index. */
+ public int vibratorIdAt(int index) {
+ return mVibratorEffects.keyAt(index);
+ }
+
+ /** Return the {@link VibrationEffect} at given index. */
+ public VibrationEffect.Composed effectAt(int index) {
+ return mVibratorEffects.valueAt(index);
+ }
+
+ /**
+ * Return all capabilities required from the {@link IVibratorManager} to prepare and
+ * trigger all given effects in sync.
+ *
+ * @return {@link IVibratorManager#CAP_SYNC} together with all required
+ * IVibratorManager.CAP_PREPARE_* and IVibratorManager.CAP_MIXED_TRIGGER_* capabilities.
+ */
+ private long calculateRequiredSyncCapabilities(
+ SparseArray<VibrationEffect.Composed> effects) {
+ long prepareCap = 0;
+ for (int i = 0; i < effects.size(); i++) {
+ VibrationEffectSegment firstSegment = effects.valueAt(i).getSegments().get(0);
+ if (firstSegment instanceof StepSegment) {
+ prepareCap |= IVibratorManager.CAP_PREPARE_ON;
+ } else if (firstSegment instanceof PrebakedSegment) {
+ prepareCap |= IVibratorManager.CAP_PREPARE_PERFORM;
+ } else if (firstSegment instanceof PrimitiveSegment) {
+ prepareCap |= IVibratorManager.CAP_PREPARE_COMPOSE;
+ }
+ }
+ int triggerCap = 0;
+ if (requireMixedTriggerCapability(prepareCap, IVibratorManager.CAP_PREPARE_ON)) {
+ triggerCap |= IVibratorManager.CAP_MIXED_TRIGGER_ON;
+ }
+ if (requireMixedTriggerCapability(prepareCap, IVibratorManager.CAP_PREPARE_PERFORM)) {
+ triggerCap |= IVibratorManager.CAP_MIXED_TRIGGER_PERFORM;
+ }
+ if (requireMixedTriggerCapability(prepareCap, IVibratorManager.CAP_PREPARE_COMPOSE)) {
+ triggerCap |= IVibratorManager.CAP_MIXED_TRIGGER_COMPOSE;
+ }
+ return IVibratorManager.CAP_SYNC | prepareCap | triggerCap;
+ }
+
+ /**
+ * Return true if {@code prepareCapabilities} contains this {@code capability} mixed with
+ * different ones, requiring a mixed trigger capability from the vibrator manager for
+ * syncing all effects.
+ */
+ private boolean requireMixedTriggerCapability(long prepareCapabilities, long capability) {
+ return (prepareCapabilities & capability) != 0
+ && (prepareCapabilities & ~capability) != 0;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/vibrator/Step.java b/services/core/java/com/android/server/vibrator/Step.java
new file mode 100644
index 0000000..042e8a0
--- /dev/null
+++ b/services/core/java/com/android/server/vibrator/Step.java
@@ -0,0 +1,103 @@
+/*
+ * 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.vibrator;
+
+import android.annotation.NonNull;
+import android.os.CombinedVibration;
+import android.os.SystemClock;
+import android.os.VibrationEffect;
+
+import java.util.List;
+
+/**
+ * Represent a single step for playing a vibration.
+ *
+ * <p>Every step has a start time, which can be used to apply delays between steps while
+ * executing them in sequence.
+ */
+abstract class Step implements Comparable<Step> {
+ public final VibrationStepConductor conductor;
+ public final long startTime;
+
+ Step(VibrationStepConductor conductor, long startTime) {
+ this.conductor = conductor;
+ this.startTime = startTime;
+ }
+
+ protected Vibration getVibration() {
+ return conductor.getVibration();
+ }
+
+ /**
+ * Returns true if this step is a clean up step and not part of a {@link VibrationEffect} or
+ * {@link CombinedVibration}.
+ */
+ public boolean isCleanUp() {
+ return false;
+ }
+
+ /** Play this step, returning a (possibly empty) list of next steps. */
+ @NonNull
+ public abstract List<Step> play();
+
+ /**
+ * Cancel this pending step and return a (possibly empty) list of clean-up steps that should
+ * be played to gracefully cancel this step.
+ */
+ @NonNull
+ public abstract List<Step> cancel();
+
+ /** Cancel this pending step immediately, skipping any clean-up. */
+ public abstract void cancelImmediately();
+
+ /**
+ * Return the duration the vibrator was turned on when this step was played.
+ *
+ * @return A positive duration that the vibrator was turned on for by this step;
+ * Zero if the segment is not supported, the step was not played yet or vibrator was never
+ * turned on by this step; A negative value if the vibrator call has failed.
+ */
+ public long getVibratorOnDuration() {
+ return 0;
+ }
+
+ /**
+ * Return true to run this step right after a vibrator has notified vibration completed,
+ * used to resume steps waiting on vibrator callbacks with a timeout.
+ */
+ public boolean acceptVibratorCompleteCallback(int vibratorId) {
+ return false;
+ }
+
+ /**
+ * Returns the time in millis to wait before playing this step. This is performed
+ * while holding the queue lock, so should not rely on potentially slow operations.
+ */
+ public long calculateWaitTime() {
+ if (startTime == Long.MAX_VALUE) {
+ // This step don't have a predefined start time, it's just marked to be executed
+ // after all other steps have finished.
+ return 0;
+ }
+ return Math.max(0, startTime - SystemClock.uptimeMillis());
+ }
+
+ @Override
+ public int compareTo(Step o) {
+ return Long.compare(startTime, o.startTime);
+ }
+}
diff --git a/services/core/java/com/android/server/vibrator/TurnOffVibratorStep.java b/services/core/java/com/android/server/vibrator/TurnOffVibratorStep.java
new file mode 100644
index 0000000..297ef56
--- /dev/null
+++ b/services/core/java/com/android/server/vibrator/TurnOffVibratorStep.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.vibrator;
+
+import android.os.SystemClock;
+import android.os.Trace;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Represents a step to turn the vibrator off.
+ *
+ * <p>This runs after a timeout on the expected time the vibrator should have finished playing,
+ * and can be brought forward by vibrator complete callbacks. The step shouldn't be skipped, even
+ * if the vibrator-complete callback was received, as some implementations still rely on the
+ * "off" call to actually stop.
+ */
+final class TurnOffVibratorStep extends AbstractVibratorStep {
+
+ TurnOffVibratorStep(VibrationStepConductor conductor, long startTime,
+ VibratorController controller) {
+ super(conductor, startTime, controller, /* effect= */ null, /* index= */ -1, startTime);
+ }
+
+ @Override
+ public boolean isCleanUp() {
+ return true;
+ }
+
+ @Override
+ public List<Step> cancel() {
+ return Arrays.asList(
+ new TurnOffVibratorStep(conductor, SystemClock.uptimeMillis(), controller));
+ }
+
+ @Override
+ public void cancelImmediately() {
+ stopVibrating();
+ }
+
+ @Override
+ public List<Step> play() {
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "TurnOffVibratorStep");
+ try {
+ stopVibrating();
+ return VibrationStepConductor.EMPTY_STEP_LIST;
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/vibrator/VibrationStepConductor.java b/services/core/java/com/android/server/vibrator/VibrationStepConductor.java
new file mode 100644
index 0000000..3667631
--- /dev/null
+++ b/services/core/java/com/android/server/vibrator/VibrationStepConductor.java
@@ -0,0 +1,431 @@
+/*
+ * 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.vibrator;
+
+import android.annotation.Nullable;
+import android.os.Build;
+import android.os.CombinedVibration;
+import android.os.VibrationEffect;
+import android.os.vibrator.PrebakedSegment;
+import android.os.vibrator.PrimitiveSegment;
+import android.os.vibrator.RampSegment;
+import android.os.vibrator.VibrationEffectSegment;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.PriorityQueue;
+import java.util.Queue;
+
+/**
+ * Creates and manages a queue of steps for performing a VibrationEffect, as well as coordinating
+ * dispatch of callbacks.
+ *
+ * <p>In general, methods in this class are intended to be called only by a single instance of
+ * VibrationThread. The only thread-safe methods for calling from other threads are the "notify"
+ * methods (which should never be used from the VibrationThread thread).
+ */
+final class VibrationStepConductor {
+ private static final boolean DEBUG = VibrationThread.DEBUG;
+ private static final String TAG = VibrationThread.TAG;
+
+ /**
+ * Extra timeout added to the end of each vibration step to ensure it finishes even when
+ * vibrator callbacks are lost.
+ */
+ static final long CALLBACKS_EXTRA_TIMEOUT = 1_000;
+ /** Threshold to prevent the ramp off steps from trying to set extremely low amplitudes. */
+ static final float RAMP_OFF_AMPLITUDE_MIN = 1e-3f;
+ static final List<Step> EMPTY_STEP_LIST = new ArrayList<>();
+
+ private final Object mLock = new Object();
+
+ // Used within steps.
+ public final VibrationSettings vibrationSettings;
+ public final DeviceVibrationEffectAdapter deviceEffectAdapter;
+ public final VibrationThread.VibratorManagerHooks vibratorManagerHooks;
+
+ private final Vibration mVibration;
+ private final SparseArray<VibratorController> mVibrators = new SparseArray<>();
+
+ private final PriorityQueue<Step> mNextSteps = new PriorityQueue<>();
+ private final Queue<Step> mPendingOnVibratorCompleteSteps = new LinkedList<>();
+ @GuardedBy("mLock")
+ private Queue<Integer> mCompletionNotifiedVibrators = new LinkedList<>();
+
+ private int mPendingVibrateSteps;
+ private int mRemainingStartSequentialEffectSteps;
+ private int mSuccessfulVibratorOnSteps;
+
+ VibrationStepConductor(Vibration vib, VibrationSettings vibrationSettings,
+ DeviceVibrationEffectAdapter effectAdapter,
+ SparseArray<VibratorController> availableVibrators,
+ VibrationThread.VibratorManagerHooks vibratorManagerHooks) {
+ this.mVibration = vib;
+ this.vibrationSettings = vibrationSettings;
+ this.deviceEffectAdapter = effectAdapter;
+ this.vibratorManagerHooks = vibratorManagerHooks;
+
+ CombinedVibration effect = vib.getEffect();
+ for (int i = 0; i < availableVibrators.size(); i++) {
+ if (effect.hasVibrator(availableVibrators.keyAt(i))) {
+ mVibrators.put(availableVibrators.keyAt(i), availableVibrators.valueAt(i));
+ }
+ }
+ }
+
+ @Nullable
+ AbstractVibratorStep nextVibrateStep(long startTime, VibratorController controller,
+ VibrationEffect.Composed effect, int segmentIndex,
+ long previousStepVibratorOffTimeout) {
+ if (Build.IS_DEBUGGABLE) {
+ expectIsVibrationThread(true);
+ }
+ if (segmentIndex >= effect.getSegments().size()) {
+ segmentIndex = effect.getRepeatIndex();
+ }
+ if (segmentIndex < 0) {
+ // No more segments to play, last step is to complete the vibration on this vibrator.
+ return new CompleteEffectVibratorStep(this, startTime, /* cancelled= */ false,
+ controller, previousStepVibratorOffTimeout);
+ }
+
+ VibrationEffectSegment segment = effect.getSegments().get(segmentIndex);
+ if (segment instanceof PrebakedSegment) {
+ return new PerformPrebakedVibratorStep(this, startTime, controller, effect,
+ segmentIndex, previousStepVibratorOffTimeout);
+ }
+ if (segment instanceof PrimitiveSegment) {
+ return new ComposePrimitivesVibratorStep(this, startTime, controller, effect,
+ segmentIndex, previousStepVibratorOffTimeout);
+ }
+ if (segment instanceof RampSegment) {
+ return new ComposePwleVibratorStep(this, startTime, controller, effect, segmentIndex,
+ previousStepVibratorOffTimeout);
+ }
+ return new SetAmplitudeVibratorStep(this, startTime, controller, effect, segmentIndex,
+ previousStepVibratorOffTimeout);
+ }
+
+ /** Called when this conductor is going to be started running by the VibrationThread. */
+ public void prepareToStart() {
+ if (Build.IS_DEBUGGABLE) {
+ expectIsVibrationThread(true);
+ }
+ CombinedVibration.Sequential sequentialEffect = toSequential(mVibration.getEffect());
+ mPendingVibrateSteps++;
+ // This count is decremented at the completion of the step, so we don't subtract one.
+ mRemainingStartSequentialEffectSteps = sequentialEffect.getEffects().size();
+ mNextSteps.offer(new StartSequentialEffectStep(this, sequentialEffect));
+ }
+
+ public Vibration getVibration() {
+ // No thread assertion: immutable
+ return mVibration;
+ }
+
+ SparseArray<VibratorController> getVibrators() {
+ // No thread assertion: immutable
+ return mVibrators;
+ }
+
+ public boolean isFinished() {
+ if (Build.IS_DEBUGGABLE) {
+ expectIsVibrationThread(true);
+ }
+ // 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();
+ }
+
+ /**
+ * Calculate the {@link Vibration.Status} based on the current queue state and the expected
+ * number of {@link StartSequentialEffectStep} to be played.
+ */
+ public Vibration.Status calculateVibrationStatus() {
+ if (Build.IS_DEBUGGABLE) {
+ expectIsVibrationThread(true);
+ }
+
+ if (mPendingVibrateSteps > 0
+ || mRemainingStartSequentialEffectSteps > 0) {
+ return Vibration.Status.RUNNING;
+ }
+ // No pending steps, and something happened.
+ if (mSuccessfulVibratorOnSteps > 0) {
+ return Vibration.Status.FINISHED;
+ }
+ // If no step was able to turn the vibrator ON successfully.
+ return Vibration.Status.IGNORED_UNSUPPORTED;
+ }
+
+ /**
+ * Blocks until the next step is due to run. The wait here may be interrupted by calling
+ * {@link #notifyWakeUp} or other "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.
+ *
+ * @return true if the method waited at all, or false if a step is ready to run now.
+ */
+ 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) {
+ 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;
+ }
+ }
+ }
+
+ /**
+ * Play and remove the step at the top of this queue, and also adds the next steps generated
+ * to be played next.
+ */
+ public void runNextStep() {
+ if (Build.IS_DEBUGGABLE) {
+ expectIsVibrationThread(true);
+ }
+ // In theory a completion callback could have come in between the wait finishing and
+ // this method starting, but that only means the step is due now anyway, so it's reasonable
+ // to run it before processing callbacks as the window is tiny.
+ Step nextStep = pollNext();
+ if (nextStep != null) {
+ List<Step> nextSteps = nextStep.play();
+ if (nextStep.getVibratorOnDuration() > 0) {
+ mSuccessfulVibratorOnSteps++;
+ }
+ if (nextStep instanceof StartSequentialEffectStep) {
+ mRemainingStartSequentialEffectSteps--;
+ }
+ if (!nextStep.isCleanUp()) {
+ mPendingVibrateSteps--;
+ }
+ for (int i = 0; i < nextSteps.size(); i++) {
+ mPendingVibrateSteps += nextSteps.get(i).isCleanUp() ? 0 : 1;
+ }
+ mNextSteps.addAll(nextSteps);
+ }
+ }
+
+ /**
+ * Wake up the execution thread, which may be waiting until the next step is due.
+ * The caller is responsible for diverting VibrationThread execution.
+ *
+ * <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.
+ */
+ public void notifyWakeUp() {
+ if (Build.IS_DEBUGGABLE) {
+ expectIsVibrationThread(false);
+ }
+
+ synchronized (mLock) {
+ mLock.notify();
+ }
+ }
+
+ /**
+ * Notify the conductor that a vibrator has completed its work.
+ *
+ * <p>This is a lightweight method intended to be called directly via native callbacks.
+ * The state update is recorded for processing on the main execution thread (VibrationThread).
+ */
+ public void notifyVibratorComplete(int vibratorId) {
+ if (Build.IS_DEBUGGABLE) {
+ expectIsVibrationThread(false);
+ }
+
+ if (DEBUG) {
+ Slog.d(TAG, "Vibration complete reported by vibrator " + vibratorId);
+ }
+
+ synchronized (mLock) {
+ mCompletionNotifiedVibrators.offer(vibratorId);
+ mLock.notify();
+ }
+ }
+
+ /**
+ * Notify that a VibratorManager sync operation has completed.
+ *
+ * <p>This is a lightweight method intended to be called directly via native callbacks.
+ * The state update is recorded for processing on the main execution thread
+ * (VibrationThread).
+ */
+ public void notifySyncedVibrationComplete() {
+ if (Build.IS_DEBUGGABLE) {
+ expectIsVibrationThread(false);
+ }
+
+ if (DEBUG) {
+ Slog.d(TAG, "Synced vibration complete reported by vibrator manager");
+ }
+
+ synchronized (mLock) {
+ for (int i = 0; i < mVibrators.size(); i++) {
+ mCompletionNotifiedVibrators.offer(mVibrators.keyAt(i));
+ }
+ mLock.notify();
+ }
+ }
+
+ /**
+ * Cancel the current queue, replacing all remaining steps with respective clean-up steps.
+ *
+ * <p>This will remove all steps and replace them with respective
+ * {@link Step#cancel()}.
+ */
+ public void cancel() {
+ if (Build.IS_DEBUGGABLE) {
+ expectIsVibrationThread(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<>();
+ Step step;
+ while ((step = pollNext()) != null) {
+ cleanUpSteps.addAll(step.cancel());
+ }
+ // All steps generated by Step.cancel() should be clean-up steps.
+ mPendingVibrateSteps = 0;
+ mNextSteps.addAll(cleanUpSteps);
+ }
+
+ /**
+ * Cancel the current queue immediately, clearing all remaining steps and skipping clean-up.
+ *
+ * <p>This will remove and trigger {@link Step#cancelImmediately()} in all steps, in order.
+ */
+ public void cancelImmediately() {
+ if (Build.IS_DEBUGGABLE) {
+ expectIsVibrationThread(true);
+ }
+
+ Step step;
+ while ((step = pollNext()) != null) {
+ step.cancelImmediately();
+ }
+ 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.
+ *
+ * <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() {
+ 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();
+ Iterator<Step> it = mNextSteps.iterator();
+ while (it.hasNext()) {
+ Step step = it.next();
+ if (step.acceptVibratorCompleteCallback(vibratorId)) {
+ it.remove();
+ mPendingOnVibratorCompleteSteps.offer(step);
+ break;
+ }
+ }
+ }
+ }
+
+ private static CombinedVibration.Sequential toSequential(CombinedVibration effect) {
+ if (effect instanceof CombinedVibration.Sequential) {
+ return (CombinedVibration.Sequential) effect;
+ }
+ return (CombinedVibration.Sequential) CombinedVibration.startSequential()
+ .addNext(effect)
+ .combine();
+ }
+
+ /**
+ * This check is used for debugging and documentation to indicate the thread that's expected
+ * to invoke a given public method on this class. Most methods are only invoked by
+ * VibrationThread, which is where all the steps and HAL calls should be made. Other threads
+ * should only signal to the execution flow being run by VibrationThread.
+ */
+ private static void expectIsVibrationThread(boolean isVibrationThread) {
+ if ((Thread.currentThread() instanceof VibrationThread) != isVibrationThread) {
+ Slog.wtfStack("VibrationStepConductor",
+ "Thread caller assertion failed, expected isVibrationThread="
+ + isVibrationThread);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/vibrator/VibrationThread.java b/services/core/java/com/android/server/vibrator/VibrationThread.java
index 1f1f40b..3fef7f2 100644
--- a/services/core/java/com/android/server/vibrator/VibrationThread.java
+++ b/services/core/java/com/android/server/vibrator/VibrationThread.java
@@ -16,59 +16,21 @@
package com.android.server.vibrator;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.hardware.vibrator.IVibratorManager;
-import android.os.CombinedVibration;
import android.os.IBinder;
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
-import android.os.SystemClock;
import android.os.Trace;
-import android.os.VibrationEffect;
-import android.os.VibratorInfo;
import android.os.WorkSource;
-import android.os.vibrator.PrebakedSegment;
-import android.os.vibrator.PrimitiveSegment;
-import android.os.vibrator.RampSegment;
-import android.os.vibrator.StepSegment;
-import android.os.vibrator.VibrationEffectSegment;
import android.util.Slog;
import android.util.SparseArray;
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.app.IBatteryStats;
-import com.android.internal.util.FrameworkStatsLog;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
import java.util.NoSuchElementException;
-import java.util.PriorityQueue;
-import java.util.Queue;
/** Plays a {@link Vibration} in dedicated thread. */
final class VibrationThread extends Thread implements IBinder.DeathRecipient {
- private static final String TAG = "VibrationThread";
- private static final boolean DEBUG = false;
-
- /**
- * Extra timeout added to the end of each vibration step to ensure it finishes even when
- * vibrator callbacks are lost.
- */
- private static final long CALLBACKS_EXTRA_TIMEOUT = 1_000;
-
- /** Threshold to prevent the ramp off steps from trying to set extremely low amplitudes. */
- private static final float RAMP_OFF_AMPLITUDE_MIN = 1e-3f;
-
- /** Fixed large duration used to note repeating vibrations to {@link IBatteryStats}. */
- private static final long BATTERY_STATS_REPEATING_VIBRATION_DURATION = 5_000;
-
- private static final List<Step> EMPTY_STEP_LIST = new ArrayList<>();
+ static final String TAG = "VibrationThread";
+ static final boolean DEBUG = false;
/** Calls into VibratorManager functionality needed for playing a {@link Vibration}. */
interface VibratorManagerHooks {
@@ -94,6 +56,15 @@
void cancelSyncedVibration();
/**
+ * Record that a vibrator was turned on, and may remain on for the specified duration,
+ * on behalf of the given uid.
+ */
+ void noteVibratorOn(int uid, long duration);
+
+ /** Record that a vibrator was turned off, on behalf of the given uid. */
+ void noteVibratorOff(int uid);
+
+ /**
* Tell the manager that the currently active vibration has completed its vibration, from
* the perspective of the Effect. However, the VibrationThread may still be continuing with
* cleanup tasks, and should not be given new work until {@link #onVibrationThreadReleased}
@@ -108,16 +79,10 @@
void onVibrationThreadReleased();
}
- private final Object mLock = new Object();
- private final WorkSource mWorkSource;
private final PowerManager.WakeLock mWakeLock;
- private final IBatteryStats mBatteryStatsService;
- private final VibrationSettings mVibrationSettings;
- private final DeviceVibrationEffectAdapter mDeviceEffectAdapter;
- private final Vibration mVibration;
- private final VibratorManagerHooks mVibratorManagerHooks;
- private final SparseArray<VibratorController> mVibrators = new SparseArray<>();
- private final StepQueue mStepQueue = new StepQueue();
+ private final VibrationThread.VibratorManagerHooks mVibratorManagerHooks;
+
+ private final VibrationStepConductor mStepConductor;
private volatile boolean mStop;
private volatile boolean mForceStop;
@@ -127,30 +92,15 @@
VibrationThread(Vibration vib, VibrationSettings vibrationSettings,
DeviceVibrationEffectAdapter effectAdapter,
SparseArray<VibratorController> availableVibrators, PowerManager.WakeLock wakeLock,
- IBatteryStats batteryStatsService, VibratorManagerHooks vibratorManagerHooks) {
- mVibration = vib;
- mVibrationSettings = vibrationSettings;
- mDeviceEffectAdapter = effectAdapter;
+ VibratorManagerHooks vibratorManagerHooks) {
mVibratorManagerHooks = vibratorManagerHooks;
- mWorkSource = new WorkSource(mVibration.uid);
mWakeLock = wakeLock;
- mBatteryStatsService = batteryStatsService;
-
- CombinedVibration effect = vib.getEffect();
- for (int i = 0; i < availableVibrators.size(); i++) {
- if (effect.hasVibrator(availableVibrators.keyAt(i))) {
- mVibrators.put(availableVibrators.keyAt(i), availableVibrators.valueAt(i));
- }
- }
+ mStepConductor = new VibrationStepConductor(vib, vibrationSettings, effectAdapter,
+ availableVibrators, vibratorManagerHooks);
}
Vibration getVibration() {
- return mVibration;
- }
-
- @VisibleForTesting
- SparseArray<VibratorController> getVibrators() {
- return mVibrators;
+ return mStepConductor.getVibration();
}
@Override
@@ -179,12 +129,14 @@
/** Runs the VibrationThread ensuring that the wake lock is acquired and released. */
private void runWithWakeLock() {
- mWakeLock.setWorkSource(mWorkSource);
+ WorkSource workSource = new WorkSource(mStepConductor.getVibration().uid);
+ mWakeLock.setWorkSource(workSource);
mWakeLock.acquire();
try {
runWithWakeLockAndDeathLink();
} finally {
mWakeLock.release();
+ mWakeLock.setWorkSource(null);
}
}
@@ -193,8 +145,9 @@
* Called from within runWithWakeLock.
*/
private void runWithWakeLockAndDeathLink() {
+ IBinder vibrationBinderToken = mStepConductor.getVibration().token;
try {
- mVibration.token.linkToDeath(this, 0);
+ vibrationBinderToken.linkToDeath(this, 0);
} catch (RemoteException e) {
Slog.e(TAG, "Error linking vibration to token death", e);
clientVibrationCompleteIfNotAlready(Vibration.Status.IGNORED_ERROR_TOKEN);
@@ -206,7 +159,7 @@
playVibration();
} finally {
try {
- mVibration.token.unlinkToDeath(this, 0);
+ vibrationBinderToken.unlinkToDeath(this, 0);
} catch (NoSuchElementException e) {
Slog.wtf(TAG, "Failed to unlink token", e);
}
@@ -220,12 +173,10 @@
return;
}
mStop = true;
- synchronized (mLock) {
- if (DEBUG) {
- Slog.d(TAG, "Vibration cancelled");
- }
- mLock.notify();
+ if (DEBUG) {
+ Slog.d(TAG, "Vibration cancelled");
}
+ mStepConductor.notifyWakeUp();
}
/** Cancel current vibration and shuts off the vibrators immediately. */
@@ -234,37 +185,21 @@
// Already forced the thread to stop, wait for it to finish.
return;
}
- mStop = mForceStop = true;
- synchronized (mLock) {
- if (DEBUG) {
- Slog.d(TAG, "Vibration cancelled immediately");
- }
- mLock.notify();
+ if (DEBUG) {
+ Slog.d(TAG, "Vibration cancelled immediately");
}
+ mStop = mForceStop = true;
+ mStepConductor.notifyWakeUp();
}
/** Notify current vibration that a synced step has completed. */
public void syncedVibrationComplete() {
- synchronized (mLock) {
- if (DEBUG) {
- Slog.d(TAG, "Synced vibration complete reported by vibrator manager");
- }
- for (int i = 0; i < mVibrators.size(); i++) {
- mStepQueue.notifyVibratorComplete(mVibrators.keyAt(i));
- }
- mLock.notify();
- }
+ mStepConductor.notifySyncedVibrationComplete();
}
/** Notify current vibration that a step has completed on given vibrator. */
public void vibratorComplete(int vibratorId) {
- synchronized (mLock) {
- if (DEBUG) {
- Slog.d(TAG, "Vibration complete reported by vibrator " + vibratorId);
- }
- mStepQueue.notifyVibratorComplete(vibratorId);
- mLock.notify();
- }
+ mStepConductor.notifyVibratorComplete(vibratorId);
}
// Indicate that the vibration is complete. This can be called multiple times only for
@@ -273,1387 +208,51 @@
private void clientVibrationCompleteIfNotAlready(Vibration.Status completedStatus) {
if (!mCalledVibrationCompleteCallback) {
mCalledVibrationCompleteCallback = true;
- mVibratorManagerHooks.onVibrationCompleted(mVibration.id, completedStatus);
+ mVibratorManagerHooks.onVibrationCompleted(
+ mStepConductor.getVibration().id, completedStatus);
}
}
private void playVibration() {
Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "playVibration");
try {
- CombinedVibration.Sequential sequentialEffect = toSequential(mVibration.getEffect());
- final int sequentialEffectSize = sequentialEffect.getEffects().size();
- mStepQueue.initializeForEffect(sequentialEffect);
+ mStepConductor.prepareToStart();
- while (!mStepQueue.isFinished()) {
- long waitMillisBeforeNextStep;
- synchronized (mLock) {
- waitMillisBeforeNextStep = mStepQueue.getWaitMillisBeforeNextStep();
- if (waitMillisBeforeNextStep > 0) {
- try {
- mLock.wait(waitMillisBeforeNextStep);
- } catch (InterruptedException e) {
- }
- }
- }
- // Only run the next vibration step if we didn't have to wait in this loop.
- // If we waited then the queue may have changed, so loop again to re-evaluate
- // the scheduling of the queue top element.
- if (waitMillisBeforeNextStep <= 0) {
+ 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) {
if (DEBUG) {
Slog.d(TAG, "Play vibration consuming next step...");
}
// Run the step without holding the main lock, to avoid HAL interactions from
// blocking the thread.
- mStepQueue.runNextStep();
+ 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
- : mStepQueue.calculateVibrationStatus(sequentialEffectSize);
+ : 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) {
- mStepQueue.cancel();
+ mStepConductor.cancel();
}
}
- if (mForceStop) {
- // Cancel every step and stop playing them right away, even clean-up steps.
- mStepQueue.cancelImmediately();
- clientVibrationCompleteIfNotAlready(Vibration.Status.CANCELLED);
- break;
- }
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
-
- private void noteVibratorOn(long duration) {
- try {
- if (duration <= 0) {
- return;
- }
- if (duration == Long.MAX_VALUE) {
- // Repeating duration has started. Report a fixed duration here, noteVibratorOff
- // should be called when this is cancelled.
- duration = BATTERY_STATS_REPEATING_VIBRATION_DURATION;
- }
- mBatteryStatsService.noteVibratorOn(mVibration.uid, duration);
- FrameworkStatsLog.write_non_chained(FrameworkStatsLog.VIBRATOR_STATE_CHANGED,
- mVibration.uid, null, FrameworkStatsLog.VIBRATOR_STATE_CHANGED__STATE__ON,
- duration);
- } catch (RemoteException e) {
- }
- }
-
- private void noteVibratorOff() {
- try {
- mBatteryStatsService.noteVibratorOff(mVibration.uid);
- FrameworkStatsLog.write_non_chained(FrameworkStatsLog.VIBRATOR_STATE_CHANGED,
- mVibration.uid, null, FrameworkStatsLog.VIBRATOR_STATE_CHANGED__STATE__OFF,
- /* duration= */ 0);
- } catch (RemoteException e) {
- }
- }
-
- @Nullable
- private SingleVibratorStep nextVibrateStep(long startTime, VibratorController controller,
- VibrationEffect.Composed effect, int segmentIndex, long vibratorOffTimeout) {
- if (segmentIndex >= effect.getSegments().size()) {
- segmentIndex = effect.getRepeatIndex();
- }
- if (segmentIndex < 0) {
- // No more segments to play, last step is to complete the vibration on this vibrator.
- return new EffectCompleteStep(startTime, /* cancelled= */ false, controller,
- vibratorOffTimeout);
- }
-
- VibrationEffectSegment segment = effect.getSegments().get(segmentIndex);
- if (segment instanceof PrebakedSegment) {
- return new PerformStep(startTime, controller, effect, segmentIndex, vibratorOffTimeout);
- }
- if (segment instanceof PrimitiveSegment) {
- return new ComposePrimitivesStep(startTime, controller, effect, segmentIndex,
- vibratorOffTimeout);
- }
- if (segment instanceof RampSegment) {
- return new ComposePwleStep(startTime, controller, effect, segmentIndex,
- vibratorOffTimeout);
- }
- return new AmplitudeStep(startTime, controller, effect, segmentIndex, vibratorOffTimeout);
- }
-
- private static CombinedVibration.Sequential toSequential(CombinedVibration effect) {
- if (effect instanceof CombinedVibration.Sequential) {
- return (CombinedVibration.Sequential) effect;
- }
- return (CombinedVibration.Sequential) CombinedVibration.startSequential()
- .addNext(effect)
- .combine();
- }
-
- /** Queue for {@link Step Steps}, sorted by their start time. */
- private final class StepQueue {
- @GuardedBy("mLock")
- private final PriorityQueue<Step> mNextSteps = new PriorityQueue<>();
- @GuardedBy("mLock")
- private final Queue<Step> mPendingOnVibratorCompleteSteps = new LinkedList<>();
- @GuardedBy("mLock")
- private final Queue<Integer> mCompletionNotifiedVibrators = new LinkedList<>();
-
- @GuardedBy("mLock")
- private int mPendingVibrateSteps;
- @GuardedBy("mLock")
- private int mConsumedStartVibrateSteps;
- @GuardedBy("mLock")
- private int mSuccessfulVibratorOnSteps;
- @GuardedBy("mLock")
- private boolean mWaitToProcessVibratorCompleteCallbacks;
-
- public void initializeForEffect(@NonNull CombinedVibration.Sequential vibration) {
- synchronized (mLock) {
- mPendingVibrateSteps++;
- mNextSteps.offer(new StartVibrateStep(vibration));
- }
- }
-
- public boolean isFinished() {
- synchronized (mLock) {
- return mPendingOnVibratorCompleteSteps.isEmpty() && mNextSteps.isEmpty();
- }
- }
-
- /**
- * Calculate the {@link Vibration.Status} based on the current queue state and the expected
- * number of {@link StartVibrateStep} to be played.
- */
- public Vibration.Status calculateVibrationStatus(int expectedStartVibrateSteps) {
- synchronized (mLock) {
- if (mPendingVibrateSteps > 0
- || mConsumedStartVibrateSteps < expectedStartVibrateSteps) {
- return Vibration.Status.RUNNING;
- }
- if (mSuccessfulVibratorOnSteps > 0) {
- return Vibration.Status.FINISHED;
- }
- // If no step was able to turn the vibrator ON successfully.
- return Vibration.Status.IGNORED_UNSUPPORTED;
- }
- }
-
- /** Returns the time in millis to wait before calling {@link #runNextStep()}. */
- @GuardedBy("VibrationThread.this.mLock")
- public long getWaitMillisBeforeNextStep() {
- if (!mPendingOnVibratorCompleteSteps.isEmpty()) {
- // Steps resumed by vibrator complete callback should be played right away.
- return 0;
- }
- Step nextStep = mNextSteps.peek();
- return nextStep == null ? 0 : nextStep.calculateWaitTime();
- }
-
- /**
- * Play and remove the step at the top of this queue, and also adds the next steps generated
- * to be played next.
- */
- public void runNextStep() {
- // Vibrator callbacks should wait until the polled step is played and the next steps are
- // added back to the queue, so they can handle the callback.
- markWaitToProcessVibratorCallbacks();
- try {
- Step nextStep = pollNext();
- if (nextStep != null) {
- // This might turn on the vibrator and have a HAL latency. Execute this outside
- // any lock to avoid blocking other interactions with the thread.
- List<Step> nextSteps = nextStep.play();
- synchronized (mLock) {
- if (nextStep.getVibratorOnDuration() > 0) {
- mSuccessfulVibratorOnSteps++;
- }
- if (nextStep instanceof StartVibrateStep) {
- mConsumedStartVibrateSteps++;
- }
- if (!nextStep.isCleanUp()) {
- mPendingVibrateSteps--;
- }
- for (int i = 0; i < nextSteps.size(); i++) {
- mPendingVibrateSteps += nextSteps.get(i).isCleanUp() ? 0 : 1;
- }
- mNextSteps.addAll(nextSteps);
- }
- }
- } finally {
- synchronized (mLock) {
- processVibratorCompleteCallbacks();
- }
- }
- }
-
- /**
- * Notify the vibrator completion.
- *
- * <p>This is a lightweight method that do not trigger any operation from {@link
- * VibratorController}, so it can be called directly from a native callback.
- */
- @GuardedBy("mLock")
- public void notifyVibratorComplete(int vibratorId) {
- mCompletionNotifiedVibrators.offer(vibratorId);
- if (!mWaitToProcessVibratorCompleteCallbacks) {
- // No step is being played or cancelled now, process the callback right away.
- processVibratorCompleteCallbacks();
- }
- }
-
- /**
- * Cancel the current queue, replacing all remaining steps with respective clean-up steps.
- *
- * <p>This will remove all steps and replace them with respective
- * {@link Step#cancel()}.
- */
- public void cancel() {
- // 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.
- markWaitToProcessVibratorCallbacks();
- try {
- List<Step> cleanUpSteps = new ArrayList<>();
- Step step;
- while ((step = pollNext()) != null) {
- cleanUpSteps.addAll(step.cancel());
- }
- synchronized (mLock) {
- // All steps generated by Step.cancel() should be clean-up steps.
- mPendingVibrateSteps = 0;
- mNextSteps.addAll(cleanUpSteps);
- }
- } finally {
- synchronized (mLock) {
- processVibratorCompleteCallbacks();
- }
- }
- }
-
- /**
- * Cancel the current queue immediately, clearing all remaining steps and skipping clean-up.
- *
- * <p>This will remove and trigger {@link Step#cancelImmediately()} in all steps, in order.
- */
- public void cancelImmediately() {
- // Vibrator callbacks should wait until all steps from the queue are properly cancelled.
- markWaitToProcessVibratorCallbacks();
- try {
- Step step;
- while ((step = pollNext()) != null) {
- // This might turn off the vibrator and have a HAL latency. Execute this outside
- // any lock to avoid blocking other interactions with the thread.
- step.cancelImmediately();
- }
- synchronized (mLock) {
- mPendingVibrateSteps = 0;
- }
- } finally {
- synchronized (mLock) {
- processVibratorCompleteCallbacks();
- }
- }
- }
-
- @Nullable
- private Step pollNext() {
- synchronized (mLock) {
- // Prioritize the steps resumed by a vibrator complete callback.
- if (!mPendingOnVibratorCompleteSteps.isEmpty()) {
- return mPendingOnVibratorCompleteSteps.poll();
- }
- return mNextSteps.poll();
- }
- }
-
- private void markWaitToProcessVibratorCallbacks() {
- synchronized (mLock) {
- mWaitToProcessVibratorCompleteCallbacks = true;
- }
- }
-
- /**
- * Notify the step in this queue that should be resumed by the vibrator completion
- * callback and keep it separate to be consumed by {@link #runNextStep()}.
- *
- * <p>This is a lightweight method that do not trigger any operation from {@link
- * VibratorController}, so it can be called directly from a native callback.
- *
- * <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.
- */
- @GuardedBy("mLock")
- private void processVibratorCompleteCallbacks() {
- mWaitToProcessVibratorCompleteCallbacks = false;
- while (!mCompletionNotifiedVibrators.isEmpty()) {
- int vibratorId = mCompletionNotifiedVibrators.poll();
- Iterator<Step> it = mNextSteps.iterator();
- while (it.hasNext()) {
- Step step = it.next();
- if (step.acceptVibratorCompleteCallback(vibratorId)) {
- it.remove();
- mPendingOnVibratorCompleteSteps.offer(step);
- break;
- }
- }
- }
- }
- }
-
- /**
- * Represent a single step for playing a vibration.
- *
- * <p>Every step has a start time, which can be used to apply delays between steps while
- * executing them in sequence.
- */
- private abstract class Step implements Comparable<Step> {
- public final long startTime;
-
- Step(long startTime) {
- this.startTime = startTime;
- }
-
- /**
- * Returns true if this step is a clean up step and not part of a {@link VibrationEffect} or
- * {@link CombinedVibration}.
- */
- public boolean isCleanUp() {
- return false;
- }
-
- /** Play this step, returning a (possibly empty) list of next steps. */
- @NonNull
- public abstract List<Step> play();
-
- /**
- * Cancel this pending step and return a (possibly empty) list of clean-up steps that should
- * be played to gracefully cancel this step.
- */
- @NonNull
- public abstract List<Step> cancel();
-
- /** Cancel this pending step immediately, skipping any clean-up. */
- public abstract void cancelImmediately();
-
- /**
- * Return the duration the vibrator was turned on when this step was played.
- *
- * @return A positive duration that the vibrator was turned on for by this step;
- * Zero if the segment is not supported, the step was not played yet or vibrator was never
- * turned on by this step; A negative value if the vibrator call has failed.
- */
- public long getVibratorOnDuration() {
- return 0;
- }
-
- /**
- * Return true to run this step right after a vibrator has notified vibration completed,
- * used to resume steps waiting on vibrator callbacks with a timeout.
- */
- public boolean acceptVibratorCompleteCallback(int vibratorId) {
- return false;
- }
-
- /**
- * Returns the time in millis to wait before playing this step. This is performed
- * while holding the queue lock, so should not rely on potentially slow operations.
- */
- public long calculateWaitTime() {
- if (startTime == Long.MAX_VALUE) {
- // This step don't have a predefined start time, it's just marked to be executed
- // after all other steps have finished.
- return 0;
- }
- return Math.max(0, startTime - SystemClock.uptimeMillis());
- }
-
- @Override
- public int compareTo(Step o) {
- return Long.compare(startTime, o.startTime);
- }
- }
-
- /**
- * Starts a sync vibration.
- *
- * <p>If this step has successfully started playing a vibration on any vibrator, it will always
- * add a {@link FinishVibrateStep} to the queue, to be played after all vibrators have finished
- * all their individual steps.
- *
- * <p>If this step does not start any vibrator, it will add a {@link StartVibrateStep} if the
- * sequential effect isn't finished yet.
- */
- private final class StartVibrateStep extends Step {
- public final CombinedVibration.Sequential sequentialEffect;
- public final int currentIndex;
-
- private long mVibratorsOnMaxDuration;
-
- StartVibrateStep(CombinedVibration.Sequential effect) {
- this(SystemClock.uptimeMillis() + effect.getDelays().get(0), effect, /* index= */ 0);
- }
-
- StartVibrateStep(long startTime, CombinedVibration.Sequential effect, int index) {
- super(startTime);
- sequentialEffect = effect;
- currentIndex = index;
- }
-
- @Override
- public long getVibratorOnDuration() {
- return mVibratorsOnMaxDuration;
- }
-
- @Override
- public List<Step> play() {
- Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "StartVibrateStep");
- List<Step> nextSteps = new ArrayList<>();
- mVibratorsOnMaxDuration = -1;
- try {
- if (DEBUG) {
- Slog.d(TAG, "StartVibrateStep for effect #" + currentIndex);
- }
- CombinedVibration effect = sequentialEffect.getEffects().get(currentIndex);
- DeviceEffectMap effectMapping = createEffectToVibratorMapping(effect);
- if (effectMapping == null) {
- // Unable to map effects to vibrators, ignore this step.
- return nextSteps;
- }
-
- mVibratorsOnMaxDuration = startVibrating(effectMapping, nextSteps);
- noteVibratorOn(mVibratorsOnMaxDuration);
- } finally {
- if (mVibratorsOnMaxDuration >= 0) {
- // It least one vibrator was started then add a finish step to wait for all
- // active vibrators to finish their individual steps before going to the next.
- // Otherwise this step was ignored so just go to the next one.
- Step nextStep =
- mVibratorsOnMaxDuration > 0 ? new FinishVibrateStep(this) : nextStep();
- if (nextStep != null) {
- nextSteps.add(nextStep);
- }
- }
- Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
- }
- return nextSteps;
- }
-
- @Override
- public List<Step> cancel() {
- return EMPTY_STEP_LIST;
- }
-
- @Override
- public void cancelImmediately() {
- }
-
- /**
- * Create the next {@link StartVibrateStep} to play this sequential effect, starting at the
- * time this method is called, or null if sequence is complete.
- */
- @Nullable
- private Step nextStep() {
- int nextIndex = currentIndex + 1;
- if (nextIndex >= sequentialEffect.getEffects().size()) {
- return null;
- }
- long nextEffectDelay = sequentialEffect.getDelays().get(nextIndex);
- long nextStartTime = SystemClock.uptimeMillis() + nextEffectDelay;
- return new StartVibrateStep(nextStartTime, sequentialEffect, nextIndex);
- }
-
- /** Create a mapping of individual {@link VibrationEffect} to available vibrators. */
- @Nullable
- private DeviceEffectMap createEffectToVibratorMapping(
- CombinedVibration effect) {
- if (effect instanceof CombinedVibration.Mono) {
- return new DeviceEffectMap((CombinedVibration.Mono) effect);
- }
- if (effect instanceof CombinedVibration.Stereo) {
- return new DeviceEffectMap((CombinedVibration.Stereo) effect);
- }
- return null;
- }
-
- /**
- * Starts playing effects on designated vibrators, in sync.
- *
- * @param effectMapping The {@link CombinedVibration} mapped to this device vibrators
- * @param nextSteps An output list to accumulate the future {@link Step Steps} created
- * by this method, typically one for each vibrator that has
- * successfully started vibrating on this step.
- * @return The duration, in millis, of the {@link CombinedVibration}. Repeating
- * waveforms return {@link Long#MAX_VALUE}. Zero or negative values indicate the vibrators
- * have ignored all effects.
- */
- private long startVibrating(DeviceEffectMap effectMapping, List<Step> nextSteps) {
- int vibratorCount = effectMapping.size();
- if (vibratorCount == 0) {
- // No effect was mapped to any available vibrator.
- return 0;
- }
-
- SingleVibratorStep[] steps = new SingleVibratorStep[vibratorCount];
- long vibrationStartTime = SystemClock.uptimeMillis();
- for (int i = 0; i < vibratorCount; i++) {
- steps[i] = nextVibrateStep(vibrationStartTime,
- mVibrators.get(effectMapping.vibratorIdAt(i)),
- effectMapping.effectAt(i),
- /* segmentIndex= */ 0, /* vibratorOffTimeout= */ 0);
- }
-
- if (steps.length == 1) {
- // No need to prepare and trigger sync effects on a single vibrator.
- return startVibrating(steps[0], nextSteps);
- }
-
- // This synchronization of vibrators should be executed one at a time, even if we are
- // vibrating different sets of vibrators in parallel. The manager can only prepareSynced
- // one set of vibrators at a time.
- synchronized (mLock) {
- boolean hasPrepared = false;
- boolean hasTriggered = false;
- long maxDuration = 0;
- try {
- hasPrepared = mVibratorManagerHooks.prepareSyncedVibration(
- effectMapping.getRequiredSyncCapabilities(),
- effectMapping.getVibratorIds());
-
- for (SingleVibratorStep step : steps) {
- long duration = startVibrating(step, nextSteps);
- if (duration < 0) {
- // One vibrator has failed, fail this entire sync attempt.
- return maxDuration = -1;
- }
- maxDuration = Math.max(maxDuration, duration);
- }
-
- // Check if sync was prepared and if any step was accepted by a vibrator,
- // otherwise there is nothing to trigger here.
- if (hasPrepared && maxDuration > 0) {
- hasTriggered = mVibratorManagerHooks.triggerSyncedVibration(mVibration.id);
- }
- return maxDuration;
- } finally {
- if (hasPrepared && !hasTriggered) {
- // Trigger has failed or all steps were ignored by the vibrators.
- mVibratorManagerHooks.cancelSyncedVibration();
- nextSteps.clear();
- } else if (maxDuration < 0) {
- // Some vibrator failed without being prepared so other vibrators might be
- // active. Cancel and remove every pending step from output list.
- for (int i = nextSteps.size() - 1; i >= 0; i--) {
- nextSteps.remove(i).cancelImmediately();
- }
- }
- }
- }
- }
-
- private long startVibrating(SingleVibratorStep step, List<Step> nextSteps) {
- nextSteps.addAll(step.play());
- long stepDuration = step.getVibratorOnDuration();
- if (stepDuration < 0) {
- // Step failed, so return negative duration to propagate failure.
- return stepDuration;
- }
- // Return the longest estimation for the entire effect.
- return Math.max(stepDuration, step.effect.getDuration());
- }
- }
-
- /**
- * Finish a sync vibration started by a {@link StartVibrateStep}.
- *
- * <p>This only plays after all active vibrators steps have finished, and adds a {@link
- * StartVibrateStep} to the queue if the sequential effect isn't finished yet.
- */
- private final class FinishVibrateStep extends Step {
- public final StartVibrateStep startedStep;
-
- FinishVibrateStep(StartVibrateStep startedStep) {
- super(Long.MAX_VALUE); // No predefined startTime, just wait for all steps in the queue.
- this.startedStep = startedStep;
- }
-
- @Override
- public boolean isCleanUp() {
- // This step only notes that all the vibrators has been turned off.
- return true;
- }
-
- @Override
- public List<Step> play() {
- Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "FinishVibrateStep");
- try {
- if (DEBUG) {
- Slog.d(TAG, "FinishVibrateStep for effect #" + startedStep.currentIndex);
- }
- noteVibratorOff();
- Step nextStep = startedStep.nextStep();
- return nextStep == null ? EMPTY_STEP_LIST : Arrays.asList(nextStep);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
- }
- }
-
- @Override
- public List<Step> cancel() {
- cancelImmediately();
- return EMPTY_STEP_LIST;
- }
-
- @Override
- public void cancelImmediately() {
- noteVibratorOff();
- }
- }
-
- /**
- * Represent a step on a single vibrator that plays one or more segments from a
- * {@link VibrationEffect.Composed} effect.
- */
- private abstract class SingleVibratorStep extends Step {
- public final VibratorController controller;
- public final VibrationEffect.Composed effect;
- public final int segmentIndex;
- public final long vibratorOffTimeout;
-
- long mVibratorOnResult;
- boolean mVibratorCompleteCallbackReceived;
-
- /**
- * @param startTime The time to schedule this step in the {@link StepQueue}.
- * @param controller The vibrator that is playing the effect.
- * @param effect The effect being played in this step.
- * @param index The index of the next segment to be played by this step
- * @param vibratorOffTimeout The time the vibrator is expected to complete any previous
- * vibration and turn off. This is used to allow this step to be
- * triggered when the completion callback is received, and can
- * be used play effects back-to-back.
- */
- SingleVibratorStep(long startTime, VibratorController controller,
- VibrationEffect.Composed effect, int index, long vibratorOffTimeout) {
- super(startTime);
- this.controller = controller;
- this.effect = effect;
- this.segmentIndex = index;
- this.vibratorOffTimeout = vibratorOffTimeout;
- }
-
- @Override
- public long getVibratorOnDuration() {
- return mVibratorOnResult;
- }
-
- @Override
- public boolean acceptVibratorCompleteCallback(int vibratorId) {
- boolean isSameVibrator = controller.getVibratorInfo().getId() == vibratorId;
- mVibratorCompleteCallbackReceived |= isSameVibrator;
- // Only activate this step if a timeout was set to wait for the vibration to complete,
- // otherwise we are waiting for the correct time to play the next step.
- return isSameVibrator && (vibratorOffTimeout > SystemClock.uptimeMillis());
- }
-
- @Override
- public List<Step> cancel() {
- return Arrays.asList(new EffectCompleteStep(SystemClock.uptimeMillis(),
- /* cancelled= */ true, controller, vibratorOffTimeout));
- }
-
- @Override
- public void cancelImmediately() {
- if (vibratorOffTimeout > SystemClock.uptimeMillis()) {
- // Vibrator might be running from previous steps, so turn it off while canceling.
- stopVibrating();
- }
- }
-
- void stopVibrating() {
- if (DEBUG) {
- Slog.d(TAG, "Turning off vibrator " + controller.getVibratorInfo().getId());
- }
- controller.off();
- }
-
- void changeAmplitude(float amplitude) {
- if (DEBUG) {
- Slog.d(TAG, "Amplitude changed on vibrator " + controller.getVibratorInfo().getId()
- + " to " + amplitude);
- }
- controller.setAmplitude(amplitude);
- }
-
- /** Return the {@link #nextVibrateStep} with same timings, only jumping the segments. */
- public List<Step> skipToNextSteps(int segmentsSkipped) {
- return nextSteps(startTime, vibratorOffTimeout, segmentsSkipped);
- }
-
- /**
- * Return the {@link #nextVibrateStep} with same start and off timings calculated from
- * {@link #getVibratorOnDuration()}, jumping all played segments.
- *
- * <p>This method has same behavior as {@link #skipToNextSteps(int)} when the vibrator
- * result is non-positive, meaning the vibrator has either ignored or failed to turn on.
- */
- public List<Step> nextSteps(int segmentsPlayed) {
- if (mVibratorOnResult <= 0) {
- // Vibration was not started, so just skip the played segments and keep timings.
- return skipToNextSteps(segmentsPlayed);
- }
- long nextStartTime = SystemClock.uptimeMillis() + mVibratorOnResult;
- long nextVibratorOffTimeout = nextStartTime + CALLBACKS_EXTRA_TIMEOUT;
- return nextSteps(nextStartTime, nextVibratorOffTimeout, segmentsPlayed);
- }
-
- /**
- * Return the {@link #nextVibrateStep} with given start and off timings, which might be
- * calculated independently, jumping all played segments.
- *
- * <p>This should be used when the vibrator on/off state is not responsible for the steps
- * execution timings, e.g. while playing the vibrator amplitudes.
- */
- public List<Step> nextSteps(long nextStartTime, long vibratorOffTimeout,
- int segmentsPlayed) {
- Step nextStep = nextVibrateStep(nextStartTime, controller, effect,
- segmentIndex + segmentsPlayed, vibratorOffTimeout);
- return nextStep == null ? EMPTY_STEP_LIST : Arrays.asList(nextStep);
- }
- }
-
- /**
- * Represent a step turn the vibrator on with a single prebaked effect.
- *
- * <p>This step automatically falls back by replacing the prebaked segment with
- * {@link VibrationSettings#getFallbackEffect(int)}, if available.
- */
- private final class PerformStep extends SingleVibratorStep {
-
- PerformStep(long startTime, VibratorController controller,
- VibrationEffect.Composed effect, int index, long vibratorOffTimeout) {
- // This step should wait for the last vibration to finish (with the timeout) and for the
- // intended step start time (to respect the effect delays).
- super(Math.max(startTime, vibratorOffTimeout), controller, effect, index,
- vibratorOffTimeout);
- }
-
- @Override
- public List<Step> play() {
- Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "PerformStep");
- try {
- VibrationEffectSegment segment = effect.getSegments().get(segmentIndex);
- if (!(segment instanceof PrebakedSegment)) {
- Slog.w(TAG, "Ignoring wrong segment for a PerformStep: " + segment);
- return skipToNextSteps(/* segmentsSkipped= */ 1);
- }
-
- PrebakedSegment prebaked = (PrebakedSegment) segment;
- if (DEBUG) {
- Slog.d(TAG, "Perform " + VibrationEffect.effectIdToString(
- prebaked.getEffectId()) + " on vibrator "
- + controller.getVibratorInfo().getId());
- }
-
- VibrationEffect fallback = mVibration.getFallback(prebaked.getEffectId());
- mVibratorOnResult = controller.on(prebaked, mVibration.id);
-
- if (mVibratorOnResult == 0 && prebaked.shouldFallback()
- && (fallback instanceof VibrationEffect.Composed)) {
- if (DEBUG) {
- Slog.d(TAG, "Playing fallback for effect "
- + VibrationEffect.effectIdToString(prebaked.getEffectId()));
- }
- SingleVibratorStep fallbackStep = nextVibrateStep(startTime, controller,
- replaceCurrentSegment((VibrationEffect.Composed) fallback),
- segmentIndex, vibratorOffTimeout);
- List<Step> fallbackResult = fallbackStep.play();
- // Update the result with the fallback result so this step is seamlessly
- // replaced by the fallback to any outer application of this.
- mVibratorOnResult = fallbackStep.getVibratorOnDuration();
- return fallbackResult;
- }
-
- return nextSteps(/* segmentsPlayed= */ 1);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
- }
- }
-
- /**
- * Replace segment at {@link #segmentIndex} in {@link #effect} with given fallback segments.
- *
- * @return a copy of {@link #effect} with replaced segment.
- */
- private VibrationEffect.Composed replaceCurrentSegment(VibrationEffect.Composed fallback) {
- List<VibrationEffectSegment> newSegments = new ArrayList<>(effect.getSegments());
- int newRepeatIndex = effect.getRepeatIndex();
- newSegments.remove(segmentIndex);
- newSegments.addAll(segmentIndex, fallback.getSegments());
- if (segmentIndex < effect.getRepeatIndex()) {
- newRepeatIndex += fallback.getSegments().size() - 1;
- }
- return new VibrationEffect.Composed(newSegments, newRepeatIndex);
- }
- }
-
- /**
- * Represent a step turn the vibrator on using a composition of primitives.
- *
- * <p>This step will use the maximum supported number of consecutive segments of type
- * {@link PrimitiveSegment} starting at the current index.
- */
- private final class ComposePrimitivesStep extends SingleVibratorStep {
-
- ComposePrimitivesStep(long startTime, VibratorController controller,
- VibrationEffect.Composed effect, int index, long vibratorOffTimeout) {
- // This step should wait for the last vibration to finish (with the timeout) and for the
- // intended step start time (to respect the effect delays).
- super(Math.max(startTime, vibratorOffTimeout), controller, effect, index,
- vibratorOffTimeout);
- }
-
- @Override
- public List<Step> play() {
- Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "ComposePrimitivesStep");
- try {
- // Load the next PrimitiveSegments to create a single compose call to the vibrator,
- // limited to the vibrator composition maximum size.
- int limit = controller.getVibratorInfo().getCompositionSizeMax();
- int segmentCount = limit > 0
- ? Math.min(effect.getSegments().size(), segmentIndex + limit)
- : effect.getSegments().size();
- List<PrimitiveSegment> primitives = new ArrayList<>();
- for (int i = segmentIndex; i < segmentCount; i++) {
- VibrationEffectSegment segment = effect.getSegments().get(i);
- if (segment instanceof PrimitiveSegment) {
- primitives.add((PrimitiveSegment) segment);
- } else {
- break;
- }
- }
-
- if (primitives.isEmpty()) {
- Slog.w(TAG, "Ignoring wrong segment for a ComposePrimitivesStep: "
- + effect.getSegments().get(segmentIndex));
- return skipToNextSteps(/* segmentsSkipped= */ 1);
- }
-
- if (DEBUG) {
- Slog.d(TAG, "Compose " + primitives + " primitives on vibrator "
- + controller.getVibratorInfo().getId());
- }
- mVibratorOnResult = controller.on(
- primitives.toArray(new PrimitiveSegment[primitives.size()]),
- mVibration.id);
-
- return nextSteps(/* segmentsPlayed= */ primitives.size());
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
- }
- }
- }
-
- /**
- * Represent a step turn the vibrator on using a composition of PWLE segments.
- *
- * <p>This step will use the maximum supported number of consecutive segments of type
- * {@link StepSegment} or {@link RampSegment} starting at the current index.
- */
- private final class ComposePwleStep extends SingleVibratorStep {
-
- ComposePwleStep(long startTime, VibratorController controller,
- VibrationEffect.Composed effect, int index, long vibratorOffTimeout) {
- // This step should wait for the last vibration to finish (with the timeout) and for the
- // intended step start time (to respect the effect delays).
- super(Math.max(startTime, vibratorOffTimeout), controller, effect, index,
- vibratorOffTimeout);
- }
-
- @Override
- public List<Step> play() {
- Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "ComposePwleStep");
- try {
- // Load the next RampSegments to create a single composePwle call to the vibrator,
- // limited to the vibrator PWLE maximum size.
- int limit = controller.getVibratorInfo().getPwleSizeMax();
- int segmentCount = limit > 0
- ? Math.min(effect.getSegments().size(), segmentIndex + limit)
- : effect.getSegments().size();
- List<RampSegment> pwles = new ArrayList<>();
- for (int i = segmentIndex; i < segmentCount; i++) {
- VibrationEffectSegment segment = effect.getSegments().get(i);
- if (segment instanceof RampSegment) {
- pwles.add((RampSegment) segment);
- } else {
- break;
- }
- }
-
- if (pwles.isEmpty()) {
- Slog.w(TAG, "Ignoring wrong segment for a ComposePwleStep: "
- + effect.getSegments().get(segmentIndex));
- return skipToNextSteps(/* segmentsSkipped= */ 1);
- }
-
- if (DEBUG) {
- Slog.d(TAG, "Compose " + pwles + " PWLEs on vibrator "
- + controller.getVibratorInfo().getId());
- }
- mVibratorOnResult = controller.on(pwles.toArray(new RampSegment[pwles.size()]),
- mVibration.id);
-
- return nextSteps(/* segmentsPlayed= */ pwles.size());
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
- }
- }
- }
-
- /**
- * Represents a step to complete a {@link VibrationEffect}.
- *
- * <p>This runs right at the time the vibration is considered to end and will update the pending
- * vibrators count. This can turn off the vibrator or slowly ramp it down to zero amplitude.
- */
- private final class EffectCompleteStep extends SingleVibratorStep {
- private final boolean mCancelled;
-
- EffectCompleteStep(long startTime, boolean cancelled, VibratorController controller,
- long vibratorOffTimeout) {
- super(startTime, controller, /* effect= */ null, /* index= */ -1, vibratorOffTimeout);
- mCancelled = cancelled;
- }
-
- @Override
- public boolean isCleanUp() {
- // If the vibration was cancelled then this is just a clean up to ramp off the vibrator.
- // Otherwise this step is part of the vibration.
- return mCancelled;
- }
-
- @Override
- public List<Step> cancel() {
- if (mCancelled) {
- // Double cancelling will just turn off the vibrator right away.
- return Arrays.asList(new OffStep(SystemClock.uptimeMillis(), controller));
- }
- return super.cancel();
- }
-
- @Override
- public List<Step> play() {
- Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "EffectCompleteStep");
- try {
- if (DEBUG) {
- Slog.d(TAG, "Running " + (mCancelled ? "cancel" : "complete") + " vibration"
- + " step on vibrator " + controller.getVibratorInfo().getId());
- }
- if (mVibratorCompleteCallbackReceived) {
- // Vibration completion callback was received by this step, just turn if off
- // and skip any clean-up.
- stopVibrating();
- return EMPTY_STEP_LIST;
- }
-
- float currentAmplitude = controller.getCurrentAmplitude();
- long remainingOnDuration =
- vibratorOffTimeout - CALLBACKS_EXTRA_TIMEOUT - SystemClock.uptimeMillis();
- long rampDownDuration =
- Math.min(remainingOnDuration, mVibrationSettings.getRampDownDuration());
- long stepDownDuration = mVibrationSettings.getRampStepDuration();
- if (currentAmplitude < RAMP_OFF_AMPLITUDE_MIN
- || rampDownDuration <= stepDownDuration) {
- // No need to ramp down the amplitude, just wait to turn it off.
- if (mCancelled) {
- // Vibration is completing because it was cancelled, turn off right away.
- stopVibrating();
- return EMPTY_STEP_LIST;
- } else {
- return Arrays.asList(new OffStep(vibratorOffTimeout, controller));
- }
- }
-
- if (DEBUG) {
- Slog.d(TAG, "Ramping down vibrator " + controller.getVibratorInfo().getId()
- + " from amplitude " + currentAmplitude
- + " for " + rampDownDuration + "ms");
- }
- float amplitudeDelta = currentAmplitude / (rampDownDuration / stepDownDuration);
- float amplitudeTarget = currentAmplitude - amplitudeDelta;
- long newVibratorOffTimeout = mCancelled ? rampDownDuration : vibratorOffTimeout;
- return Arrays.asList(new RampOffStep(startTime, amplitudeTarget, amplitudeDelta,
- controller, newVibratorOffTimeout));
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
- }
- }
- }
-
- /** Represents a step to ramp down the vibrator amplitude before turning it off. */
- private final class RampOffStep extends SingleVibratorStep {
- private final float mAmplitudeTarget;
- private final float mAmplitudeDelta;
-
- RampOffStep(long startTime, float amplitudeTarget, float amplitudeDelta,
- VibratorController controller, long vibratorOffTimeout) {
- super(startTime, controller, /* effect= */ null, /* index= */ -1, vibratorOffTimeout);
- mAmplitudeTarget = amplitudeTarget;
- mAmplitudeDelta = amplitudeDelta;
- }
-
- @Override
- public boolean isCleanUp() {
- return true;
- }
-
- @Override
- public List<Step> cancel() {
- return Arrays.asList(new OffStep(SystemClock.uptimeMillis(), controller));
- }
-
- @Override
- public List<Step> play() {
- Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "RampOffStep");
- try {
- if (DEBUG) {
- long latency = SystemClock.uptimeMillis() - startTime;
- Slog.d(TAG, "Ramp down the vibrator amplitude, step with "
- + latency + "ms latency.");
- }
- if (mVibratorCompleteCallbackReceived) {
- // Vibration completion callback was received by this step, just turn if off
- // and skip the rest of the steps to ramp down the vibrator amplitude.
- stopVibrating();
- return EMPTY_STEP_LIST;
- }
-
- changeAmplitude(mAmplitudeTarget);
-
- float newAmplitudeTarget = mAmplitudeTarget - mAmplitudeDelta;
- if (newAmplitudeTarget < RAMP_OFF_AMPLITUDE_MIN) {
- // Vibrator amplitude cannot go further down, just turn it off.
- return Arrays.asList(new OffStep(vibratorOffTimeout, controller));
- }
- return Arrays.asList(new RampOffStep(
- startTime + mVibrationSettings.getRampStepDuration(), newAmplitudeTarget,
- mAmplitudeDelta, controller, vibratorOffTimeout));
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
- }
- }
- }
-
- /**
- * Represents a step to turn the vibrator off.
- *
- * <p>This runs after a timeout on the expected time the vibrator should have finished playing,
- * and can be brought forward by vibrator complete callbacks.
- */
- private final class OffStep extends SingleVibratorStep {
-
- OffStep(long startTime, VibratorController controller) {
- super(startTime, controller, /* effect= */ null, /* index= */ -1, startTime);
- }
-
- @Override
- public boolean isCleanUp() {
- return true;
- }
-
- @Override
- public List<Step> cancel() {
- return Arrays.asList(new OffStep(SystemClock.uptimeMillis(), controller));
- }
-
- @Override
- public void cancelImmediately() {
- stopVibrating();
- }
-
- @Override
- public List<Step> play() {
- Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "OffStep");
- try {
- stopVibrating();
- return EMPTY_STEP_LIST;
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
- }
- }
- }
-
- /**
- * Represents a step to turn the vibrator on and change its amplitude.
- *
- * <p>This step ignores vibration completion callbacks and control the vibrator on/off state
- * and amplitude to simulate waveforms represented by a sequence of {@link StepSegment}.
- */
- private final class AmplitudeStep extends SingleVibratorStep {
- private long mNextOffTime;
-
- AmplitudeStep(long startTime, VibratorController controller,
- VibrationEffect.Composed effect, int index, long vibratorOffTimeout) {
- // This step has a fixed startTime coming from the timings of the waveform it's playing.
- super(startTime, controller, effect, index, vibratorOffTimeout);
- mNextOffTime = vibratorOffTimeout;
- }
-
- @Override
- public boolean acceptVibratorCompleteCallback(int vibratorId) {
- if (controller.getVibratorInfo().getId() == vibratorId) {
- mVibratorCompleteCallbackReceived = true;
- mNextOffTime = SystemClock.uptimeMillis();
- }
- // Timings are tightly controlled here, so only trigger this step if the vibrator was
- // supposed to be ON but has completed prematurely, to turn it back on as soon as
- // possible.
- return mNextOffTime < startTime && controller.getCurrentAmplitude() > 0;
- }
-
- @Override
- public List<Step> play() {
- Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "AmplitudeStep");
- try {
- long now = SystemClock.uptimeMillis();
- long latency = now - startTime;
- if (DEBUG) {
- Slog.d(TAG, "Running amplitude step with " + latency + "ms latency.");
- }
-
- if (mVibratorCompleteCallbackReceived && latency < 0) {
- // This step was run early because the vibrator turned off prematurely.
- // Turn it back on and return this same step to run at the exact right time.
- mNextOffTime = turnVibratorBackOn(/* remainingDuration= */ -latency);
- return Arrays.asList(new AmplitudeStep(startTime, controller, effect,
- segmentIndex, mNextOffTime));
- }
-
- VibrationEffectSegment segment = effect.getSegments().get(segmentIndex);
- if (!(segment instanceof StepSegment)) {
- Slog.w(TAG, "Ignoring wrong segment for a AmplitudeStep: " + segment);
- return skipToNextSteps(/* segmentsSkipped= */ 1);
- }
-
- StepSegment stepSegment = (StepSegment) segment;
- if (stepSegment.getDuration() == 0) {
- // Skip waveform entries with zero timing.
- return skipToNextSteps(/* segmentsSkipped= */ 1);
- }
-
- float amplitude = stepSegment.getAmplitude();
- if (amplitude == 0) {
- if (vibratorOffTimeout > now) {
- // Amplitude cannot be set to zero, so stop the vibrator.
- stopVibrating();
- mNextOffTime = now;
- }
- } else {
- if (startTime >= mNextOffTime) {
- // Vibrator is OFF. Turn vibrator back on for the duration of another
- // cycle before setting the amplitude.
- long onDuration = getVibratorOnDuration(effect, segmentIndex);
- if (onDuration > 0) {
- mVibratorOnResult = startVibrating(onDuration);
- mNextOffTime = now + onDuration + CALLBACKS_EXTRA_TIMEOUT;
- }
- }
- changeAmplitude(amplitude);
- }
-
- // Use original startTime to avoid propagating latencies to the waveform.
- long nextStartTime = startTime + segment.getDuration();
- return nextSteps(nextStartTime, mNextOffTime, /* segmentsPlayed= */ 1);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
- }
- }
-
- private long turnVibratorBackOn(long remainingDuration) {
- long onDuration = getVibratorOnDuration(effect, segmentIndex);
- if (onDuration <= 0) {
- // Vibrator is supposed to go back off when this step starts, so just leave it off.
- return vibratorOffTimeout;
- }
- onDuration += remainingDuration;
- float expectedAmplitude = controller.getCurrentAmplitude();
- mVibratorOnResult = startVibrating(onDuration);
- if (mVibratorOnResult > 0) {
- // Set the amplitude back to the value it was supposed to be playing at.
- changeAmplitude(expectedAmplitude);
- }
- return SystemClock.uptimeMillis() + onDuration + CALLBACKS_EXTRA_TIMEOUT;
- }
-
- private long startVibrating(long duration) {
- if (DEBUG) {
- Slog.d(TAG, "Turning on vibrator " + controller.getVibratorInfo().getId() + " for "
- + duration + "ms");
- }
- return controller.on(duration, mVibration.id);
- }
-
- /**
- * Get the duration the vibrator will be on for a waveform, starting at {@code startIndex}
- * until the next time it's vibrating amplitude is zero or a different type of segment is
- * found.
- */
- private long getVibratorOnDuration(VibrationEffect.Composed effect, int startIndex) {
- List<VibrationEffectSegment> segments = effect.getSegments();
- int segmentCount = segments.size();
- int repeatIndex = effect.getRepeatIndex();
- int i = startIndex;
- long timing = 0;
- while (i < segmentCount) {
- VibrationEffectSegment segment = segments.get(i);
- if (!(segment instanceof StepSegment)
- || ((StepSegment) segment).getAmplitude() == 0) {
- break;
- }
- timing += segment.getDuration();
- i++;
- if (i == segmentCount && repeatIndex >= 0) {
- i = repeatIndex;
- // prevent infinite loop
- repeatIndex = -1;
- }
- if (i == startIndex) {
- // The repeating waveform keeps the vibrator ON all the time. Use a minimum
- // of 1s duration to prevent short patterns from turning the vibrator ON too
- // frequently.
- return Math.max(timing, 1000);
- }
- }
- if (i == segmentCount && effect.getRepeatIndex() < 0) {
- // Vibration ending at non-zero amplitude, add extra timings to ramp down after
- // vibration is complete.
- timing += mVibrationSettings.getRampDownDuration();
- }
- return timing;
- }
- }
-
- /**
- * Map a {@link CombinedVibration} to the vibrators available on the device.
- *
- * <p>This contains the logic to find the capabilities required from {@link IVibratorManager} to
- * play all of the effects in sync.
- */
- private final class DeviceEffectMap {
- private final SparseArray<VibrationEffect.Composed> mVibratorEffects;
- private final int[] mVibratorIds;
- private final long mRequiredSyncCapabilities;
-
- DeviceEffectMap(CombinedVibration.Mono mono) {
- mVibratorEffects = new SparseArray<>(mVibrators.size());
- mVibratorIds = new int[mVibrators.size()];
- for (int i = 0; i < mVibrators.size(); i++) {
- int vibratorId = mVibrators.keyAt(i);
- VibratorInfo vibratorInfo = mVibrators.valueAt(i).getVibratorInfo();
- VibrationEffect effect = mDeviceEffectAdapter.apply(mono.getEffect(), vibratorInfo);
- if (effect instanceof VibrationEffect.Composed) {
- mVibratorEffects.put(vibratorId, (VibrationEffect.Composed) effect);
- mVibratorIds[i] = vibratorId;
- }
- }
- mRequiredSyncCapabilities = calculateRequiredSyncCapabilities(mVibratorEffects);
- }
-
- DeviceEffectMap(CombinedVibration.Stereo stereo) {
- SparseArray<VibrationEffect> stereoEffects = stereo.getEffects();
- mVibratorEffects = new SparseArray<>();
- for (int i = 0; i < stereoEffects.size(); i++) {
- int vibratorId = stereoEffects.keyAt(i);
- if (mVibrators.contains(vibratorId)) {
- VibratorInfo vibratorInfo = mVibrators.valueAt(i).getVibratorInfo();
- VibrationEffect effect = mDeviceEffectAdapter.apply(
- stereoEffects.valueAt(i), vibratorInfo);
- if (effect instanceof VibrationEffect.Composed) {
- mVibratorEffects.put(vibratorId, (VibrationEffect.Composed) effect);
- }
- }
- }
- mVibratorIds = new int[mVibratorEffects.size()];
- for (int i = 0; i < mVibratorEffects.size(); i++) {
- mVibratorIds[i] = mVibratorEffects.keyAt(i);
- }
- mRequiredSyncCapabilities = calculateRequiredSyncCapabilities(mVibratorEffects);
- }
-
- /**
- * Return the number of vibrators mapped to play the {@link CombinedVibration} on this
- * device.
- */
- public int size() {
- return mVibratorIds.length;
- }
-
- /**
- * Return all capabilities required to play the {@link CombinedVibration} in
- * between calls to {@link IVibratorManager#prepareSynced} and
- * {@link IVibratorManager#triggerSynced}.
- */
- public long getRequiredSyncCapabilities() {
- return mRequiredSyncCapabilities;
- }
-
- /** Return all vibrator ids mapped to play the {@link CombinedVibration}. */
- public int[] getVibratorIds() {
- return mVibratorIds;
- }
-
- /** Return the id of the vibrator at given index. */
- public int vibratorIdAt(int index) {
- return mVibratorEffects.keyAt(index);
- }
-
- /** Return the {@link VibrationEffect} at given index. */
- public VibrationEffect.Composed effectAt(int index) {
- return mVibratorEffects.valueAt(index);
- }
-
- /**
- * Return all capabilities required from the {@link IVibratorManager} to prepare and
- * trigger all given effects in sync.
- *
- * @return {@link IVibratorManager#CAP_SYNC} together with all required
- * IVibratorManager.CAP_PREPARE_* and IVibratorManager.CAP_MIXED_TRIGGER_* capabilities.
- */
- private long calculateRequiredSyncCapabilities(
- SparseArray<VibrationEffect.Composed> effects) {
- long prepareCap = 0;
- for (int i = 0; i < effects.size(); i++) {
- VibrationEffectSegment firstSegment = effects.valueAt(i).getSegments().get(0);
- if (firstSegment instanceof StepSegment) {
- prepareCap |= IVibratorManager.CAP_PREPARE_ON;
- } else if (firstSegment instanceof PrebakedSegment) {
- prepareCap |= IVibratorManager.CAP_PREPARE_PERFORM;
- } else if (firstSegment instanceof PrimitiveSegment) {
- prepareCap |= IVibratorManager.CAP_PREPARE_COMPOSE;
- }
- }
- int triggerCap = 0;
- if (requireMixedTriggerCapability(prepareCap, IVibratorManager.CAP_PREPARE_ON)) {
- triggerCap |= IVibratorManager.CAP_MIXED_TRIGGER_ON;
- }
- if (requireMixedTriggerCapability(prepareCap, IVibratorManager.CAP_PREPARE_PERFORM)) {
- triggerCap |= IVibratorManager.CAP_MIXED_TRIGGER_PERFORM;
- }
- if (requireMixedTriggerCapability(prepareCap, IVibratorManager.CAP_PREPARE_COMPOSE)) {
- triggerCap |= IVibratorManager.CAP_MIXED_TRIGGER_COMPOSE;
- }
- return IVibratorManager.CAP_SYNC | prepareCap | triggerCap;
- }
-
- /**
- * Return true if {@code prepareCapabilities} contains this {@code capability} mixed with
- * different ones, requiring a mixed trigger capability from the vibrator manager for
- * syncing all effects.
- */
- private boolean requireMixedTriggerCapability(long prepareCapabilities, long capability) {
- return (prepareCapabilities & capability) != 0
- && (prepareCapabilities & ~capability) != 0;
- }
- }
}
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index 63f3af3..01f9d0b9 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -42,6 +42,7 @@
import android.os.Looper;
import android.os.PowerManager;
import android.os.Process;
+import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
import android.os.ShellCallback;
@@ -60,6 +61,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
import com.android.internal.util.DumpUtils;
+import com.android.internal.util.FrameworkStatsLog;
import com.android.server.LocalServices;
import com.android.server.SystemService;
@@ -88,6 +90,9 @@
VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY
| VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF;
+ /** Fixed large duration used to note repeating vibrations to {@link IBatteryStats}. */
+ private static final long BATTERY_STATS_REPEATING_VIBRATION_DURATION = 5_000;
+
/** Lifecycle responsible for initializing this class at the right system server phases. */
public static class Lifecycle extends SystemService {
private VibratorManagerService mService;
@@ -201,8 +206,7 @@
mSystemUiPackage = LocalServices.getService(PackageManagerInternal.class)
.getSystemUiServiceComponent().getPackageName();
- mBatteryStatsService = IBatteryStats.Stub.asInterface(ServiceManager.getService(
- BatteryStats.SERVICE_NAME));
+ mBatteryStatsService = injector.getBatteryStatsService();
mAppOps = mContext.getSystemService(AppOpsManager.class);
@@ -634,7 +638,7 @@
}
VibrationThread vibThread = new VibrationThread(vib, mVibrationSettings,
- mDeviceVibrationEffectAdapter, mVibrators, mWakeLock, mBatteryStatsService,
+ mDeviceVibrationEffectAdapter, mVibrators, mWakeLock,
mVibrationThreadCallbacks);
if (mCurrentVibration == null) {
@@ -1105,6 +1109,11 @@
return new Handler(looper);
}
+ IBatteryStats getBatteryStatsService() {
+ return IBatteryStats.Stub.asInterface(ServiceManager.getService(
+ BatteryStats.SERVICE_NAME));
+ }
+
VibratorController createVibratorController(int vibratorId,
VibratorController.OnVibrationCompleteListener listener) {
return new VibratorController(vibratorId, listener);
@@ -1141,6 +1150,36 @@
}
@Override
+ public void noteVibratorOn(int uid, long duration) {
+ try {
+ if (duration <= 0) {
+ return;
+ }
+ if (duration == Long.MAX_VALUE) {
+ // Repeating duration has started. Report a fixed duration here, noteVibratorOff
+ // should be called when this is cancelled.
+ duration = BATTERY_STATS_REPEATING_VIBRATION_DURATION;
+ }
+ mBatteryStatsService.noteVibratorOn(uid, duration);
+ FrameworkStatsLog.write_non_chained(FrameworkStatsLog.VIBRATOR_STATE_CHANGED,
+ uid, null, FrameworkStatsLog.VIBRATOR_STATE_CHANGED__STATE__ON,
+ duration);
+ } catch (RemoteException e) {
+ }
+ }
+
+ @Override
+ public void noteVibratorOff(int uid) {
+ try {
+ mBatteryStatsService.noteVibratorOff(uid);
+ FrameworkStatsLog.write_non_chained(FrameworkStatsLog.VIBRATOR_STATE_CHANGED,
+ uid, null, FrameworkStatsLog.VIBRATOR_STATE_CHANGED__STATE__OFF,
+ /* duration= */ 0);
+ } catch (RemoteException e) {
+ }
+ }
+
+ @Override
public void onVibrationCompleted(long vibrationId, Vibration.Status status) {
if (DEBUG) {
Slog.d(TAG, "Vibration " + vibrationId + " finished with status " + status);
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 87c8a79..2da2987 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -62,8 +62,8 @@
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
-import android.graphics.BitmapRegionDecoder;
import android.graphics.Color;
+import android.graphics.ImageDecoder;
import android.graphics.Rect;
import android.graphics.RectF;
import android.hardware.display.DisplayManager;
@@ -199,6 +199,8 @@
static final String WALLPAPER_LOCK_ORIG = "wallpaper_lock_orig";
static final String WALLPAPER_LOCK_CROP = "wallpaper_lock";
static final String WALLPAPER_INFO = "wallpaper_info.xml";
+ private static final String RECORD_FILE = "decode_record";
+ private static final String RECORD_LOCK_FILE = "decode_lock_record";
// All the various per-user state files we need to be aware of
private static final String[] sPerUserFiles = new String[] {
@@ -689,8 +691,7 @@
}
if (DEBUG) {
- // This is just a quick estimation, may be smaller than it is.
- long estimateSize = options.outWidth * options.outHeight * 4;
+ long estimateSize = (long) options.outWidth * options.outHeight * 4;
Slog.v(TAG, "Null crop of new wallpaper, estimate size="
+ estimateSize + ", success=" + success);
}
@@ -699,9 +700,6 @@
FileOutputStream f = null;
BufferedOutputStream bos = null;
try {
- BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(
- wallpaper.wallpaperFile.getAbsolutePath(), false);
-
// This actually downsamples only by powers of two, but that's okay; we do
// a proper scaling blit later. This is to minimize transient RAM use.
// We calculate the largest power-of-two under the actual ratio rather than
@@ -755,8 +753,24 @@
Slog.v(TAG, " maxTextureSize=" + GLHelper.getMaxTextureSize());
}
- Bitmap cropped = decoder.decodeRegion(cropHint, options);
- decoder.recycle();
+ //Create a record file and will delete if ImageDecoder work well.
+ final String recordName =
+ (wallpaper.wallpaperFile.getName().equals(WALLPAPER)
+ ? RECORD_FILE : RECORD_LOCK_FILE);
+ final File record = new File(getWallpaperDir(wallpaper.userId), recordName);
+ record.createNewFile();
+ Slog.v(TAG, "record path =" + record.getPath()
+ + ", record name =" + record.getName());
+
+ final ImageDecoder.Source srcData =
+ ImageDecoder.createSource(wallpaper.wallpaperFile);
+ final int sampleSize = scale;
+ Bitmap cropped = ImageDecoder.decodeBitmap(srcData, (decoder, info, src) -> {
+ decoder.setTargetSampleSize(sampleSize);
+ decoder.setCrop(estimateCrop);
+ });
+
+ record.delete();
if (cropped == null) {
Slog.e(TAG, "Could not decode new wallpaper");
@@ -1819,6 +1833,7 @@
new UserSwitchObserver() {
@Override
public void onUserSwitching(int newUserId, IRemoteCallback reply) {
+ errorCheck(newUserId);
switchUser(newUserId, reply);
}
}, TAG);
@@ -1856,6 +1871,14 @@
@Override
public void onBootPhase(int phase) {
+ // If someone set too large jpg file as wallpaper, system_server may be killed by lmk in
+ // generateCrop(), so we create a file in generateCrop() before ImageDecoder starts working
+ // and delete this file after ImageDecoder finishing. If the specific file exists, that
+ // means ImageDecoder can't handle the original wallpaper file, in order to avoid
+ // system_server restart again and again and rescue party will trigger factory reset,
+ // so we reset default wallpaper in case system_server is trapped into a restart loop.
+ errorCheck(UserHandle.USER_SYSTEM);
+
if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
systemReady();
} else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
@@ -1863,6 +1886,38 @@
}
}
+ private static final HashMap<Integer, String> sWallpaperType = new HashMap<Integer, String>() {
+ {
+ put(FLAG_SYSTEM, RECORD_FILE);
+ put(FLAG_LOCK, RECORD_LOCK_FILE);
+ }
+ };
+
+ private void errorCheck(int userID) {
+ sWallpaperType.forEach((type, filename) -> {
+ final File record = new File(getWallpaperDir(userID), filename);
+ if (record.exists()) {
+ Slog.w(TAG, "User:" + userID + ", wallpaper tyep = " + type
+ + ", wallpaper fail detect!! reset to default wallpaper");
+ clearWallpaperData(userID, type);
+ record.delete();
+ }
+ });
+ }
+
+ private void clearWallpaperData(int userID, int wallpaperType) {
+ final WallpaperData wallpaper = new WallpaperData(userID, getWallpaperDir(userID),
+ (wallpaperType == FLAG_LOCK) ? WALLPAPER_LOCK_ORIG : WALLPAPER,
+ (wallpaperType == FLAG_LOCK) ? WALLPAPER_LOCK_CROP : WALLPAPER_CROP);
+ if (wallpaper.sourceExists()) {
+ wallpaper.wallpaperFile.delete();
+ }
+ if (wallpaper.cropExists()) {
+ wallpaper.cropFile.delete();
+ }
+
+ }
+
@Override
public void onUnlockUser(final int userId) {
synchronized (mLock) {
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 0396a11..57f77d5 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -45,7 +45,6 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowTracing.WINSCOPE_EXT;
-import static com.android.server.wm.utils.RegionUtils.forEachRect;
import android.accessibilityservice.AccessibilityTrace;
import android.animation.ObjectAnimator;
@@ -101,6 +100,7 @@
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.LocalServices;
import com.android.server.policy.WindowManagerPolicy;
+import com.android.server.wm.AccessibilityWindowsPopulator.AccessibilityWindow;
import com.android.server.wm.WindowManagerInternal.AccessibilityControllerInternal;
import com.android.server.wm.WindowManagerInternal.MagnificationCallbacks;
import com.android.server.wm.WindowManagerInternal.WindowsForAccessibilityCallback;
@@ -133,19 +133,22 @@
private static final Rect EMPTY_RECT = new Rect();
private static final float[] sTempFloats = new float[9];
- private SparseArray<DisplayMagnifier> mDisplayMagnifiers = new SparseArray<>();
- private SparseArray<WindowsForAccessibilityObserver> mWindowsForAccessibilityObserver =
+ private final SparseArray<DisplayMagnifier> mDisplayMagnifiers = new SparseArray<>();
+ private final SparseArray<WindowsForAccessibilityObserver> mWindowsForAccessibilityObserver =
new SparseArray<>();
private SparseArray<IBinder> mFocusedWindow = new SparseArray<>();
private int mFocusedDisplay = -1;
private boolean mIsImeVisible = false;
// Set to true if initializing window population complete.
private boolean mAllObserversInitialized = true;
+ private final AccessibilityWindowsPopulator mAccessibilityWindowsPopulator;
AccessibilityController(WindowManagerService service) {
mService = service;
mAccessibilityTracing =
AccessibilityController.getAccessibilityControllerInternal(service);
+
+ mAccessibilityWindowsPopulator = new AccessibilityWindowsPopulator(mService, this);
}
boolean setMagnificationCallbacks(int displayId, MagnificationCallbacks callbacks) {
@@ -209,7 +212,9 @@
}
mWindowsForAccessibilityObserver.remove(displayId);
}
- observer = new WindowsForAccessibilityObserver(mService, displayId, callback);
+ mAccessibilityWindowsPopulator.setWindowsNotification(true);
+ observer = new WindowsForAccessibilityObserver(mService, displayId, callback,
+ mAccessibilityWindowsPopulator);
mWindowsForAccessibilityObserver.put(displayId, observer);
mAllObserversInitialized &= observer.mInitialized;
} else {
@@ -224,6 +229,10 @@
}
}
mWindowsForAccessibilityObserver.remove(displayId);
+
+ if (mWindowsForAccessibilityObserver.size() <= 0) {
+ mAccessibilityWindowsPopulator.setWindowsNotification(false);
+ }
}
}
@@ -254,6 +263,8 @@
FLAGS_MAGNIFICATION_CALLBACK | FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK,
"displayId=" + displayId + "; spec={" + spec + "}");
}
+ mAccessibilityWindowsPopulator.setMagnificationSpec(displayId, spec);
+
final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
if (displayMagnifier != null) {
displayMagnifier.setMagnificationSpec(spec);
@@ -309,11 +320,6 @@
if (displayMagnifier != null) {
displayMagnifier.onDisplaySizeChanged(displayContent);
}
- final WindowsForAccessibilityObserver windowsForA11yObserver =
- mWindowsForAccessibilityObserver.get(displayId);
- if (windowsForA11yObserver != null) {
- windowsForA11yObserver.scheduleComputeChangedWindows();
- }
}
void onAppWindowTransition(int displayId, int transition) {
@@ -341,11 +347,6 @@
if (displayMagnifier != null) {
displayMagnifier.onWindowTransition(windowState, transition);
}
- final WindowsForAccessibilityObserver windowsForA11yObserver =
- mWindowsForAccessibilityObserver.get(displayId);
- if (windowsForA11yObserver != null) {
- windowsForA11yObserver.scheduleComputeChangedWindows();
- }
}
void onWindowFocusChangedNot(int displayId) {
@@ -1403,20 +1404,18 @@
private static final boolean DEBUG = false;
- private final SparseArray<WindowState> mTempWindowStates = new SparseArray<>();
+ private final List<AccessibilityWindow> mTempA11yWindows = new ArrayList<>();
private final Set<IBinder> mTempBinderSet = new ArraySet<>();
- private final RectF mTempRectF = new RectF();
-
- private final Matrix mTempMatrix = new Matrix();
-
private final Point mTempPoint = new Point();
private final Region mTempRegion = new Region();
private final Region mTempRegion1 = new Region();
+ private final Region mTempRegion2 = new Region();
+
private final WindowManagerService mService;
private final Handler mHandler;
@@ -1431,10 +1430,11 @@
// Set to true if initializing window population complete.
private boolean mInitialized;
+ private final AccessibilityWindowsPopulator mA11yWindowsPopulator;
WindowsForAccessibilityObserver(WindowManagerService windowManagerService,
- int displayId,
- WindowsForAccessibilityCallback callback) {
+ int displayId, WindowsForAccessibilityCallback callback,
+ AccessibilityWindowsPopulator accessibilityWindowsPopulator) {
mService = windowManagerService;
mCallback = callback;
mDisplayId = displayId;
@@ -1443,6 +1443,7 @@
AccessibilityController.getAccessibilityControllerInternal(mService);
mRecurringAccessibilityEventsIntervalMillis = ViewConfiguration
.getSendRecurringAccessibilityEventsInterval();
+ mA11yWindowsPopulator = accessibilityWindowsPopulator;
computeChangedWindows(true);
}
@@ -1466,52 +1467,6 @@
}
}
- boolean shellRootIsAbove(WindowState windowState, ShellRoot shellRoot) {
- int wsLayer = mService.mPolicy.getWindowLayerLw(windowState);
- int shellLayer = mService.mPolicy.getWindowLayerFromTypeLw(shellRoot.getWindowType(),
- true);
- return shellLayer >= wsLayer;
- }
-
- int addShellRootsIfAbove(WindowState windowState, ArrayList<ShellRoot> shellRoots,
- int shellRootIndex, List<WindowInfo> windows, Set<IBinder> addedWindows,
- Region unaccountedSpace, boolean focusedWindowAdded) {
- while (shellRootIndex < shellRoots.size()
- && shellRootIsAbove(windowState, shellRoots.get(shellRootIndex))) {
- ShellRoot shellRoot = shellRoots.get(shellRootIndex);
- shellRootIndex++;
- final WindowInfo info = shellRoot.getWindowInfo();
- if (info == null) {
- continue;
- }
-
- info.layer = addedWindows.size();
- windows.add(info);
- addedWindows.add(info.token);
- unaccountedSpace.op(info.regionInScreen, unaccountedSpace,
- Region.Op.REVERSE_DIFFERENCE);
- if (unaccountedSpace.isEmpty() && focusedWindowAdded) {
- break;
- }
- }
- return shellRootIndex;
- }
-
- private ArrayList<ShellRoot> getSortedShellRoots(
- SparseArray<ShellRoot> originalShellRoots) {
- ArrayList<ShellRoot> sortedShellRoots = new ArrayList<>(originalShellRoots.size());
- for (int i = originalShellRoots.size() - 1; i >= 0; --i) {
- sortedShellRoots.add(originalShellRoots.valueAt(i));
- }
-
- sortedShellRoots.sort((left, right) ->
- mService.mPolicy.getWindowLayerFromTypeLw(right.getWindowType(), true)
- - mService.mPolicy.getWindowLayerFromTypeLw(left.getWindowType(),
- true));
-
- return sortedShellRoots;
- }
-
/**
* Check if windows have changed, and send them to the accessibility subsystem if they have.
*
@@ -1561,44 +1516,29 @@
Region unaccountedSpace = mTempRegion;
unaccountedSpace.set(0, 0, screenWidth, screenHeight);
- final SparseArray<WindowState> visibleWindows = mTempWindowStates;
- populateVisibleWindowsOnScreen(visibleWindows);
+ final List<AccessibilityWindow> visibleWindows = mTempA11yWindows;
+ mA11yWindowsPopulator.populateVisibleWindowsOnScreenLocked(
+ mDisplayId, visibleWindows);
Set<IBinder> addedWindows = mTempBinderSet;
addedWindows.clear();
boolean focusedWindowAdded = false;
final int visibleWindowCount = visibleWindows.size();
- ArrayList<TaskFragment> skipRemainingWindowsForTaskFragments = new ArrayList<>();
-
- ArrayList<ShellRoot> shellRoots = getSortedShellRoots(dc.mShellRoots);
// Iterate until we figure out what is touchable for the entire screen.
- int shellRootIndex = 0;
- for (int i = visibleWindowCount - 1; i >= 0; i--) {
- final WindowState windowState = visibleWindows.valueAt(i);
- int prevShellRootIndex = shellRootIndex;
- shellRootIndex = addShellRootsIfAbove(windowState, shellRoots, shellRootIndex,
- windows, addedWindows, unaccountedSpace, focusedWindowAdded);
-
- // If a Shell Root was added, it could have accounted for all the space already.
- if (shellRootIndex > prevShellRootIndex && unaccountedSpace.isEmpty()
- && focusedWindowAdded) {
- break;
- }
-
- final Region regionInScreen = new Region();
- computeWindowRegionInScreen(windowState, regionInScreen);
- if (windowMattersToAccessibility(windowState,
- regionInScreen, unaccountedSpace,
- skipRemainingWindowsForTaskFragments)) {
- addPopulatedWindowInfo(windowState, regionInScreen, windows, addedWindows);
- if (windowMattersToUnaccountedSpaceComputation(windowState)) {
- updateUnaccountedSpace(windowState, regionInScreen, unaccountedSpace,
- skipRemainingWindowsForTaskFragments);
+ for (int i = 0; i < visibleWindowCount; i++) {
+ final AccessibilityWindow a11yWindow = visibleWindows.get(i);
+ final Region regionInWindow = new Region();
+ a11yWindow.getTouchableRegionInWindow(regionInWindow);
+ if (windowMattersToAccessibility(a11yWindow, regionInWindow,
+ unaccountedSpace)) {
+ addPopulatedWindowInfo(a11yWindow, regionInWindow, windows, addedWindows);
+ if (windowMattersToUnaccountedSpaceComputation(a11yWindow)) {
+ updateUnaccountedSpace(a11yWindow, unaccountedSpace);
}
- focusedWindowAdded |= windowState.isFocused();
- } else if (isUntouchableNavigationBar(windowState, mTempRegion1)) {
+ focusedWindowAdded |= a11yWindow.isFocused();
+ } else if (a11yWindow.isUntouchableNavigationBar()) {
// If this widow is navigation bar without touchable region, accounting the
// region of navigation bar inset because all touch events from this region
// would be received by launcher, i.e. this region is a un-touchable one
@@ -1647,47 +1587,39 @@
// Some windows should be excluded from unaccounted space computation, though they still
// should be reported
- private boolean windowMattersToUnaccountedSpaceComputation(WindowState windowState) {
+ private boolean windowMattersToUnaccountedSpaceComputation(AccessibilityWindow a11yWindow) {
// Do not account space of trusted non-touchable windows, except the split-screen
// divider.
// If it's not trusted, touch events are not sent to the windows behind it.
- if (((windowState.mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0)
- && (windowState.mAttrs.type != TYPE_DOCK_DIVIDER)
- && windowState.isTrustedOverlay()) {
+ if (((a11yWindow.getFlags() & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0)
+ && (a11yWindow.getType() != TYPE_DOCK_DIVIDER)
+ && a11yWindow.isTrustedOverlay()) {
return false;
}
- if (windowState.mAttrs.type
- == WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY) {
+ if (a11yWindow.getType() == WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY) {
return false;
}
return true;
}
- private boolean windowMattersToAccessibility(WindowState windowState,
- Region regionInScreen, Region unaccountedSpace,
- ArrayList<TaskFragment> skipRemainingWindowsForTaskFragments) {
- final RecentsAnimationController controller = mService.getRecentsAnimationController();
- if (controller != null && controller.shouldIgnoreForAccessibility(windowState)) {
+ private boolean windowMattersToAccessibility(AccessibilityWindow a11yWindow,
+ Region regionInScreen, Region unaccountedSpace) {
+ if (a11yWindow.ignoreRecentsAnimationForAccessibility()) {
return false;
}
- if (windowState.isFocused()) {
+ if (a11yWindow.isFocused()) {
return true;
}
- // If the window is part of a task that we're finished with - ignore.
- final TaskFragment taskFragment = windowState.getTaskFragment();
- if (taskFragment != null
- && skipRemainingWindowsForTaskFragments.contains(taskFragment)) {
- return false;
- }
-
// Ignore non-touchable windows, except the split-screen divider, which is
// occasionally non-touchable but still useful for identifying split-screen
- // mode.
- if (((windowState.mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0)
- && (windowState.mAttrs.type != TYPE_DOCK_DIVIDER)) {
+ // mode and the PIP menu.
+ if (((a11yWindow.getFlags()
+ & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0)
+ && (a11yWindow.getType() != TYPE_DOCK_DIVIDER
+ && !a11yWindow.isPIPMenu())) {
return false;
}
@@ -1697,88 +1629,36 @@
}
// Add windows of certain types not covered by modal windows.
- if (isReportedWindowType(windowState.mAttrs.type)) {
+ if (isReportedWindowType(a11yWindow.getType())) {
return true;
}
return false;
}
- private void updateUnaccountedSpace(WindowState windowState, Region regionInScreen,
- Region unaccountedSpace,
- ArrayList<TaskFragment> skipRemainingWindowsForTaskFragments) {
- // Account for the space this window takes if the window
- // is not an accessibility overlay which does not change
- // the reported windows.
- unaccountedSpace.op(regionInScreen, unaccountedSpace,
- Region.Op.REVERSE_DIFFERENCE);
-
- // If a window is modal it prevents other windows from being touched
- if ((windowState.mAttrs.flags & (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL)) == 0) {
- if (!windowState.hasTapExcludeRegion()) {
- // Account for all space in the task, whether the windows in it are
- // touchable or not. The modal window blocks all touches from the task's
- // area.
- unaccountedSpace.op(windowState.getDisplayFrame(), unaccountedSpace,
- Region.Op.REVERSE_DIFFERENCE);
- } else {
- // If a window has tap exclude region, we need to account it.
- final Region displayRegion = new Region(windowState.getDisplayFrame());
- final Region tapExcludeRegion = new Region();
- windowState.getTapExcludeRegion(tapExcludeRegion);
- displayRegion.op(tapExcludeRegion, displayRegion,
- Region.Op.REVERSE_DIFFERENCE);
- unaccountedSpace.op(displayRegion, unaccountedSpace,
- Region.Op.REVERSE_DIFFERENCE);
- }
-
- final TaskFragment taskFragment = windowState.getTaskFragment();
- if (taskFragment != null) {
- // If the window is associated with a particular task, we can skip the
- // rest of the windows for that task.
- skipRemainingWindowsForTaskFragments.add(taskFragment);
- } else if (!windowState.hasTapExcludeRegion()) {
- // If the window is not associated with a particular task, then it is
- // globally modal. In this case we can skip all remaining windows when
- // it doesn't has tap exclude region.
- unaccountedSpace.setEmpty();
- }
- }
-
- // Account for the space of letterbox.
- if (windowState.areAppWindowBoundsLetterboxed()) {
- unaccountedSpace.op(getLetterboxBounds(windowState), unaccountedSpace,
+ private void updateUnaccountedSpace(AccessibilityWindow a11yWindow,
+ Region unaccountedSpace) {
+ if (a11yWindow.getType()
+ != WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY) {
+ // Account for the space this window takes if the window
+ // is not an accessibility overlay which does not change
+ // the reported windows.
+ final Region touchableRegion = mTempRegion2;
+ a11yWindow.getTouchableRegionInScreen(touchableRegion);
+ unaccountedSpace.op(touchableRegion, unaccountedSpace,
Region.Op.REVERSE_DIFFERENCE);
+ // Account for the space of letterbox.
+ final Region letterboxBounds = mTempRegion1;
+ if (a11yWindow.setLetterBoxBoundsIfNeeded(letterboxBounds)) {
+ unaccountedSpace.op(letterboxBounds,
+ unaccountedSpace, Region.Op.REVERSE_DIFFERENCE);
+ }
}
}
- private void computeWindowRegionInScreen(WindowState windowState, Region outRegion) {
- // Get the touchable frame.
- Region touchableRegion = mTempRegion1;
- windowState.getTouchableRegion(touchableRegion);
-
- // Map the frame to get what appears on the screen.
- Matrix matrix = mTempMatrix;
- populateTransformationMatrix(windowState, matrix);
-
- forEachRect(touchableRegion, rect -> {
- // Move to origin as all transforms are captured by the matrix.
- RectF windowFrame = mTempRectF;
- windowFrame.set(rect);
- windowFrame.offset(-windowState.getFrame().left, -windowState.getFrame().top);
-
- matrix.mapRect(windowFrame);
-
- // Union all rects.
- outRegion.union(new Rect((int) windowFrame.left, (int) windowFrame.top,
- (int) windowFrame.right, (int) windowFrame.bottom));
- });
- }
-
- private static void addPopulatedWindowInfo(WindowState windowState, Region regionInScreen,
- List<WindowInfo> out, Set<IBinder> tokenOut) {
- final WindowInfo window = windowState.getWindowInfo();
+ private static void addPopulatedWindowInfo(AccessibilityWindow a11yWindow,
+ Region regionInScreen, List<WindowInfo> out, Set<IBinder> tokenOut) {
+ final WindowInfo window = a11yWindow.getWindowInfo();
window.regionInScreen.set(regionInScreen);
window.layer = tokenOut.size();
out.add(window);
@@ -1805,23 +1685,6 @@
&& windowType != WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION);
}
- private void populateVisibleWindowsOnScreen(SparseArray<WindowState> outWindows) {
- final List<WindowState> tempWindowStatesList = new ArrayList<>();
- final DisplayContent dc = mService.mRoot.getDisplayContent(mDisplayId);
- if (dc == null) {
- return;
- }
-
- dc.forAllWindows(w -> {
- if (w.isVisible()) {
- tempWindowStatesList.add(w);
- }
- }, false /* traverseTopToBottom */);
- for (int i = 0; i < tempWindowStatesList.size(); i++) {
- outWindows.put(i, tempWindowStatesList.get(i));
- }
- }
-
private WindowState getTopFocusWindow() {
return mService.mRoot.getTopFocusedDisplayContent().mCurrentFocus;
}
diff --git a/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java b/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
new file mode 100644
index 0000000..43317ad
--- /dev/null
+++ b/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
@@ -0,0 +1,861 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
+
+import static com.android.server.wm.utils.RegionUtils.forEachRect;
+
+import android.annotation.NonNull;
+import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.Region;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.view.IWindow;
+import android.view.InputWindowHandle;
+import android.view.MagnificationSpec;
+import android.view.WindowInfo;
+import android.view.WindowManager;
+import android.window.WindowInfosListener;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This class is the accessibility windows population adapter.
+ */
+public final class AccessibilityWindowsPopulator extends WindowInfosListener {
+
+ private static final String TAG = AccessibilityWindowsPopulator.class.getSimpleName();
+ // If the surface flinger callback is not coming within in 2 frames time, i.e. about
+ // 35ms, then assuming the windows become stable.
+ private static final int SURFACE_FLINGER_CALLBACK_WINDOWS_STABLE_TIMES_MS = 35;
+ // To avoid the surface flinger callbacks always comes within in 2 frames, then no windows
+ // are reported to the A11y framework, and the animation duration time is 500ms, so setting
+ // this value as the max timeout value to force computing changed windows.
+ private static final int WINDOWS_CHANGED_NOTIFICATION_MAX_DURATION_TIMES_MS = 500;
+
+ private static final float[] sTempFloats = new float[9];
+
+ private final WindowManagerService mService;
+ private final AccessibilityController mAccessibilityController;
+ @GuardedBy("mLock")
+ private final SparseArray<List<InputWindowHandle>> mInputWindowHandlesOnDisplays =
+ new SparseArray<>();
+ @GuardedBy("mLock")
+ private final SparseArray<Matrix> mMagnificationSpecInverseMatrix = new SparseArray<>();
+ @GuardedBy("mLock")
+ private final SparseArray<DisplayInfo> mDisplayInfos = new SparseArray<>();
+ private final SparseArray<MagnificationSpec> mCurrentMagnificationSpec = new SparseArray<>();
+ @GuardedBy("mLock")
+ private final SparseArray<MagnificationSpec> mPreviousMagnificationSpec = new SparseArray<>();
+ @GuardedBy("mLock")
+ private final List<InputWindowHandle> mVisibleWindows = new ArrayList<>();
+ @GuardedBy("mLock")
+ private boolean mWindowsNotificationEnabled = false;
+ @GuardedBy("mLock")
+ private final Map<IBinder, Matrix> mWindowsTransformMatrixMap = new HashMap<>();
+ private final Object mLock = new Object();
+ private final Handler mHandler;
+
+ private final Matrix mTempMatrix1 = new Matrix();
+ private final Matrix mTempMatrix2 = new Matrix();
+ private final float[] mTempFloat1 = new float[9];
+ private final float[] mTempFloat2 = new float[9];
+ private final float[] mTempFloat3 = new float[9];
+
+ AccessibilityWindowsPopulator(WindowManagerService service,
+ AccessibilityController accessibilityController) {
+ mService = service;
+ mAccessibilityController = accessibilityController;
+ mHandler = new MyHandler(mService.mH.getLooper());
+
+ register();
+ }
+
+ /**
+ * Gets the visible windows list with the window layer on the specified display.
+ *
+ * @param displayId The display.
+ * @param outWindows The visible windows list. The z-order of each window in the list
+ * is from the top to bottom.
+ */
+ public void populateVisibleWindowsOnScreenLocked(int displayId,
+ List<AccessibilityWindow> outWindows) {
+ List<InputWindowHandle> inputWindowHandles;
+ final Matrix inverseMatrix = new Matrix();
+ final Matrix displayMatrix = new Matrix();
+
+ synchronized (mLock) {
+ inputWindowHandles = mInputWindowHandlesOnDisplays.get(displayId);
+ if (inputWindowHandles == null) {
+ outWindows.clear();
+
+ return;
+ }
+ inverseMatrix.set(mMagnificationSpecInverseMatrix.get(displayId));
+
+ final DisplayInfo displayInfo = mDisplayInfos.get(displayId);
+ if (displayInfo != null) {
+ displayMatrix.set(displayInfo.mTransform);
+ } else {
+ Slog.w(TAG, "The displayInfo of this displayId (" + displayId + ") called "
+ + "back from the surface fligner is null");
+ }
+ }
+
+ final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
+ final ShellRoot shellroot = dc.mShellRoots.get(WindowManager.SHELL_ROOT_LAYER_PIP);
+ final IBinder pipMenuIBinder =
+ shellroot != null ? shellroot.getAccessibilityWindowToken() : null;
+
+ for (final InputWindowHandle windowHandle : inputWindowHandles) {
+ final AccessibilityWindow accessibilityWindow =
+ AccessibilityWindow.initializeData(mService, windowHandle, inverseMatrix,
+ pipMenuIBinder, displayMatrix);
+
+ outWindows.add(accessibilityWindow);
+ }
+ }
+
+ @Override
+ public void onWindowInfosChanged(InputWindowHandle[] windowHandles,
+ DisplayInfo[] displayInfos) {
+ final List<InputWindowHandle> tempVisibleWindows = new ArrayList<>();
+
+ for (InputWindowHandle window : windowHandles) {
+ if (window.visible && window.getWindow() != null) {
+ tempVisibleWindows.add(window);
+ }
+ }
+ final HashMap<IBinder, Matrix> windowsTransformMatrixMap =
+ getWindowsTransformMatrix(tempVisibleWindows);
+
+ synchronized (mLock) {
+ mWindowsTransformMatrixMap.clear();
+ mWindowsTransformMatrixMap.putAll(windowsTransformMatrixMap);
+
+ mVisibleWindows.clear();
+ mVisibleWindows.addAll(tempVisibleWindows);
+
+ mDisplayInfos.clear();
+ for (final DisplayInfo displayInfo : displayInfos) {
+ mDisplayInfos.put(displayInfo.mDisplayId, displayInfo);
+ }
+
+ if (!mHandler.hasMessages(
+ MyHandler.MESSAGE_NOTIFY_WINDOWS_CHANGED_BY_TIMEOUT)) {
+ mHandler.sendEmptyMessageDelayed(
+ MyHandler.MESSAGE_NOTIFY_WINDOWS_CHANGED_BY_TIMEOUT,
+ WINDOWS_CHANGED_NOTIFICATION_MAX_DURATION_TIMES_MS);
+ }
+ populateVisibleWindowHandlesAndNotifyWindowsChangeIfNeeded();
+ }
+ }
+
+ private HashMap<IBinder, Matrix> getWindowsTransformMatrix(List<InputWindowHandle> windows) {
+ synchronized (mService.mGlobalLock) {
+ final HashMap<IBinder, Matrix> windowsTransformMatrixMap = new HashMap<>();
+
+ for (InputWindowHandle inputWindowHandle : windows) {
+ final IWindow iWindow = inputWindowHandle.getWindow();
+ final WindowState windowState = iWindow != null ? mService.mWindowMap.get(
+ iWindow.asBinder()) : null;
+
+ if (windowState != null && windowState.shouldMagnify()) {
+ final Matrix transformMatrix = new Matrix();
+ windowState.getTransformationMatrix(sTempFloats, transformMatrix);
+ windowsTransformMatrixMap.put(iWindow.asBinder(), transformMatrix);
+ }
+ }
+
+ return windowsTransformMatrixMap;
+ }
+ }
+
+ /**
+ * Sets to notify the accessibilityController to compute changed windows on
+ * the display after populating the visible windows if the windows reported
+ * from the surface flinger changes.
+ *
+ * @param register {@code true} means starting windows population.
+ */
+ public void setWindowsNotification(boolean register) {
+ synchronized (mLock) {
+ if (mWindowsNotificationEnabled == register) {
+ return;
+ }
+ mWindowsNotificationEnabled = register;
+ if (mWindowsNotificationEnabled) {
+ populateVisibleWindowHandlesAndNotifyWindowsChangeIfNeeded();
+ } else {
+ releaseResources();
+ }
+ }
+ }
+
+ /**
+ * Sets the magnification spec for calculating the window bounds of all windows
+ * reported from the surface flinger in the magnifying.
+ *
+ * @param displayId The display Id.
+ * @param spec THe magnification spec.
+ */
+ public void setMagnificationSpec(int displayId, MagnificationSpec spec) {
+ synchronized (mLock) {
+ MagnificationSpec currentMagnificationSpec = mCurrentMagnificationSpec.get(displayId);
+ if (currentMagnificationSpec == null) {
+ currentMagnificationSpec = new MagnificationSpec();
+ currentMagnificationSpec.setTo(spec);
+ mCurrentMagnificationSpec.put(displayId, currentMagnificationSpec);
+
+ return;
+ }
+
+ MagnificationSpec previousMagnificationSpec = mPreviousMagnificationSpec.get(displayId);
+ if (previousMagnificationSpec == null) {
+ previousMagnificationSpec = new MagnificationSpec();
+ mPreviousMagnificationSpec.put(displayId, previousMagnificationSpec);
+ }
+ previousMagnificationSpec.setTo(currentMagnificationSpec);
+ currentMagnificationSpec.setTo(spec);
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void populateVisibleWindowHandlesAndNotifyWindowsChangeIfNeeded() {
+ final SparseArray<List<InputWindowHandle>> tempWindowHandleList = new SparseArray<>();
+
+ for (final InputWindowHandle windowHandle : mVisibleWindows) {
+ List<InputWindowHandle> inputWindowHandles = tempWindowHandleList.get(
+ windowHandle.displayId);
+
+ if (inputWindowHandles == null) {
+ inputWindowHandles = new ArrayList<>();
+ tempWindowHandleList.put(windowHandle.displayId, inputWindowHandles);
+ }
+ inputWindowHandles.add(windowHandle);
+ }
+ findMagnificationSpecInverseMatrixIfNeeded(tempWindowHandleList);
+
+ final List<Integer> displayIdsForWindowsChanged = new ArrayList<>();
+ getDisplaysForWindowsChanged(displayIdsForWindowsChanged, tempWindowHandleList,
+ mInputWindowHandlesOnDisplays);
+
+ // Clones all windows from the callback of the surface flinger.
+ mInputWindowHandlesOnDisplays.clear();
+ for (int i = 0; i < tempWindowHandleList.size(); i++) {
+ final int displayId = tempWindowHandleList.keyAt(i);
+ mInputWindowHandlesOnDisplays.put(displayId, tempWindowHandleList.get(displayId));
+ }
+
+ if (!displayIdsForWindowsChanged.isEmpty()) {
+ if (!mHandler.hasMessages(MyHandler.MESSAGE_NOTIFY_WINDOWS_CHANGED)) {
+ mHandler.obtainMessage(MyHandler.MESSAGE_NOTIFY_WINDOWS_CHANGED,
+ displayIdsForWindowsChanged).sendToTarget();
+ }
+
+ return;
+ }
+ mHandler.removeMessages(MyHandler.MESSAGE_NOTIFY_WINDOWS_CHANGED_BY_UI_STABLE);
+ mHandler.sendEmptyMessageDelayed(MyHandler.MESSAGE_NOTIFY_WINDOWS_CHANGED_BY_UI_STABLE,
+ SURFACE_FLINGER_CALLBACK_WINDOWS_STABLE_TIMES_MS);
+ }
+
+ @GuardedBy("mLock")
+ private static void getDisplaysForWindowsChanged(List<Integer> outDisplayIdsForWindowsChanged,
+ SparseArray<List<InputWindowHandle>> newWindowsList,
+ SparseArray<List<InputWindowHandle>> oldWindowsList) {
+ for (int i = 0; i < newWindowsList.size(); i++) {
+ final int displayId = newWindowsList.keyAt(i);
+ final List<InputWindowHandle> newWindows = newWindowsList.get(displayId);
+ final List<InputWindowHandle> oldWindows = oldWindowsList.get(displayId);
+
+ if (hasWindowsChanged(newWindows, oldWindows)) {
+ outDisplayIdsForWindowsChanged.add(displayId);
+ }
+ }
+ }
+
+ @GuardedBy("mLock")
+ private static boolean hasWindowsChanged(List<InputWindowHandle> newWindows,
+ List<InputWindowHandle> oldWindows) {
+ if (oldWindows == null || oldWindows.size() != newWindows.size()) {
+ return true;
+ }
+
+ final int windowsCount = newWindows.size();
+ // Since we always traverse windows from high to low layer,
+ // the old and new windows at the same index should be the
+ // same, otherwise something changed.
+ for (int i = 0; i < windowsCount; i++) {
+ final InputWindowHandle newWindow = newWindows.get(i);
+ final InputWindowHandle oldWindow = oldWindows.get(i);
+
+ if (!newWindow.getWindow().asBinder().equals(oldWindow.getWindow().asBinder())) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ @GuardedBy("mLock")
+ private void findMagnificationSpecInverseMatrixIfNeeded(SparseArray<List<InputWindowHandle>>
+ windowHandleList) {
+ MagnificationSpec currentMagnificationSpec;
+ MagnificationSpec previousMagnificationSpec;
+ for (int i = 0; i < windowHandleList.size(); i++) {
+ final int displayId = windowHandleList.keyAt(i);
+ List<InputWindowHandle> inputWindowHandles = windowHandleList.get(displayId);
+
+ final MagnificationSpec currentSpec = mCurrentMagnificationSpec.get(displayId);
+ if (currentSpec == null) {
+ continue;
+ }
+ currentMagnificationSpec = new MagnificationSpec();
+ currentMagnificationSpec.setTo(currentSpec);
+
+ final MagnificationSpec previousSpec = mPreviousMagnificationSpec.get(displayId);
+
+ if (previousSpec == null) {
+ final Matrix inverseMatrixForCurrentSpec = new Matrix();
+ generateInverseMatrix(currentMagnificationSpec, inverseMatrixForCurrentSpec);
+ mMagnificationSpecInverseMatrix.put(displayId, inverseMatrixForCurrentSpec);
+ continue;
+ }
+ previousMagnificationSpec = new MagnificationSpec();
+ previousMagnificationSpec.setTo(previousSpec);
+
+ generateInverseMatrixBasedOnProperMagnificationSpecForDisplay(inputWindowHandles,
+ currentMagnificationSpec, previousMagnificationSpec);
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void generateInverseMatrixBasedOnProperMagnificationSpecForDisplay(
+ List<InputWindowHandle> inputWindowHandles, MagnificationSpec currentMagnificationSpec,
+ MagnificationSpec previousMagnificationSpec) {
+ // To decrease the counts of holding the WindowManagerService#mGlogalLock in
+ // the method, getWindowTransformMatrix(), this for loop begins from the bottom
+ // to top of the z-order windows.
+ for (int index = inputWindowHandles.size() - 1; index >= 0; index--) {
+ final Matrix windowTransformMatrix = mTempMatrix2;
+ final InputWindowHandle windowHandle = inputWindowHandles.get(index);
+ final IBinder iBinder = windowHandle.getWindow().asBinder();
+
+ if (getWindowTransformMatrix(iBinder, windowTransformMatrix)) {
+ generateMagnificationSpecInverseMatrix(windowHandle, currentMagnificationSpec,
+ previousMagnificationSpec, windowTransformMatrix);
+
+ break;
+ }
+ }
+ }
+
+ @GuardedBy("mLock")
+ private boolean getWindowTransformMatrix(IBinder iBinder, Matrix outTransform) {
+ final Matrix windowMatrix = iBinder != null
+ ? mWindowsTransformMatrixMap.get(iBinder) : null;
+
+ if (windowMatrix == null) {
+ return false;
+ }
+ outTransform.set(windowMatrix);
+
+ return true;
+ }
+
+ /**
+ * Generates the inverse matrix based on the proper magnification spec.
+ * The magnification spec associated with the InputWindowHandle might not the current
+ * spec set by WM, which might be the previous one. To find the appropriate spec,
+ * we store two consecutive magnification specs, and found out which one is the proper
+ * one closing the identity matrix for generating the inverse matrix.
+ *
+ * @param inputWindowHandle The window from the surface flinger.
+ * @param currentMagnificationSpec The current magnification spec.
+ * @param previousMagnificationSpec The previous magnification spec.
+ * @param transformMatrix The transform matrix of the window doesn't consider the
+ * magnifying effect.
+ */
+ @GuardedBy("mLock")
+ private void generateMagnificationSpecInverseMatrix(InputWindowHandle inputWindowHandle,
+ @NonNull MagnificationSpec currentMagnificationSpec,
+ @NonNull MagnificationSpec previousMagnificationSpec, Matrix transformMatrix) {
+
+ final float[] identityMatrixFloatsForCurrentSpec = mTempFloat1;
+ computeIdentityMatrix(inputWindowHandle, currentMagnificationSpec,
+ transformMatrix, identityMatrixFloatsForCurrentSpec);
+ final float[] identityMatrixFloatsForPreviousSpec = mTempFloat2;
+ computeIdentityMatrix(inputWindowHandle, previousMagnificationSpec,
+ transformMatrix, identityMatrixFloatsForPreviousSpec);
+
+ Matrix inverseMatrixForMagnificationSpec = new Matrix();
+ if (selectProperMagnificationSpecByComparingIdentityDegree(
+ identityMatrixFloatsForCurrentSpec, identityMatrixFloatsForPreviousSpec)) {
+ generateInverseMatrix(currentMagnificationSpec,
+ inverseMatrixForMagnificationSpec);
+
+ // Choosing the current spec means the previous spec is out of date,
+ // so removing it. And if the current spec is no magnifying, meaning
+ // the magnifying is done so removing the inverse matrix of this display.
+ mPreviousMagnificationSpec.remove(inputWindowHandle.displayId);
+ if (currentMagnificationSpec.isNop()) {
+ mCurrentMagnificationSpec.remove(inputWindowHandle.displayId);
+ mMagnificationSpecInverseMatrix.remove(inputWindowHandle.displayId);
+ return;
+ }
+ } else {
+ generateInverseMatrix(previousMagnificationSpec,
+ inverseMatrixForMagnificationSpec);
+ }
+
+ mMagnificationSpecInverseMatrix.put(inputWindowHandle.displayId,
+ inverseMatrixForMagnificationSpec);
+ }
+
+ /**
+ * Computes the identity matrix for generating the
+ * inverse matrix based on below formula under window is at the stable state:
+ * inputWindowHandle#transform * MagnificationSpecMatrix * WindowState#transform
+ * = IdentityMatrix
+ */
+ @GuardedBy("mLock")
+ private void computeIdentityMatrix(InputWindowHandle inputWindowHandle,
+ @NonNull MagnificationSpec magnificationSpec,
+ Matrix transformMatrix, float[] magnifyMatrixFloats) {
+ final Matrix specMatrix = mTempMatrix1;
+ transformMagnificationSpecToMatrix(magnificationSpec, specMatrix);
+
+ final Matrix resultMatrix = new Matrix(inputWindowHandle.transform);
+ resultMatrix.preConcat(specMatrix);
+ resultMatrix.preConcat(transformMatrix);
+
+ resultMatrix.getValues(magnifyMatrixFloats);
+ }
+
+ /**
+ * @return true if selecting the magnification spec one, otherwise selecting the
+ * magnification spec two.
+ */
+ @GuardedBy("mLock")
+ private boolean selectProperMagnificationSpecByComparingIdentityDegree(
+ float[] magnifyMatrixFloatsForSpecOne,
+ float[] magnifyMatrixFloatsForSpecTwo) {
+ final float[] IdentityMatrixValues = mTempFloat3;
+ Matrix.IDENTITY_MATRIX.getValues(IdentityMatrixValues);
+
+ final float scaleDiffForSpecOne = Math.abs(IdentityMatrixValues[Matrix.MSCALE_X]
+ - magnifyMatrixFloatsForSpecOne[Matrix.MSCALE_X]);
+ final float scaleDiffForSpecTwo = Math.abs(IdentityMatrixValues[Matrix.MSCALE_X]
+ - magnifyMatrixFloatsForSpecTwo[Matrix.MSCALE_X]);
+ final float offsetXDiffForSpecOne = Math.abs(IdentityMatrixValues[Matrix.MTRANS_X]
+ - magnifyMatrixFloatsForSpecOne[Matrix.MTRANS_X]);
+ final float offsetXDiffForSpecTwo = Math.abs(IdentityMatrixValues[Matrix.MTRANS_X]
+ - magnifyMatrixFloatsForSpecTwo[Matrix.MTRANS_X]);
+ final float offsetYDiffForSpecOne = Math.abs(IdentityMatrixValues[Matrix.MTRANS_Y]
+ - magnifyMatrixFloatsForSpecOne[Matrix.MTRANS_Y]);
+ final float offsetYDiffForSpecTwo = Math.abs(IdentityMatrixValues[Matrix.MTRANS_Y]
+ - magnifyMatrixFloatsForSpecTwo[Matrix.MTRANS_Y]);
+ final float offsetDiffForSpecOne = offsetXDiffForSpecOne
+ + offsetYDiffForSpecOne;
+ final float offsetDiffForSpecTwo = offsetXDiffForSpecTwo
+ + offsetYDiffForSpecTwo;
+
+ return Float.compare(scaleDiffForSpecTwo, scaleDiffForSpecOne) > 0
+ || (Float.compare(scaleDiffForSpecTwo, scaleDiffForSpecOne) == 0
+ && Float.compare(offsetDiffForSpecTwo, offsetDiffForSpecOne) > 0);
+ }
+
+ @GuardedBy("mLock")
+ private static void generateInverseMatrix(MagnificationSpec spec, Matrix outMatrix) {
+ outMatrix.reset();
+
+ final Matrix tempMatrix = new Matrix();
+ transformMagnificationSpecToMatrix(spec, tempMatrix);
+
+ final boolean result = tempMatrix.invert(outMatrix);
+ if (!result) {
+ Slog.e(TAG, "Can't inverse the magnification spec matrix with the "
+ + "magnification spec = " + spec);
+ outMatrix.reset();
+ }
+ }
+
+ @GuardedBy("mLock")
+ private static void transformMagnificationSpecToMatrix(MagnificationSpec spec,
+ Matrix outMatrix) {
+ outMatrix.reset();
+ outMatrix.postScale(spec.scale, spec.scale);
+ outMatrix.postTranslate(spec.offsetX, spec.offsetY);
+ }
+
+ private void notifyWindowsChanged(@NonNull List<Integer> displayIdsForWindowsChanged) {
+ mHandler.removeMessages(MyHandler.MESSAGE_NOTIFY_WINDOWS_CHANGED_BY_TIMEOUT);
+
+ for (int i = 0; i < displayIdsForWindowsChanged.size(); i++) {
+ mAccessibilityController.performComputeChangedWindowsNot(
+ displayIdsForWindowsChanged.get(i), false);
+ }
+ }
+
+ private void forceUpdateWindows() {
+ final List<Integer> displayIdsForWindowsChanged = new ArrayList<>();
+
+ synchronized (mLock) {
+ for (int i = 0; i < mInputWindowHandlesOnDisplays.size(); i++) {
+ final int displayId = mInputWindowHandlesOnDisplays.keyAt(i);
+ displayIdsForWindowsChanged.add(displayId);
+ }
+ }
+ notifyWindowsChanged(displayIdsForWindowsChanged);
+ }
+
+ @GuardedBy("mLock")
+ private void releaseResources() {
+ mInputWindowHandlesOnDisplays.clear();
+ mMagnificationSpecInverseMatrix.clear();
+ mVisibleWindows.clear();
+ mDisplayInfos.clear();
+ mCurrentMagnificationSpec.clear();
+ mPreviousMagnificationSpec.clear();
+ mWindowsTransformMatrixMap.clear();
+ mWindowsNotificationEnabled = false;
+ mHandler.removeCallbacksAndMessages(null);
+ }
+
+ private class MyHandler extends Handler {
+ public static final int MESSAGE_NOTIFY_WINDOWS_CHANGED = 1;
+ public static final int MESSAGE_NOTIFY_WINDOWS_CHANGED_BY_UI_STABLE = 2;
+ public static final int MESSAGE_NOTIFY_WINDOWS_CHANGED_BY_TIMEOUT = 3;
+
+ MyHandler(Looper looper) {
+ super(looper, null, false);
+ }
+
+ @Override
+ public void handleMessage(Message message) {
+ switch (message.what) {
+ case MESSAGE_NOTIFY_WINDOWS_CHANGED: {
+ final List<Integer> displayIdsForWindowsChanged = (List<Integer>) message.obj;
+ notifyWindowsChanged(displayIdsForWindowsChanged);
+ } break;
+
+ case MESSAGE_NOTIFY_WINDOWS_CHANGED_BY_UI_STABLE: {
+ forceUpdateWindows();
+ } break;
+
+ case MESSAGE_NOTIFY_WINDOWS_CHANGED_BY_TIMEOUT: {
+ Slog.w(TAG, "Windows change within in 2 frames continuously over 500 ms "
+ + "and notify windows changed immediately");
+ mHandler.removeMessages(
+ MyHandler.MESSAGE_NOTIFY_WINDOWS_CHANGED_BY_UI_STABLE);
+
+ forceUpdateWindows();
+ } break;
+ }
+ }
+ }
+
+ /**
+ * This class represents information about a window from the
+ * surface flinger to the accessibility framework.
+ */
+ public static class AccessibilityWindow {
+ private static final Region TEMP_REGION = new Region();
+ private static final RectF TEMP_RECTF = new RectF();
+ // Data
+ private IWindow mWindow;
+ private int mDisplayId;
+ private int mFlags;
+ private int mType;
+ private int mPrivateFlags;
+ private boolean mIsPIPMenu;
+ private boolean mIsFocused;
+ private boolean mShouldMagnify;
+ private boolean mIgnoreDuetoRecentsAnimation;
+ private boolean mIsTrustedOverlay;
+ private final Region mTouchableRegionInScreen = new Region();
+ private final Region mTouchableRegionInWindow = new Region();
+ private final Region mLetterBoxBounds = new Region();
+ private WindowInfo mWindowInfo;
+
+ /**
+ * Returns the instance after initializing the internal data.
+ * @param service The window manager service.
+ * @param inputWindowHandle The window from the surface flinger.
+ * @param inverseMatrix The magnification spec inverse matrix.
+ */
+ public static AccessibilityWindow initializeData(WindowManagerService service,
+ InputWindowHandle inputWindowHandle, Matrix inverseMatrix, IBinder pipIBinder,
+ Matrix displayMatrix) {
+ final IWindow window = inputWindowHandle.getWindow();
+ final WindowState windowState = window != null ? service.mWindowMap.get(
+ window.asBinder()) : null;
+
+ final AccessibilityWindow instance = new AccessibilityWindow();
+
+ instance.mWindow = inputWindowHandle.getWindow();
+ instance.mDisplayId = inputWindowHandle.displayId;
+ instance.mFlags = inputWindowHandle.layoutParamsFlags;
+ instance.mType = inputWindowHandle.layoutParamsType;
+ instance.mIsPIPMenu = inputWindowHandle.getWindow().asBinder().equals(pipIBinder);
+
+ // TODO (b/199357848): gets the private flag of the window from other way.
+ instance.mPrivateFlags = windowState != null ? windowState.mAttrs.privateFlags : 0;
+ // TODO (b/199358208) : using new way to implement the focused window.
+ instance.mIsFocused = windowState != null && windowState.isFocused();
+ instance.mShouldMagnify = windowState == null || windowState.shouldMagnify();
+
+ final RecentsAnimationController controller = service.getRecentsAnimationController();
+ instance.mIgnoreDuetoRecentsAnimation = windowState != null && controller != null
+ && controller.shouldIgnoreForAccessibility(windowState);
+ instance.mIsTrustedOverlay = inputWindowHandle.trustedOverlay;
+
+ // TODO (b/199358388) : gets the letterbox bounds of the window from other way.
+ if (windowState != null && windowState.areAppWindowBoundsLetterboxed()) {
+ getLetterBoxBounds(windowState, instance.mLetterBoxBounds);
+ }
+
+ final Rect windowFrame = new Rect(inputWindowHandle.frameLeft,
+ inputWindowHandle.frameTop, inputWindowHandle.frameRight,
+ inputWindowHandle.frameBottom);
+ getTouchableRegionInWindow(instance.mShouldMagnify, inputWindowHandle.touchableRegion,
+ instance.mTouchableRegionInWindow, windowFrame, inverseMatrix, displayMatrix);
+ getUnMagnifiedTouchableRegion(instance.mShouldMagnify,
+ inputWindowHandle.touchableRegion, instance.mTouchableRegionInScreen,
+ inverseMatrix, displayMatrix);
+ instance.mWindowInfo = windowState != null
+ ? windowState.getWindowInfo() : getWindowInfoForWindowlessWindows(instance);
+
+ return instance;
+ }
+
+ /**
+ * Returns the touchable region in the screen.
+ * @param outRegion The touchable region.
+ */
+ public void getTouchableRegionInScreen(Region outRegion) {
+ outRegion.set(mTouchableRegionInScreen);
+ }
+
+ /**
+ * Returns the touchable region in the window.
+ * @param outRegion The touchable region.
+ */
+ public void getTouchableRegionInWindow(Region outRegion) {
+ outRegion.set(mTouchableRegionInWindow);
+ }
+
+ /**
+ * @return the layout parameter flag {@link android.view.WindowManager.LayoutParams#flags}.
+ */
+ public int getFlags() {
+ return mFlags;
+ }
+
+ /**
+ * @return the layout parameter type {@link android.view.WindowManager.LayoutParams#type}.
+ */
+ public int getType() {
+ return mType;
+ }
+
+ /**
+ * @return the layout parameter private flag
+ * {@link android.view.WindowManager.LayoutParams#privateFlags}.
+ */
+ public int getPrivateFlag() {
+ return mPrivateFlags;
+ }
+
+ /**
+ * @return the windowInfo {@link WindowInfo}.
+ */
+ public WindowInfo getWindowInfo() {
+ return mWindowInfo;
+ }
+
+ /**
+ * Gets the letter box bounds if activity bounds are letterboxed
+ * or letterboxed for display cutout.
+ *
+ * @return {@code true} there's a letter box bounds.
+ */
+ public Boolean setLetterBoxBoundsIfNeeded(Region outBounds) {
+ if (mLetterBoxBounds.isEmpty()) {
+ return false;
+ }
+
+ outBounds.set(mLetterBoxBounds);
+ return true;
+ }
+
+ /**
+ * @return true if this window should be magnified.
+ */
+ public boolean shouldMagnify() {
+ return mShouldMagnify;
+ }
+
+ /**
+ * @return true if this window is focused.
+ */
+ public boolean isFocused() {
+ return mIsFocused;
+ }
+
+ /**
+ * @return true if it's running the recent animation but not the target app.
+ */
+ public boolean ignoreRecentsAnimationForAccessibility() {
+ return mIgnoreDuetoRecentsAnimation;
+ }
+
+ /**
+ * @return true if this window is the trusted overlay.
+ */
+ public boolean isTrustedOverlay() {
+ return mIsTrustedOverlay;
+ }
+
+ /**
+ * @return true if this window is the navigation bar with the gesture mode.
+ */
+ public boolean isUntouchableNavigationBar() {
+ if (mType != WindowManager.LayoutParams.TYPE_NAVIGATION_BAR) {
+ return false;
+ }
+
+ return mTouchableRegionInScreen.isEmpty();
+ }
+
+ /**
+ * @return true if this window is PIP menu.
+ */
+ public boolean isPIPMenu() {
+ return mIsPIPMenu;
+ }
+
+ private static void getTouchableRegionInWindow(boolean shouldMagnify, Region inRegion,
+ Region outRegion, Rect frame, Matrix inverseMatrix, Matrix displayMatrix) {
+ // Some modal windows, like the activity with Theme.dialog, has the full screen
+ // as its touchable region, but its window frame is smaller than the touchable
+ // region. The region we report should be the touchable area in the window frame
+ // for the consistency and match developers expectation.
+ // So we need to make the intersection between the frame and touchable region to
+ // obtain the real touch region in the screen.
+ Region touchRegion = TEMP_REGION;
+ touchRegion.set(inRegion);
+ touchRegion.op(frame, Region.Op.INTERSECT);
+
+ getUnMagnifiedTouchableRegion(shouldMagnify, touchRegion, outRegion, inverseMatrix,
+ displayMatrix);
+ }
+
+ /**
+ * Gets the un-magnified touchable region. If this window can be magnified and magnifying,
+ * we will transform the input touchable region by applying the inverse matrix of the
+ * magnification spec to get the un-magnified touchable region.
+ * @param shouldMagnify The window can be magnified.
+ * @param inRegion The touchable region of this window.
+ * @param outRegion The un-magnified touchable region of this window.
+ * @param inverseMatrix The inverse matrix of the magnification spec.
+ * @param displayMatrix The display transform matrix which takes display coordinates to
+ * logical display coordinates.
+ */
+ private static void getUnMagnifiedTouchableRegion(boolean shouldMagnify, Region inRegion,
+ Region outRegion, Matrix inverseMatrix, Matrix displayMatrix) {
+ if ((!shouldMagnify || inverseMatrix.isIdentity()) && displayMatrix.isIdentity()) {
+ outRegion.set(inRegion);
+ return;
+ }
+
+ forEachRect(inRegion, rect -> {
+ // Move to origin as all transforms are captured by the matrix.
+ RectF windowFrame = TEMP_RECTF;
+ windowFrame.set(rect);
+
+ inverseMatrix.mapRect(windowFrame);
+ displayMatrix.mapRect(windowFrame);
+ // Union all rects.
+ outRegion.union(new Rect((int) windowFrame.left, (int) windowFrame.top,
+ (int) windowFrame.right, (int) windowFrame.bottom));
+ });
+ }
+
+ private static WindowInfo getWindowInfoForWindowlessWindows(AccessibilityWindow window) {
+ WindowInfo windowInfo = WindowInfo.obtain();
+ windowInfo.displayId = window.mDisplayId;
+ windowInfo.type = window.mType;
+ windowInfo.token = window.mWindow.asBinder();
+ windowInfo.hasFlagWatchOutsideTouch = (window.mFlags
+ & WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH) != 0;
+ windowInfo.inPictureInPicture = false;
+
+ // There only are two windowless windows now, one is split window, and the other
+ // one is PIP.
+ if (windowInfo.type == TYPE_DOCK_DIVIDER) {
+ windowInfo.title = "Splitscreen Divider";
+ } else if (window.mIsPIPMenu) {
+ windowInfo.title = "Picture-in-Picture menu";
+ }
+ return windowInfo;
+ }
+
+ private static void getLetterBoxBounds(WindowState windowState, Region outRegion) {
+ final Rect letterboxInsets = windowState.mActivityRecord.getLetterboxInsets();
+ final Rect nonLetterboxRect = windowState.getBounds();
+
+ nonLetterboxRect.inset(letterboxInsets);
+ outRegion.set(windowState.getBounds());
+ outRegion.op(nonLetterboxRect, Region.Op.DIFFERENCE);
+ }
+
+ @Override
+ public String toString() {
+ String builder = "A11yWindow=[" + mWindow.asBinder()
+ + ", displayId=" + mDisplayId
+ + ", flag=0x" + Integer.toHexString(mFlags)
+ + ", type=" + mType
+ + ", privateFlag=0x" + Integer.toHexString(mPrivateFlags)
+ + ", focused=" + mIsFocused
+ + ", shouldMagnify=" + mShouldMagnify
+ + ", ignoreDuetoRecentsAnimation=" + mIgnoreDuetoRecentsAnimation
+ + ", isTrustedOverlay=" + mIsTrustedOverlay
+ + ", regionInScreen=" + mTouchableRegionInScreen
+ + ", touchableRegion=" + mTouchableRegionInWindow
+ + ", letterBoxBounds=" + mLetterBoxBounds
+ + ", isPIPMenu=" + mIsPIPMenu
+ + ", windowInfo=" + mWindowInfo
+ + "]";
+
+ return builder;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index b0efa5b..26815b4 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -148,6 +148,7 @@
import static com.android.server.wm.ActivityRecordProto.APP_STOPPED;
import static com.android.server.wm.ActivityRecordProto.CLIENT_VISIBLE;
import static com.android.server.wm.ActivityRecordProto.DEFER_HIDING_CLIENT;
+import static com.android.server.wm.ActivityRecordProto.ENABLE_RECENTS_SCREENSHOT;
import static com.android.server.wm.ActivityRecordProto.FILLS_PARENT;
import static com.android.server.wm.ActivityRecordProto.FRONT_OF_TASK;
import static com.android.server.wm.ActivityRecordProto.IN_SIZE_COMPAT_MODE;
@@ -771,7 +772,7 @@
// Last visibility state we reported to the app token.
boolean reportedVisible;
- boolean mEnablePreviewScreenshots = true;
+ boolean mEnableRecentsScreenshot = true;
// Information about an application starting window if displayed.
// Note: these are de-referenced before the starting window animates away.
@@ -5083,10 +5084,9 @@
}
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;
@@ -5151,7 +5151,7 @@
* See {@link Activity#setRecentsScreenshotEnabled}.
*/
void setRecentsScreenshotEnabled(boolean enabled) {
- mEnablePreviewScreenshots = enabled;
+ mEnableRecentsScreenshot = enabled;
}
/**
@@ -5163,7 +5163,7 @@
* screenshot.
*/
boolean shouldUseAppThemeSnapshot() {
- return !mEnablePreviewScreenshots || forAllWindows(WindowState::isSecureLocked,
+ return !mEnableRecentsScreenshot || forAllWindows(WindowState::isSecureLocked,
true /* topToBottom */);
}
@@ -6186,6 +6186,10 @@
// The pending transition state will be cleared after the transition is started, so
// save the state for launching the client later (used by LaunchActivityItem).
mStartingData.mIsTransitionForward = true;
+ // Ensure that the transition can run with the latest orientation.
+ if (this != mDisplayContent.getLastOrientationSource()) {
+ mDisplayContent.updateOrientation();
+ }
mDisplayContent.executeAppTransition();
}
}
@@ -9184,6 +9188,7 @@
// Only record if max bounds sandboxing is applied, if the caller has the necessary
// permission to access the device configs.
proto.write(PROVIDES_MAX_BOUNDS, providesMaxBounds());
+ proto.write(ENABLE_RECENTS_SCREENSHOT, mEnableRecentsScreenshot);
}
@Override
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index 2a26050..c9b8501 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -523,8 +523,8 @@
}
void registerRemoteAnimationForNextActivityStart(String packageName,
- RemoteAnimationAdapter adapter) {
- mPendingRemoteAnimationRegistry.addPendingAnimation(packageName, adapter);
+ RemoteAnimationAdapter adapter, @Nullable IBinder launchCookie) {
+ mPendingRemoteAnimationRegistry.addPendingAnimation(packageName, adapter, launchCookie);
}
PendingRemoteAnimationRegistry getPendingRemoteAnimationRegistry() {
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index ef0ee12..fd2afd4 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -208,6 +208,9 @@
private boolean mAvoidMoveToFront;
private boolean mFrozeTaskList;
private boolean mTransientLaunch;
+ // The task which was above the targetTask before starting this activity. null if the targetTask
+ // was already on top or if the activity is in a new task.
+ private Task mPriorAboveTask;
// We must track when we deliver the new intent since multiple code paths invoke
// {@link #deliverNewIntent}. This is due to early returns in the code path. This flag is used
@@ -1666,7 +1669,8 @@
if (isTransient) {
// `r` isn't guaranteed to be the actual relevant activity, so we must wait
// until after we launched to identify the relevant activity.
- transitionController.setTransientLaunch(mLastStartActivityRecord);
+ transitionController.setTransientLaunch(mLastStartActivityRecord,
+ mPriorAboveTask);
}
if (newTransition != null) {
transitionController.requestStartTransition(newTransition,
@@ -1785,6 +1789,10 @@
return startResult;
}
+ if (targetTask != null) {
+ mPriorAboveTask = TaskDisplayArea.getRootTaskAbove(targetTask.getRootTask());
+ }
+
final ActivityRecord targetTaskTop = newTask
? null : targetTask.getTopNonFinishingActivity();
if (targetTaskTop != null) {
@@ -2196,8 +2204,9 @@
// removed from calling performClearTaskLocked (For example, if it is being brought out
// of history or if it is finished immediately), thus disassociating the task. Also note
// that mReuseTask is reset as a result of {@link Task#performClearTaskLocked}
- // launching another activity.
- targetTask.performClearTaskLocked();
+ // launching another activity. Keep the task-overlay activity because the targetTask
+ // will be reused to launch new activity.
+ targetTask.performClearTaskForReuse(true /* excludingTaskOverlay*/);
targetTask.setIntent(mStartActivity);
mAddingToTask = true;
} else if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
@@ -2207,8 +2216,7 @@
// In this situation we want to remove all activities from the task up to the one
// being started. In most cases this means we are resetting the task to its initial
// state.
- final ActivityRecord top = targetTask.performClearTaskForReuseLocked(mStartActivity,
- mLaunchFlags);
+ final ActivityRecord top = targetTask.performClearTop(mStartActivity, mLaunchFlags);
if (top != null) {
if (top.isRootOfTask()) {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 25c4d20..cecfccd 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -471,7 +471,7 @@
/** Dump the current activities state. */
public abstract boolean dumpActivity(FileDescriptor fd, PrintWriter pw, String name,
String[] args, int opti, boolean dumpAll, boolean dumpVisibleRootTasksOnly,
- boolean dumpFocusedRootTaskOnly);
+ boolean dumpFocusedRootTaskOnly, @UserIdInt int userId);
/** Dump the current state for inclusion in oom dump. */
public abstract void dumpForOom(PrintWriter pw);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 0497477..062e73d 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -3714,7 +3714,7 @@
@Override
public void registerRemoteAnimationForNextActivityStart(String packageName,
- RemoteAnimationAdapter adapter) {
+ RemoteAnimationAdapter adapter, IBinder launchCookie) {
mAmInternal.enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS,
"registerRemoteAnimationForNextActivityStart");
adapter.setCallingPidUid(Binder.getCallingPid(), Binder.getCallingUid());
@@ -3722,7 +3722,7 @@
final long origId = Binder.clearCallingIdentity();
try {
getActivityStartController().registerRemoteAnimationForNextActivityStart(
- packageName, adapter);
+ packageName, adapter, launchCookie);
} finally {
Binder.restoreCallingIdentity(origId);
}
@@ -4062,12 +4062,12 @@
*/
protected boolean dumpActivity(FileDescriptor fd, PrintWriter pw, String name, String[] args,
int opti, boolean dumpAll, boolean dumpVisibleRootTasksOnly,
- boolean dumpFocusedRootTaskOnly) {
+ boolean dumpFocusedRootTaskOnly, @UserIdInt int userId) {
ArrayList<ActivityRecord> activities;
synchronized (mGlobalLock) {
activities = mRootWindowContainer.getDumpActivities(name, dumpVisibleRootTasksOnly,
- dumpFocusedRootTaskOnly);
+ dumpFocusedRootTaskOnly, userId);
}
if (activities.size() <= 0) {
@@ -6410,9 +6410,9 @@
@Override
public boolean dumpActivity(FileDescriptor fd, PrintWriter pw, String name,
String[] args, int opti, boolean dumpAll, boolean dumpVisibleRootTasksOnly,
- boolean dumpFocusedRootTaskOnly) {
+ boolean dumpFocusedRootTaskOnly, @UserIdInt int userId) {
return ActivityTaskManagerService.this.dumpActivity(fd, pw, name, args, opti, dumpAll,
- dumpVisibleRootTasksOnly, dumpFocusedRootTaskOnly);
+ dumpVisibleRootTasksOnly, dumpFocusedRootTaskOnly, userId);
}
@Override
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 3d7dead..5573f16 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -1605,7 +1605,7 @@
task.mTransitionController.requestCloseTransitionIfNeeded(task);
task.mInRemoveTask = true;
try {
- task.performClearTask(reason);
+ task.removeActivities(reason, false /* excludingTaskOverlay */);
cleanUpRemovedTaskLocked(task, killProcess, removeFromRecents);
mService.getLockTaskController().clearLockedTask(task);
mService.getTaskChangeNotificationController().notifyTaskStackChanged();
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index 9893f68..487aff6 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -98,20 +98,33 @@
HardwareBuffer screenshotBuffer = null;
int prevTaskId;
int prevUserId;
- IOnBackInvokedCallback applicationCallback = null;
- IOnBackInvokedCallback systemCallback = null;
RemoteAnimationTarget topAppTarget;
SurfaceControl animLeash;
+ IOnBackInvokedCallback callback = null;
synchronized (task.mWmService.mGlobalLock) {
- activityRecord = task.topRunningActivity();
- removedWindowContainer = activityRecord;
- taskWindowConfiguration = task.getTaskInfo().configuration.windowConfiguration;
- WindowState window = task.getWindow(WindowState::isFocused);
+ // TODO Temp workaround for Sysui until b/221071505 is fixed
+ WindowState window = task.mWmService.getFocusedWindowLocked();
+ if (window == null) {
+ activityRecord = task.topRunningActivity();
+ removedWindowContainer = activityRecord;
+ taskWindowConfiguration = task.getTaskInfo().configuration.windowConfiguration;
+ window = task.getWindow(WindowState::isFocused);
+ } else {
+ activityRecord = window.mActivityRecord;
+ removedWindowContainer = activityRecord;
+ taskWindowConfiguration = window.getWindowConfiguration();
+ }
+ IOnBackInvokedCallback applicationCallback = null;
+ IOnBackInvokedCallback systemCallback = null;
if (window != null) {
applicationCallback = window.getApplicationOnBackInvokedCallback();
- systemCallback = window.getSystemOnBackInvokedCallback();
+ callback = applicationCallback;
+ if (callback == null) {
+ systemCallback = window.getSystemOnBackInvokedCallback();
+ callback = systemCallback;
+ }
}
ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "startBackNavigation task=%s, "
@@ -119,16 +132,25 @@
+ "systemBackCallback=%s",
task, activityRecord, applicationCallback, systemCallback);
+ // TODO Temp workaround for Sysui until b/221071505 is fixed
+ if (activityRecord == null && callback != null) {
+ return new BackNavigationInfo(BackNavigationInfo.TYPE_CALLBACK,
+ null /* topWindowLeash */, null /* screenshotSurface */,
+ null /* screenshotBuffer */, null /* taskWindowConfiguration */,
+ null /* onBackNavigationDone */,
+ callback /* onBackInvokedCallback */);
+ }
+
// For IME and Home, either a callback is registered, or we do nothing. In both cases,
// we don't need to pass the leashes below.
- if (task.getDisplayContent().getImeContainer().isVisible()
+ if (activityRecord == null || task.getDisplayContent().getImeContainer().isVisible()
|| activityRecord.isActivityTypeHome()) {
- if (applicationCallback != null) {
+ if (callback != null) {
return new BackNavigationInfo(BackNavigationInfo.TYPE_CALLBACK,
null /* topWindowLeash */, null /* screenshotSurface */,
null /* screenshotBuffer */, null /* taskWindowConfiguration */,
null /* onBackNavigationDone */,
- applicationCallback /* onBackInvokedCallback */);
+ callback /* onBackInvokedCallback */);
} else {
return null;
}
@@ -137,12 +159,12 @@
prev = task.getActivity(
(r) -> !r.finishing && r.getTask() == task && !r.isTopRunningActivity());
- if (applicationCallback != null) {
+ if (callback != null) {
return new BackNavigationInfo(BackNavigationInfo.TYPE_CALLBACK,
null /* topWindowLeash */, null /* screenshotSurface */,
null /* screenshotBuffer */, null /* taskWindowConfiguration */,
null /* onBackNavigationDone */,
- applicationCallback /* onBackInvokedCallback */);
+ callback /* onBackInvokedCallback */);
} else if (prev != null) {
backType = BackNavigationInfo.TYPE_CROSS_ACTIVITY;
} else if (task.returnsToHomeRootTask()) {
@@ -239,8 +261,6 @@
return null;
}
- final IOnBackInvokedCallback callback =
- applicationCallback != null ? applicationCallback : systemCallback;
RemoteCallback onBackNavigationDone = new RemoteCallback(
result -> resetSurfaces(finalRemovedWindowContainer
));
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 4c5c705..195d425 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 @@
* 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 @@
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 @@
@IntDef(flag = false, prefix = { "IME_TARGET_" }, value = {
IME_TARGET_LAYERING,
- IME_TARGET_INPUT,
IME_TARGET_CONTROL,
})
@Retention(RetentionPolicy.SOURCE)
@@ -1642,18 +1641,12 @@
// It has been set and not yet finished.
return true;
}
- if (!r.occludesParent()) {
+ if (!r.occludesParent() || r.isReportedDrawn()) {
// While entering or leaving a translucent or floating activity (e.g. dialog style),
// there is a visible activity in the background. Then it still needs rotation animation
// to cover the activity configuration change.
return false;
}
- if (mTransitionController.isShellTransitionsEnabled()
- ? mTransitionController.wasVisibleAtStart(r) : r.isVisible()) {
- // If activity is already visible, then it's not "launching". However, shell-transitions
- // will make it visible immediately.
- return false;
- }
if (checkOpening) {
if (mTransitionController.isShellTransitionsEnabled()) {
if (!mTransitionController.isCollecting(r)) {
@@ -3314,7 +3307,7 @@
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) {
@@ -3877,7 +3870,7 @@
}
private boolean isImeControlledByApp() {
- return mImeInputTarget != null && !mImeInputTarget.inMultiWindowMode();
+ return mImeInputTarget != null && mImeInputTarget.shouldControlIme();
}
boolean shouldImeAttachedToApp() {
@@ -3940,19 +3933,21 @@
*
* @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.
@@ -4001,9 +3996,18 @@
* 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.
@@ -4045,9 +4049,9 @@
}
@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();
}
@@ -4163,7 +4167,7 @@
* 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);
@@ -4173,8 +4177,8 @@
}
// 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();
}
}
@@ -4232,11 +4236,11 @@
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;
}
}
@@ -4249,7 +4253,7 @@
// 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;
}
@@ -5009,6 +5013,10 @@
final boolean canImeTargetSetRelativeLayer = imeTarget.getSurfaceControl() != null
&& imeTarget.mToken == imeControlTargetToken
&& !imeTarget.inMultiWindowMode()
+ // We don't need to set relative layer if the IME target in non-multi-window
+ // mode is the activity main window since updateImeParent will ensure the IME
+ // surface be attached on the fullscreen activity.
+ && imeTarget.mAttrs.type != TYPE_BASE_APPLICATION
&& imeTarget.mToken.getActivity(app -> app.isAnimating(TRANSITION | PARENTS,
ANIMATION_TYPE_ALL & ~ANIMATION_TYPE_RECENTS)) == null;
if (canImeTargetSetRelativeLayer) {
@@ -5499,7 +5507,7 @@
* display, which set unrestricted keep-clear areas.
*
* For context on restricted vs unrestricted keep-clear areas, see
- * {@link android.Manifest.permission.USE_UNRESTRICTED_KEEP_CLEAR_AREAS}.
+ * {@link android.Manifest.permission.SET_UNRESTRICTED_KEEP_CLEAR_AREAS}.
*/
void getKeepClearAreas(List<Rect> outRestricted, List<Rect> outUnrestricted) {
final Matrix tmpMatrix = new Matrix();
diff --git a/services/core/java/com/android/server/wm/EmbeddedWindowController.java b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
index 2ab08e6..dcc16eb 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.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 @@
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 @@
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 @@
if (ew.mClient.asBinder() == client.asBinder()) {
mWindows.removeAt(i).onRemoved();
mWindowsByFocusToken.remove(ew.getFocusGrantToken());
+ mWindowsByWindowToken.remove(ew.getWindowToken());
return;
}
}
@@ -127,6 +135,7 @@
if (ew.mHostWindowState == host) {
mWindows.removeAt(i).onRemoved();
mWindowsByFocusToken.remove(ew.getFocusGrantToken());
+ mWindowsByWindowToken.remove(ew.getWindowToken());
}
}
}
@@ -139,6 +148,10 @@
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 @@
}
@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 @@
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 f24e429..199517c 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 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 @@
}
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/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 44818a8..31ae864 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -414,6 +414,17 @@
final IBinder focusToken = focus != null ? focus.mInputChannelToken : null;
if (focusToken == null) {
mInputFocus = null;
+ // When an app is focused, but its window is not showing yet, remove the input focus
+ // from the current window.
+ if (mDisplayContent.mFocusedApp != null) {
+ ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "App %s is focused,"
+ + " but the window is not ready. Start a transaction to remove focus from"
+ + " the window of non-focused apps.",
+ mDisplayContent.mFocusedApp.getName());
+ EventLog.writeEvent(LOGTAG_INPUT_FOCUS, "Requesting to set focus to null window",
+ "reason=UpdateInputWindows");
+ mInputTransaction.removeCurrentInputFocus(mDisplayId);
+ }
return;
}
diff --git a/services/core/java/com/android/server/wm/InputTarget.java b/services/core/java/com/android/server/wm/InputTarget.java
index 5166b8a..b5ab62b 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 @@
/* Owning pid of the target. */
int getPid();
+ int getUid();
/**
* Indicates whether a target should receive focus from server side
@@ -45,7 +47,25 @@
*/
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/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java
index 8a2d116..160fc95 100644
--- a/services/core/java/com/android/server/wm/LockTaskController.java
+++ b/services/core/java/com/android/server/wm/LockTaskController.java
@@ -542,7 +542,7 @@
if (mLockTaskModeTasks.isEmpty()) {
return;
}
- task.performClearTaskLocked();
+ task.performClearTaskForReuse(false /* excludingTaskOverlay*/);
mSupervisor.mRootWindowContainer.resumeFocusedTasksTopActivities();
}
@@ -740,7 +740,7 @@
ProtoLog.d(WM_DEBUG_LOCKTASK, "onLockTaskPackagesUpdated: removing %s"
+ " mLockTaskAuth()=%s", lockedTask, lockedTask.lockTaskAuthToString());
removeLockedTask(lockedTask);
- lockedTask.performClearTaskLocked();
+ lockedTask.performClearTaskForReuse(false /* excludingTaskOverlay*/);
taskChanged = true;
}
diff --git a/services/core/java/com/android/server/wm/PendingRemoteAnimationRegistry.java b/services/core/java/com/android/server/wm/PendingRemoteAnimationRegistry.java
index 3b8631a..073bbbb 100644
--- a/services/core/java/com/android/server/wm/PendingRemoteAnimationRegistry.java
+++ b/services/core/java/com/android/server/wm/PendingRemoteAnimationRegistry.java
@@ -19,6 +19,7 @@
import android.annotation.Nullable;
import android.app.ActivityOptions;
import android.os.Handler;
+import android.os.IBinder;
import android.util.ArrayMap;
import android.view.RemoteAnimationAdapter;
@@ -43,8 +44,9 @@
/**
* Adds a remote animation to be run for all activity starts originating from a certain package.
*/
- void addPendingAnimation(String packageName, RemoteAnimationAdapter adapter) {
- mEntries.put(packageName, new Entry(packageName, adapter));
+ void addPendingAnimation(String packageName, RemoteAnimationAdapter adapter,
+ @Nullable IBinder launchCookie) {
+ mEntries.put(packageName, new Entry(packageName, adapter, launchCookie));
}
/**
@@ -62,6 +64,10 @@
} else {
options.setRemoteAnimationAdapter(entry.adapter);
}
+ IBinder launchCookie = entry.launchCookie;
+ if (launchCookie != null) {
+ options.setLaunchCookie(launchCookie);
+ }
mEntries.remove(callingPackage);
return options;
}
@@ -69,10 +75,13 @@
private class Entry {
final String packageName;
final RemoteAnimationAdapter adapter;
+ @Nullable
+ final IBinder launchCookie;
- Entry(String packageName, RemoteAnimationAdapter adapter) {
+ Entry(String packageName, RemoteAnimationAdapter adapter, @Nullable IBinder launchCookie) {
this.packageName = packageName;
this.adapter = adapter;
+ this.launchCookie = launchCookie;
mHandler.postDelayed(() -> {
synchronized (mLock) {
final Entry entry = mEntries.get(packageName);
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 8ab2ee0..b9cd657 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -18,15 +18,9 @@
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.KeyguardManager.ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
@@ -2791,35 +2785,17 @@
Task rootTask = null;
// Next preference for root task goes to the taskDisplayArea candidate.
- if (launchParams != null && launchParams.mPreferredTaskDisplayArea != null) {
+ if (launchParams != null && launchParams.mPreferredTaskDisplayArea != null
+ && canLaunchOnDisplay(r, launchParams.mPreferredTaskDisplayArea.getDisplayId())) {
taskDisplayArea = launchParams.mPreferredTaskDisplayArea;
}
-
- if (taskDisplayArea == null && displayId != INVALID_DISPLAY) {
- final DisplayContent displayContent = getDisplayContent(displayId);
- if (displayContent != null) {
- taskDisplayArea = displayContent.getDefaultTaskDisplayArea();
- }
+ if (taskDisplayArea == null && displayId != INVALID_DISPLAY
+ && canLaunchOnDisplay(r, displayId)) {
+ taskDisplayArea = getDisplayContent(displayId).getDefaultTaskDisplayArea();
}
-
if (taskDisplayArea != null) {
- final int tdaDisplayId = taskDisplayArea.getDisplayId();
- if (canLaunchOnDisplay(r, tdaDisplayId)) {
- if (r != null) {
- final Task result = getValidLaunchRootTaskInTaskDisplayArea(
- taskDisplayArea, r, candidateTask, options, launchParams);
- if (result != null) {
- return result;
- }
- }
- // Falling back to default task container
- taskDisplayArea = taskDisplayArea.mDisplayContent.getDefaultTaskDisplayArea();
- rootTask = taskDisplayArea.getOrCreateRootTask(r, options, candidateTask,
- sourceTask, launchParams, launchFlags, activityType, onTop);
- if (rootTask != null) {
- return rootTask;
- }
- }
+ return taskDisplayArea.getOrCreateRootTask(r, options, candidateTask,
+ sourceTask, launchParams, launchFlags, activityType, onTop);
}
// Give preference to the root task and display of the input task and activity if they
@@ -2869,103 +2845,6 @@
return r.canBeLaunchedOnDisplay(displayId);
}
- /**
- * Get a topmost root task on the display area, that is a valid launch root task for
- * specified activity. If there is no such root task, new dynamic root task can be created.
- *
- * @param taskDisplayArea Target display area.
- * @param r Activity that should be launched there.
- * @param candidateTask The possible task the activity might be put in.
- * @return Existing root task if there is a valid one, new dynamic root task if it is valid
- * or null.
- */
- @VisibleForTesting
- Task getValidLaunchRootTaskInTaskDisplayArea(@NonNull TaskDisplayArea taskDisplayArea,
- @NonNull ActivityRecord r, @Nullable Task candidateTask,
- @Nullable ActivityOptions options,
- @Nullable LaunchParamsController.LaunchParams launchParams) {
- if (!r.canBeLaunchedOnDisplay(taskDisplayArea.getDisplayId())) {
- return null;
- }
-
- // If {@code r} is already in target display area and its task is the same as the candidate
- // task, the intention should be getting a launch root task for the reusable activity, so we
- // can use the existing root task.
- if (candidateTask != null) {
- final TaskDisplayArea attachedTaskDisplayArea = candidateTask.getDisplayArea();
- if (attachedTaskDisplayArea == null || attachedTaskDisplayArea == taskDisplayArea) {
- return candidateTask.getRootTask();
- }
- // Or the candidate task is already a root task that can be reused by reparenting
- // it to the target display.
- if (candidateTask.isRootTask()) {
- final Task rootTask = candidateTask.getRootTask();
- rootTask.reparent(taskDisplayArea, true /* onTop */);
- return rootTask;
- }
- }
-
- int windowingMode;
- if (launchParams != null) {
- // When launch params is not null, we always defer to its windowing mode. Sometimes
- // it could be unspecified, which indicates it should inherit windowing mode from
- // display.
- windowingMode = launchParams.mWindowingMode;
- } else {
- windowingMode = options != null ? options.getLaunchWindowingMode()
- : r.getWindowingMode();
- }
- windowingMode = taskDisplayArea.validateWindowingMode(windowingMode, r, candidateTask);
-
- // Return the topmost valid root task on the display.
- final int targetWindowingMode = windowingMode;
- final Task topmostValidRootTask = taskDisplayArea.getRootTask(rootTask ->
- isValidLaunchRootTask(rootTask, r, targetWindowingMode));
- if (topmostValidRootTask != null) {
- return topmostValidRootTask;
- }
-
- // If there is no valid root task on the secondary display area - check if new dynamic root
- // task will do.
- if (taskDisplayArea != getDisplayContent(taskDisplayArea.getDisplayId())
- .getDefaultTaskDisplayArea()) {
- final int activityType =
- options != null && options.getLaunchActivityType() != ACTIVITY_TYPE_UNDEFINED
- ? options.getLaunchActivityType() : r.getActivityType();
- return taskDisplayArea.createRootTask(
- windowingMode, activityType, true /*onTop*/, options);
- }
-
- return null;
- }
-
- // TODO: Can probably be consolidated into getLaunchRootTask()...
- private boolean isValidLaunchRootTask(Task task, ActivityRecord r, int windowingMode) {
- switch (task.getActivityType()) {
- case ACTIVITY_TYPE_HOME:
- return r.isActivityTypeHome();
- case ACTIVITY_TYPE_RECENTS:
- return r.isActivityTypeRecents();
- case ACTIVITY_TYPE_ASSISTANT:
- return r.isActivityTypeAssistant();
- case ACTIVITY_TYPE_DREAM:
- return r.isActivityTypeDream();
- }
- if (task.mCreatedByOrganizer) {
- // Don't launch directly into task created by organizer...but why can't we?
- return false;
- }
- // There is a 1-to-1 relationship between root task and task when not in
- // primary split-windowing mode.
- if (task.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
- && r.supportsSplitScreenWindowingModeInDisplayArea(task.getDisplayArea())
- && (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
- || windowingMode == WINDOWING_MODE_UNDEFINED)) {
- return true;
- }
- return false;
- }
-
int resolveActivityType(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
@Nullable Task task) {
// Preference is given to the activity type for the activity then the task since the type
@@ -3434,11 +3313,11 @@
* or all visible root tasks if {@param dumpVisibleRootTasksOnly} is true.
*/
ArrayList<ActivityRecord> getDumpActivities(String name, boolean dumpVisibleRootTasksOnly,
- boolean dumpFocusedRootTaskOnly) {
+ boolean dumpFocusedRootTaskOnly, @UserIdInt int userId) {
if (dumpFocusedRootTaskOnly) {
final Task topFocusedRootTask = getTopDisplayFocusedRootTask();
if (topFocusedRootTask != null) {
- return topFocusedRootTask.getDumpActivitiesLocked(name);
+ return topFocusedRootTask.getDumpActivitiesLocked(name, userId);
} else {
return new ArrayList<>();
}
@@ -3446,7 +3325,7 @@
final ArrayList<ActivityRecord> activities = new ArrayList<>();
forAllRootTasks(rootTask -> {
if (!dumpVisibleRootTasksOnly || rootTask.shouldBeVisible(null)) {
- activities.addAll(rootTask.getDumpActivitiesLocked(name));
+ activities.addAll(rootTask.getDumpActivitiesLocked(name, userId));
}
});
return activities;
diff --git a/services/core/java/com/android/server/wm/ShellRoot.java b/services/core/java/com/android/server/wm/ShellRoot.java
index 2eab3ba..f9d7b53 100644
--- a/services/core/java/com/android/server/wm/ShellRoot.java
+++ b/services/core/java/com/android/server/wm/ShellRoot.java
@@ -25,15 +25,14 @@
import static com.android.server.wm.WindowManagerService.MAX_ANIMATION_DURATION;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.graphics.Point;
-import android.graphics.Rect;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
import android.view.DisplayInfo;
import android.view.IWindow;
import android.view.SurfaceControl;
-import android.view.WindowInfo;
import android.view.WindowManager;
import android.view.animation.Animation;
@@ -136,46 +135,12 @@
ANIMATION_TYPE_WINDOW_ANIMATION);
}
- WindowInfo getWindowInfo() {
- if (mShellRootLayer != SHELL_ROOT_LAYER_DIVIDER
- && mShellRootLayer != SHELL_ROOT_LAYER_PIP) {
- return null;
+ @Nullable
+ IBinder getAccessibilityWindowToken() {
+ if (mAccessibilityWindow != null) {
+ return mAccessibilityWindow.asBinder();
}
- if (mShellRootLayer == SHELL_ROOT_LAYER_DIVIDER) {
- return null;
- }
- if (mShellRootLayer == SHELL_ROOT_LAYER_PIP
- && mDisplayContent.getDefaultTaskDisplayArea().getRootPinnedTask() == null) {
- return null;
- }
- if (mAccessibilityWindow == null) {
- return null;
- }
- WindowInfo windowInfo = WindowInfo.obtain();
- windowInfo.displayId = mToken.getDisplayArea().getDisplayContent().mDisplayId;
- windowInfo.type = mToken.windowType;
- windowInfo.layer = mToken.getWindowLayerFromType();
- windowInfo.token = mAccessibilityWindow.asBinder();
- windowInfo.focused = false;
- windowInfo.hasFlagWatchOutsideTouch = false;
- final Rect regionRect = new Rect();
-
-
- // DividerView
- if (mShellRootLayer == SHELL_ROOT_LAYER_DIVIDER) {
- windowInfo.inPictureInPicture = false;
- mDisplayContent.getDockedDividerController().getTouchRegion(regionRect);
- windowInfo.regionInScreen.set(regionRect);
- windowInfo.title = "Splitscreen Divider";
- }
- // PipMenuView
- if (mShellRootLayer == SHELL_ROOT_LAYER_PIP) {
- windowInfo.inPictureInPicture = true;
- mDisplayContent.getDefaultTaskDisplayArea().getRootPinnedTask().getBounds(regionRect);
- windowInfo.regionInScreen.set(regionRect);
- windowInfo.title = "Picture-in-Picture menu";
- }
- return windowInfo;
+ return null;
}
void setAccessibilityWindow(IWindow window) {
@@ -196,9 +161,5 @@
mAccessibilityWindow = null;
}
}
- if (mDisplayContent.mWmService.mAccessibilityController.hasCallbacks()) {
- mDisplayContent.mWmService.mAccessibilityController.onSomeWindowResizedOrMoved(
- mDisplayContent.getDisplayId());
- }
}
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index ffa1a60..cc03c60 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -137,6 +137,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManager.RecentTaskInfo.PersistedTaskSnapshotData;
@@ -1583,19 +1584,23 @@
}
/** Completely remove all activities associated with an existing task. */
- void performClearTask(String reason) {
+ void removeActivities(String reason, boolean excludingTaskOverlay) {
clearPinnedTaskIfNeed();
// Broken down into to cases to avoid object create due to capturing mStack.
if (getRootTask() == null) {
forAllActivities((r) -> {
- if (r.finishing) return;
+ if (r.finishing || (excludingTaskOverlay && r.isTaskOverlay())) {
+ return;
+ }
// Task was restored from persistent storage.
r.takeFromHistory();
removeChild(r, reason);
});
} else {
forAllActivities((r) -> {
- if (r.finishing) return;
+ if (r.finishing || (excludingTaskOverlay && r.isTaskOverlay())) {
+ return;
+ }
// Prevent the transition from being executed too early if the top activity is
// resumed but the mVisibleRequested of any other activity is true, the transition
// should wait until next activity resumed.
@@ -1612,26 +1617,24 @@
/**
* Completely remove all activities associated with an existing task.
*/
- void performClearTaskLocked() {
+ void performClearTaskForReuse(boolean excludingTaskOverlay) {
mReuseTask = true;
mTaskSupervisor.beginDeferResume();
try {
- performClearTask("clear-task-all");
+ removeActivities("clear-task-all", excludingTaskOverlay);
} finally {
mTaskSupervisor.endDeferResume();
mReuseTask = false;
}
}
- ActivityRecord performClearTaskForReuseLocked(ActivityRecord newR, int launchFlags) {
- mReuseTask = true;
+ ActivityRecord performClearTop(ActivityRecord newR, int launchFlags) {
mTaskSupervisor.beginDeferResume();
final ActivityRecord result;
try {
- result = performClearTaskLocked(newR, launchFlags);
+ result = clearTopActivities(newR, launchFlags);
} finally {
mTaskSupervisor.endDeferResume();
- mReuseTask = false;
}
return result;
}
@@ -1647,7 +1650,7 @@
* @return Returns the old activity that should be continued to be used,
* or {@code null} if none was found.
*/
- private ActivityRecord performClearTaskLocked(ActivityRecord newR, int launchFlags) {
+ private ActivityRecord clearTopActivities(ActivityRecord newR, int launchFlags) {
final ActivityRecord r = findActivityInHistory(newR.mActivityComponent);
if (r == null) return null;
@@ -1674,7 +1677,7 @@
// Stop operation once we reach the boundary activity.
if (r == boundaryActivity) return true;
- if (!r.finishing) {
+ if (!r.finishing && !r.isTaskOverlay()) {
final ActivityOptions opts = r.getOptions();
if (opts != null) {
r.clearOptionsAnimation();
@@ -5149,10 +5152,13 @@
// Ensure that we do not trigger entering PiP an activity on the root pinned task
return false;
}
+ final boolean isTransient = opts != null && opts.getTransientLaunch();
final Task targetRootTask = toFrontTask != null
? toFrontTask.getRootTask() : toFrontActivity.getRootTask();
- if (targetRootTask != null && targetRootTask.isActivityTypeAssistant()) {
- // Ensure the task/activity being brought forward is not the assistant
+ if (targetRootTask != null && (targetRootTask.isActivityTypeAssistant() || isTransient)) {
+ // Ensure the task/activity being brought forward is not the assistant and is not
+ // transient. In the case of transient-launch, we want to wait until the end of the
+ // transition and only allow switch if the transient launch was committed.
return false;
}
return true;
@@ -5688,7 +5694,7 @@
}
}
- ArrayList<ActivityRecord> getDumpActivitiesLocked(String name) {
+ ArrayList<ActivityRecord> getDumpActivitiesLocked(String name, @UserIdInt int userId) {
ArrayList<ActivityRecord> activities = new ArrayList<>();
if ("all".equals(name)) {
@@ -5708,7 +5714,13 @@
}
});
}
-
+ if (userId != UserHandle.USER_ALL) {
+ for (int i = activities.size() - 1; i >= 0; --i) {
+ if (activities.get(i).mUserId != userId) {
+ activities.remove(i);
+ }
+ }
+ }
return activities;
}
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index f0cca18..2f50b14 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -941,36 +941,32 @@
Task getOrCreateRootTask(int windowingMode, int activityType, boolean onTop,
@Nullable Task candidateTask, @Nullable Task sourceTask,
@Nullable ActivityOptions options, int launchFlags) {
+ final int resolvedWindowingMode =
+ windowingMode == WINDOWING_MODE_UNDEFINED ? getWindowingMode() : windowingMode;
// Need to pass in a determined windowing mode to see if a new root task should be created,
// so use its parent's windowing mode if it is undefined.
- if (!alwaysCreateRootTask(
- windowingMode != WINDOWING_MODE_UNDEFINED ? windowingMode : getWindowingMode(),
- activityType)) {
- Task rootTask = getRootTask(windowingMode, activityType);
+ if (!alwaysCreateRootTask(resolvedWindowingMode, activityType)) {
+ Task rootTask = getRootTask(resolvedWindowingMode, activityType);
if (rootTask != null) {
return rootTask;
}
} else if (candidateTask != null) {
final int position = onTop ? POSITION_TOP : POSITION_BOTTOM;
- final Task launchRootTask = getLaunchRootTask(windowingMode, activityType, options,
- sourceTask, launchFlags);
+ final Task launchRootTask = getLaunchRootTask(resolvedWindowingMode, activityType,
+ options, sourceTask, launchFlags);
if (launchRootTask != null) {
if (candidateTask.getParent() == null) {
launchRootTask.addChild(candidateTask, position);
} else if (candidateTask.getParent() != launchRootTask) {
candidateTask.reparent(launchRootTask, position);
}
- } else if (candidateTask.getDisplayArea() != this || !candidateTask.isRootTask()) {
+ } else if (candidateTask.getDisplayArea() != this) {
if (candidateTask.getParent() == null) {
addChild(candidateTask, position);
} else {
candidateTask.reparent(this, onTop);
}
}
- // Update windowing mode if necessary, e.g. moving a pinned task to fullscreen.
- if (candidateTask.getWindowingMode() != windowingMode) {
- candidateTask.setWindowingMode(windowingMode);
- }
return candidateTask.getRootTask();
}
return new Task.Builder(mAtmService)
diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
index b8ceb4a..9bb0271 100644
--- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
@@ -157,12 +157,26 @@
// display.
if (launchMode == WINDOWING_MODE_UNDEFINED
&& canInheritWindowingModeFromSource(display, source)) {
- launchMode = source.getWindowingMode();
+ // The source's windowing mode may be different from its task, e.g. activity is set
+ // to fullscreen and its task is pinned windowing mode when the activity is entering
+ // pip.
+ launchMode = source.getTask().getWindowingMode();
if (DEBUG) {
appendLog("inherit-from-source="
+ WindowConfiguration.windowingModeToString(launchMode));
}
}
+ // If the launch windowing mode is still undefined, inherit from the target task if the
+ // task is already on the right display area (otherwise, the task may be on a different
+ // display area that has incompatible windowing mode).
+ if (launchMode == WINDOWING_MODE_UNDEFINED
+ && task != null && task.getTaskDisplayArea() == suggestedDisplayArea) {
+ launchMode = task.getWindowingMode();
+ if (DEBUG) {
+ appendLog("inherit-from-task="
+ + WindowConfiguration.windowingModeToString(launchMode));
+ }
+ }
// hasInitialBounds is set if either activity options or layout has specified bounds. If
// that's set we'll skip some adjustments later to avoid overriding the initial bounds.
boolean hasInitialBounds = false;
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 0b965c3..0f5828c 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -167,8 +167,11 @@
*/
private final ArraySet<WindowToken> mVisibleAtTransitionEndTokens = new ArraySet<>();
- /** Set of transient activities (lifecycle initially tied to this transition). */
- private ArraySet<ActivityRecord> mTransientLaunches = null;
+ /**
+ * Set of transient activities (lifecycle initially tied to this transition) and their
+ * restore-below tasks.
+ */
+ private ArrayMap<ActivityRecord, Task> mTransientLaunches = null;
/** Custom activity-level animation options and callbacks. */
private TransitionInfo.AnimationOptions mOverrideOptions;
@@ -196,17 +199,26 @@
}
/** Records an activity as transient-launch. This activity must be already collected. */
- void setTransientLaunch(@NonNull ActivityRecord activity) {
+ void setTransientLaunch(@NonNull ActivityRecord activity, @Nullable Task restoreBelow) {
if (mTransientLaunches == null) {
- mTransientLaunches = new ArraySet<>();
+ mTransientLaunches = new ArrayMap<>();
}
- mTransientLaunches.add(activity);
+ mTransientLaunches.put(activity, restoreBelow);
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Transition %d: Set %s as "
+ "transient-launch", mSyncId, activity);
}
boolean isTransientLaunch(@NonNull ActivityRecord activity) {
- return mTransientLaunches != null && mTransientLaunches.contains(activity);
+ return mTransientLaunches != null && mTransientLaunches.containsKey(activity);
+ }
+
+ Task getTransientLaunchRestoreTarget(@NonNull WindowContainer container) {
+ for (int i = 0; i < mTransientLaunches.size(); ++i) {
+ if (mTransientLaunches.keyAt(i).isDescendantOf(container)) {
+ return mTransientLaunches.valueAt(i);
+ }
+ }
+ return null;
}
boolean isOnDisplay(@NonNull DisplayContent dc) {
@@ -459,9 +471,19 @@
// activity in a bad state.
if (!visibleAtTransitionEnd && !ar.isVisibleRequested()) {
boolean commitVisibility = true;
- if (ar.getDeferHidingClient() && ar.getTask() != null) {
+ if (ar.isVisible() && ar.getTask() != null) {
if (ar.pictureInPictureArgs != null
&& ar.pictureInPictureArgs.isAutoEnterEnabled()) {
+ if (mTransientLaunches != null) {
+ for (int j = 0; j < mTransientLaunches.size(); ++j) {
+ if (mTransientLaunches.keyAt(j).isVisibleRequested()) {
+ // force enable pip-on-task-switch now that we've committed
+ // to actually launching to the transient activity.
+ ar.supportsEnterPipOnTaskSwitch = true;
+ break;
+ }
+ }
+ }
mController.mAtm.enterPictureInPictureMode(ar, ar.pictureInPictureArgs);
// Avoid commit visibility to false here, or else we will get a sudden
// "flash" / surface going invisible for a split second.
@@ -533,7 +555,7 @@
// Transient-launch activities cannot be IME target (WindowState#canBeImeTarget),
// so re-compute in case the IME target is changed after transition.
for (int t = 0; t < mTransientLaunches.size(); ++t) {
- if (mTransientLaunches.valueAt(t).getDisplayContent() == dc) {
+ if (mTransientLaunches.keyAt(t).getDisplayContent() == dc) {
dc.computeImeTarget(true /* updateImeTarget */);
break;
}
@@ -1252,7 +1274,11 @@
change.setAllowEnterPip(topMostActivity != null
&& topMostActivity.checkEnterPictureInPictureAppOpsState());
final ActivityRecord topRunningActivity = task.topRunningActivity();
- if (topRunningActivity != null && task.mDisplayContent != null) {
+ if (topRunningActivity != null && task.mDisplayContent != null
+ // Display won't be rotated for multi window Task, so the fixed rotation
+ // won't be applied. This can happen when the windowing mode is changed
+ // before the previous fixed rotation is applied.
+ && !task.inMultiWindowMode()) {
// If Activity is in fixed rotation, its will be applied with the next rotation,
// when the Task is still in the previous rotation.
final int taskRotation = task.getWindowConfiguration().getDisplayRotation();
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index c267cba..b0532c2 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -30,6 +30,7 @@
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.IApplicationThread;
+import android.app.WindowConfiguration;
import android.os.IBinder;
import android.os.IRemoteCallback;
import android.os.RemoteException;
@@ -281,19 +282,15 @@
return false;
}
- /**
- * Temporary work-around to deal with integration of legacy fixed-rotation. Returns whether
- * the activity was visible before the collecting transition.
- * TODO: at-least replace the polling mechanism.
- */
- boolean wasVisibleAtStart(@NonNull ActivityRecord ar) {
- if (mCollectingTransition == null) return ar.isVisible();
- final Transition.ChangeInfo ci = mCollectingTransition.mChanges.get(ar);
+ @WindowConfiguration.WindowingMode
+ int getWindowingModeAtStart(@NonNull WindowContainer wc) {
+ if (mCollectingTransition == null) return wc.getWindowingMode();
+ final Transition.ChangeInfo ci = mCollectingTransition.mChanges.get(wc);
if (ci == null) {
// not part of transition, so use current state.
- return ar.isVisible();
+ return wc.getWindowingMode();
}
- return ci.mVisible;
+ return ci.mWindowingMode;
}
@WindowManager.TransitionType
@@ -508,10 +505,12 @@
/**
* Record that the launch of {@param activity} is transient (meaning its lifecycle is currently
* tied to the transition).
+ * @param restoreBelowTask If non-null, the activity's task will be ordered right below this
+ * task if requested.
*/
- void setTransientLaunch(@NonNull ActivityRecord activity) {
+ void setTransientLaunch(@NonNull ActivityRecord activity, @Nullable Task restoreBelowTask) {
if (mCollectingTransition == null) return;
- mCollectingTransition.setTransientLaunch(activity);
+ mCollectingTransition.setTransientLaunch(activity, restoreBelowTask);
// TODO(b/188669821): Remove once legacy recents behavior is moved to shell.
// Also interpret HOME transient launch as recents
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 24493e2..14737d4 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -196,8 +196,11 @@
"Win " + w + ": token animating, looking behind.");
}
mFindResults.setIsWallpaperTargetForLetterbox(w.hasWallpaperForLetterboxBackground());
- // Found a target! End search.
- return true;
+ // While the keyguard is going away, both notification shade and a normal activity such
+ // as a launcher can satisfy criteria for a wallpaper target. In this case, we should
+ // chose the normal activity, otherwise wallpaper becomes invisible when a new animation
+ // starts before the keyguard going away animation finishes.
+ return w.mActivityRecord != null;
}
return false;
};
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index bbc8462..d306082 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -437,15 +437,9 @@
+ " already exists. Overwriting");
}
}
- if (insetsSourceProvider == null
- || !(insetsSourceProvider instanceof RectInsetsSourceProvider)) {
- insetsSourceProvider =
- new RectInsetsSourceProvider(
- new InsetsSource(insetsTypes[i]),
- mDisplayContent.getInsetsStateController(),
- mDisplayContent);
- mLocalInsetsSourceProviders.put(insetsTypes[i], insetsSourceProvider);
- }
+ insetsSourceProvider = new RectInsetsSourceProvider(new InsetsSource(insetsTypes[i]),
+ mDisplayContent.getInsetsStateController(), mDisplayContent);
+ mLocalInsetsSourceProviders.put(insetsTypes[i], insetsSourceProvider);
((RectInsetsSourceProvider) insetsSourceProvider).setRect(providerFrame);
}
mDisplayContent.getInsetsStateController().updateAboveInsetsState(true);
@@ -1029,7 +1023,7 @@
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 5b1021e..6445d1e 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.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;
@@ -200,6 +199,7 @@
import android.os.PowerManagerInternal;
import android.os.PowerSaveState;
import android.os.RemoteCallback;
+import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
@@ -288,6 +288,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.IResultReceiver;
import com.android.internal.policy.IKeyguardDismissCallback;
+import com.android.internal.policy.IKeyguardLockedStateListener;
import com.android.internal.policy.IShortcutService;
import com.android.internal.policy.KeyInterceptionInfo;
import com.android.internal.protolog.ProtoLogImpl;
@@ -460,6 +461,10 @@
final private KeyguardDisableHandler mKeyguardDisableHandler;
+ private final RemoteCallbackList<IKeyguardLockedStateListener> mKeyguardLockedStateListeners =
+ new RemoteCallbackList<>();
+ private boolean mDispatchedKeyguardLockedState = false;
+
// VR Vr2d Display Id.
int mVr2dDisplayId = INVALID_DISPLAY;
boolean mVrModeEnabled = false;
@@ -3029,6 +3034,7 @@
@Override
public void onKeyguardShowingAndNotOccludedChanged() {
mH.sendEmptyMessage(H.RECOMPUTE_FOCUS);
+ dispatchKeyguardLockedStateState();
}
@Override
@@ -3218,6 +3224,50 @@
}
}
+ @RequiresPermission(Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE)
+ @Override
+ public void addKeyguardLockedStateListener(IKeyguardLockedStateListener listener) {
+ enforceSubscribeToKeyguardLockedStatePermission();
+ boolean registered = mKeyguardLockedStateListeners.register(listener);
+ if (!registered) {
+ Slog.w(TAG, "Failed to register listener: " + listener);
+ }
+ }
+
+ @RequiresPermission(Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE)
+ @Override
+ public void removeKeyguardLockedStateListener(IKeyguardLockedStateListener listener) {
+ enforceSubscribeToKeyguardLockedStatePermission();
+ mKeyguardLockedStateListeners.unregister(listener);
+ }
+
+ private void enforceSubscribeToKeyguardLockedStatePermission() {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE,
+ Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE
+ + " permission required to read keyguard visibility");
+ }
+
+ private void dispatchKeyguardLockedStateState() {
+ mH.post(() -> {
+ final boolean isKeyguardLocked = mPolicy.isKeyguardShowing();
+ if (mDispatchedKeyguardLockedState == isKeyguardLocked) {
+ return;
+ }
+ final int n = mKeyguardLockedStateListeners.beginBroadcast();
+ for (int i = 0; i < n; i++) {
+ try {
+ mKeyguardLockedStateListeners.getBroadcastItem(i).onKeyguardLockedStateChanged(
+ isKeyguardLocked);
+ } catch (RemoteException e) {
+ // Handled by the RemoteCallbackList.
+ }
+ }
+ mKeyguardLockedStateListeners.finishBroadcast();
+ mDispatchedKeyguardLockedState = isKeyguardLocked;
+ });
+ }
+
@Override
public void setSwitchingUser(boolean switching) {
if (!checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
@@ -4849,7 +4899,7 @@
}
}
- private WindowState getFocusedWindowLocked() {
+ WindowState getFocusedWindowLocked() {
// Return the focused window in the focused display.
return mRoot.getTopFocusedDisplayContent().mCurrentFocus;
}
@@ -5018,6 +5068,15 @@
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;
@@ -6455,7 +6514,7 @@
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);
@@ -7663,7 +7722,8 @@
+ " imeTargetWindowToken=" + imeTargetWindowToken);
}
synchronized (mGlobalLock) {
- final WindowState imeTarget = mWindowMap.get(imeTargetWindowToken);
+ InputTarget imeTarget =
+ getInputTargetFromWindowTokenLocked(imeTargetWindowToken);
if (imeTarget != null) {
imeTarget.getDisplayContent().updateImeInputAndControlTarget(imeTarget);
}
@@ -7743,11 +7803,11 @@
}
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
@@ -7760,7 +7820,7 @@
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?
@@ -7784,7 +7844,7 @@
@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/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 4c7891b..c70a40c 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -30,6 +30,7 @@
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_CHILDREN;
+import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_RESTORE_TRANSIENT_ORDER;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT;
@@ -358,10 +359,11 @@
if (t != null && callback != null) {
syncId = startSyncWithOrganizer(callback);
}
+ final Transition transition = Transition.fromBinder(transitionToken);
// apply the incoming transaction before finish in case it alters the visibility
// of the participants.
if (t != null) {
- applyTransaction(t, syncId, null /*transition*/, caller);
+ applyTransaction(t, syncId, null /*transition*/, caller, transition);
}
getTransitionController().finishTransition(transitionToken);
if (syncId >= 0) {
@@ -374,13 +376,20 @@
}
}
+ private void applyTransaction(@NonNull WindowContainerTransaction t, int syncId,
+ @Nullable Transition transition, @NonNull CallerInfo caller) {
+ applyTransaction(t, syncId, transition, caller, null /* finishTransition */);
+ }
+
/**
* @param syncId If non-null, this will be a sync-transaction.
* @param transition A transition to collect changes into.
* @param caller Info about the calling process.
+ * @param finishTransition The transition that is currently being finished.
*/
private void applyTransaction(@NonNull WindowContainerTransaction t, int syncId,
- @Nullable Transition transition, @NonNull CallerInfo caller) {
+ @Nullable Transition transition, @NonNull CallerInfo caller,
+ @Nullable Transition finishTransition) {
int effects = 0;
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Apply window transaction, syncId=%d", syncId);
mService.deferWindowLayout();
@@ -433,7 +442,7 @@
for (int i = 0; i < hopSize; ++i) {
effects |= applyHierarchyOp(hops.get(i), effects, syncId, transition,
isInLockTaskMode, caller, t.getErrorCallbackToken(),
- t.getTaskFragmentOrganizer());
+ t.getTaskFragmentOrganizer(), finishTransition);
}
}
// Queue-up bounds-change transactions for tasks which are now organized. Do
@@ -604,7 +613,7 @@
private int applyHierarchyOp(WindowContainerTransaction.HierarchyOp hop, int effects,
int syncId, @Nullable Transition transition, boolean isInLockTaskMode,
@NonNull CallerInfo caller, @Nullable IBinder errorCallbackToken,
- @Nullable ITaskFragmentOrganizer organizer) {
+ @Nullable ITaskFragmentOrganizer organizer, @Nullable Transition finishTransition) {
final int type = hop.getType();
switch (type) {
case HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT: {
@@ -873,6 +882,19 @@
effects |= TRANSACT_EFFECTS_LIFECYCLE;
break;
}
+ case HIERARCHY_OP_TYPE_RESTORE_TRANSIENT_ORDER: {
+ if (finishTransition == null) break;
+ final WindowContainer container = WindowContainer.fromBinder(hop.getContainer());
+ if (container == null) break;
+ final Task thisTask = container.asActivityRecord() != null
+ ? container.asActivityRecord().getTask() : container.asTask();
+ if (thisTask == null) break;
+ final Task restoreAt = finishTransition.getTransientLaunchRestoreTarget(container);
+ if (restoreAt == null) break;
+ final TaskDisplayArea taskDisplayArea = thisTask.getTaskDisplayArea();
+ taskDisplayArea.moveRootTaskBehindRootTask(thisTask.getRootTask(), restoreAt);
+ break;
+ }
}
return effects;
}
diff --git a/services/core/java/com/android/server/wm/WindowOrientationListener.java b/services/core/java/com/android/server/wm/WindowOrientationListener.java
index a967ea8..de87ab9 100644
--- a/services/core/java/com/android/server/wm/WindowOrientationListener.java
+++ b/services/core/java/com/android/server/wm/WindowOrientationListener.java
@@ -1167,6 +1167,10 @@
if (mRotationResolverService == null) {
mRotationResolverService = LocalServices.getService(
RotationResolverInternal.class);
+ if (mRotationResolverService == null) {
+ finalizeRotation(reportedRotation);
+ return;
+ }
}
String packageName = null;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 87ef09e..517837c 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_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 @@
}
@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 @@
return mSession.mPid;
}
+ @Override
+ public int getUid() {
+ return mSession.mUid;
+ }
+
Task getTask() {
return mActivityRecord != null ? mActivityRecord.getTask() : null;
}
@@ -2348,7 +2352,7 @@
@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 @@
dc.setImeLayeringTarget(null);
dc.computeImeTarget(true /* updateImeTarget */);
}
- if (dc.getImeTarget(IME_TARGET_INPUT) == this) {
+ if (dc.getImeInputTarget() == this) {
dc.updateImeInputAndControlTarget(null);
}
@@ -4992,9 +4996,6 @@
if (isAnimating()) {
return;
}
- if (mWmService.mAccessibilityController.hasCallbacks()) {
- mWmService.mAccessibilityController.onSomeWindowResizedOrMoved(getDisplayId());
- }
if (!isSelfOrAncestorWindowAnimatingExit()) {
return;
@@ -5599,7 +5600,8 @@
* @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);
}
@@ -5734,8 +5736,8 @@
}
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() {
@@ -6120,4 +6122,37 @@
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/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index ccaa03a..a2e8813 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
@@ -645,8 +646,10 @@
final ActivityRecord r = asActivityRecord();
if (r != null) {
final Task rootTask = r.getRootTask();
- // Don't transform the activity in PiP because the PiP task organizer will handle it.
- if (rootTask != null && rootTask.inPinnedWindowingMode()) {
+ // Don't transform the activity exiting PiP because the PiP task organizer will handle
+ // it.
+ if (rootTask != null && mTransitionController.getWindowingModeAtStart(rootTask)
+ == WINDOWING_MODE_PINNED) {
return;
}
}
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index a9c6b8d..11714dc 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -50,6 +50,7 @@
#include "android_runtime/Log.h"
#include "gnss/AGnss.h"
#include "gnss/AGnssRil.h"
+#include "gnss/Gnss.h"
#include "gnss/GnssAntennaInfo.h"
#include "gnss/GnssAntennaInfoCallback.h"
#include "gnss/GnssBatching.h"
@@ -68,18 +69,7 @@
static jclass class_gnssPowerStats;
-static jmethodID method_reportLocation;
-static jmethodID method_reportStatus;
-static jmethodID method_reportSvStatus;
-static jmethodID method_reportNmea;
-static jmethodID method_setTopHalCapabilities;
-static jmethodID method_setGnssYearOfHardware;
-static jmethodID method_setGnssHardwareModelName;
-static jmethodID method_psdsDownloadRequest;
static jmethodID method_reportNiNotification;
-static jmethodID method_requestLocation;
-static jmethodID method_requestUtcTime;
-static jmethodID method_reportGnssServiceDied;
static jmethodID method_reportGnssPowerStats;
static jmethodID method_reportNfwNotification;
static jmethodID method_isInEmergencySession;
@@ -92,7 +82,6 @@
using android::String16;
using android::wp;
using android::binder::Status;
-using android::gnss::GnssConfigurationInterface;
using android::hardware::Return;
using android::hardware::Void;
@@ -128,12 +117,8 @@
using android::hardware::gnss::GnssPowerStats;
using android::hardware::gnss::IGnssPowerIndication;
using android::hardware::gnss::IGnssPowerIndicationCallback;
-using android::hardware::gnss::PsdsType;
-using IAGnssAidl = android::hardware::gnss::IAGnss;
-using IAGnssRilAidl = android::hardware::gnss::IAGnssRil;
using IGnssAidl = android::hardware::gnss::IGnss;
-using IGnssCallbackAidl = android::hardware::gnss::IGnssCallback;
using IGnssBatchingAidl = android::hardware::gnss::IGnssBatching;
using IGnssDebugAidl = android::hardware::gnss::IGnssDebug;
using IGnssPsdsAidl = android::hardware::gnss::IGnssPsds;
@@ -142,575 +127,30 @@
using GnssLocationAidl = android::hardware::gnss::GnssLocation;
using IGnssAntennaInfoAidl = android::hardware::gnss::IGnssAntennaInfo;
-struct GnssDeathRecipient : virtual public hidl_death_recipient
-{
- // hidl_death_recipient interface
- virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override {
- ALOGE("IGNSS hidl service failed, trying to recover...");
-
- JNIEnv* env = android::AndroidRuntime::getJNIEnv();
- env->CallVoidMethod(android::mCallbacksObj, method_reportGnssServiceDied);
- }
-};
-
-// Must match the value from GnssMeasurement.java
-static const uint32_t SVID_FLAGS_HAS_BASEBAND_CN0 = (1<<4);
-
-sp<GnssDeathRecipient> gnssHalDeathRecipient = nullptr;
-sp<IGnss_V1_0> gnssHal = nullptr;
-sp<IGnss_V1_1> gnssHal_V1_1 = nullptr;
-sp<IGnss_V2_0> gnssHal_V2_0 = nullptr;
-sp<IGnss_V2_1> gnssHal_V2_1 = nullptr;
-sp<IGnssAidl> gnssHalAidl = nullptr;
-sp<IGnssBatchingAidl> gnssBatchingAidlIface = nullptr;
-sp<IGnssPsdsAidl> gnssPsdsAidlIface = nullptr;
-sp<IGnssXtra> gnssXtraIface = nullptr;
sp<IGnssNi> gnssNiIface = nullptr;
sp<IGnssPowerIndication> gnssPowerIndicationIface = nullptr;
-std::unique_ptr<GnssConfigurationInterface> gnssConfigurationIface = nullptr;
+std::unique_ptr<android::gnss::GnssHal> gnssHal = nullptr;
+std::unique_ptr<android::gnss::AGnssInterface> agnssIface = nullptr;
+std::unique_ptr<android::gnss::AGnssRilInterface> agnssRilIface = nullptr;
+std::unique_ptr<android::gnss::GnssAntennaInfoInterface> gnssAntennaInfoIface = nullptr;
+std::unique_ptr<android::gnss::GnssConfigurationInterface> gnssConfigurationIface = nullptr;
std::unique_ptr<android::gnss::GnssMeasurementInterface> gnssMeasurementIface = nullptr;
std::unique_ptr<android::gnss::GnssNavigationMessageInterface> gnssNavigationMessageIface = nullptr;
std::unique_ptr<android::gnss::GnssBatchingInterface> gnssBatchingIface = nullptr;
-std::unique_ptr<android::gnss::GnssGeofenceInterface> gnssGeofencingIface = nullptr;
-std::unique_ptr<android::gnss::AGnssInterface> agnssIface = nullptr;
std::unique_ptr<android::gnss::GnssDebugInterface> gnssDebugIface = nullptr;
-std::unique_ptr<android::gnss::AGnssRilInterface> agnssRilIface = nullptr;
+std::unique_ptr<android::gnss::GnssGeofenceInterface> gnssGeofencingIface = nullptr;
+std::unique_ptr<android::gnss::GnssPsdsInterface> gnssPsdsIface = nullptr;
std::unique_ptr<android::gnss::GnssVisibilityControlInterface> gnssVisibilityControlIface = nullptr;
-std::unique_ptr<android::gnss::GnssAntennaInfoInterface> gnssAntennaInfoIface = nullptr;
std::unique_ptr<android::gnss::MeasurementCorrectionsInterface> gnssMeasurementCorrectionsIface =
nullptr;
-#define WAKE_LOCK_NAME "GPS"
-
namespace android {
namespace {
-// Returns true if location has lat/long information.
-bool hasLatLong(const GnssLocationAidl& location) {
- return (location.gnssLocationFlags & GnssLocationAidl::HAS_LAT_LONG) != 0;
-}
-
-// Returns true if location has lat/long information.
-bool hasLatLong(const GnssLocation_V1_0& location) {
- return (static_cast<uint32_t>(location.gnssLocationFlags) &
- GnssLocationFlags::HAS_LAT_LONG) != 0;
-}
-
-// Returns true if location has lat/long information.
-bool hasLatLong(const GnssLocation_V2_0& location) {
- return hasLatLong(location.v1_0);
-}
-
-bool isSvStatusRegistered = false;
-bool isNmeaRegistered = false;
-
} // namespace
-static inline jboolean boolToJbool(bool value) {
- return value ? JNI_TRUE : JNI_FALSE;
-}
-
-static GnssLocationAidl createGnssLocation(jint gnssLocationFlags, jdouble latitudeDegrees,
- jdouble longitudeDegrees, jdouble altitudeMeters,
- jfloat speedMetersPerSec, jfloat bearingDegrees,
- jfloat horizontalAccuracyMeters,
- jfloat verticalAccuracyMeters,
- jfloat speedAccuracyMetersPerSecond,
- jfloat bearingAccuracyDegrees, jlong timestamp,
- jint elapsedRealtimeFlags, jlong elapsedRealtimeNanos,
- jdouble elapsedRealtimeUncertaintyNanos) {
- GnssLocationAidl location;
- location.gnssLocationFlags = static_cast<int>(gnssLocationFlags);
- location.latitudeDegrees = static_cast<double>(latitudeDegrees);
- location.longitudeDegrees = static_cast<double>(longitudeDegrees);
- location.altitudeMeters = static_cast<double>(altitudeMeters);
- location.speedMetersPerSec = static_cast<double>(speedMetersPerSec);
- location.bearingDegrees = static_cast<double>(bearingDegrees);
- location.horizontalAccuracyMeters = static_cast<double>(horizontalAccuracyMeters);
- location.verticalAccuracyMeters = static_cast<double>(verticalAccuracyMeters);
- location.speedAccuracyMetersPerSecond = static_cast<double>(speedAccuracyMetersPerSecond);
- location.bearingAccuracyDegrees = static_cast<double>(bearingAccuracyDegrees);
- location.timestampMillis = static_cast<uint64_t>(timestamp);
-
- location.elapsedRealtime.flags = static_cast<int>(elapsedRealtimeFlags);
- location.elapsedRealtime.timestampNs = static_cast<uint64_t>(elapsedRealtimeNanos);
- location.elapsedRealtime.timeUncertaintyNs =
- static_cast<double>(elapsedRealtimeUncertaintyNanos);
-
- return location;
-}
-
-static GnssLocation_V1_0 createGnssLocation_V1_0(
- jint gnssLocationFlags, jdouble latitudeDegrees, jdouble longitudeDegrees,
- jdouble altitudeMeters, jfloat speedMetersPerSec, jfloat bearingDegrees,
- jfloat horizontalAccuracyMeters, jfloat verticalAccuracyMeters,
- jfloat speedAccuracyMetersPerSecond, jfloat bearingAccuracyDegrees,
- jlong timestamp) {
- GnssLocation_V1_0 location;
- location.gnssLocationFlags = static_cast<uint16_t>(gnssLocationFlags);
- location.latitudeDegrees = static_cast<double>(latitudeDegrees);
- location.longitudeDegrees = static_cast<double>(longitudeDegrees);
- location.altitudeMeters = static_cast<double>(altitudeMeters);
- location.speedMetersPerSec = static_cast<float>(speedMetersPerSec);
- location.bearingDegrees = static_cast<float>(bearingDegrees);
- location.horizontalAccuracyMeters = static_cast<float>(horizontalAccuracyMeters);
- location.verticalAccuracyMeters = static_cast<float>(verticalAccuracyMeters);
- location.speedAccuracyMetersPerSecond = static_cast<float>(speedAccuracyMetersPerSecond);
- location.bearingAccuracyDegrees = static_cast<float>(bearingAccuracyDegrees);
- location.timestamp = static_cast<uint64_t>(timestamp);
-
- return location;
-}
-
-static GnssLocation_V2_0 createGnssLocation_V2_0(
- jint gnssLocationFlags, jdouble latitudeDegrees, jdouble longitudeDegrees,
- jdouble altitudeMeters, jfloat speedMetersPerSec, jfloat bearingDegrees,
- jfloat horizontalAccuracyMeters, jfloat verticalAccuracyMeters,
- jfloat speedAccuracyMetersPerSecond, jfloat bearingAccuracyDegrees,
- jlong timestamp, jint elapsedRealtimeFlags, jlong elapsedRealtimeNanos,
- jdouble elapsedRealtimeUncertaintyNanos) {
- GnssLocation_V2_0 location;
- location.v1_0 = createGnssLocation_V1_0(
- gnssLocationFlags, latitudeDegrees, longitudeDegrees, altitudeMeters,
- speedMetersPerSec, bearingDegrees, horizontalAccuracyMeters,
- verticalAccuracyMeters, speedAccuracyMetersPerSecond,
- bearingAccuracyDegrees, timestamp);
-
- location.elapsedRealtime.flags = static_cast<uint16_t>(elapsedRealtimeFlags);
- location.elapsedRealtime.timestampNs = static_cast<uint64_t>(elapsedRealtimeNanos);
- location.elapsedRealtime.timeUncertaintyNs = static_cast<uint64_t>(elapsedRealtimeUncertaintyNanos);
-
- return location;
-}
-
-/*
- * GnssCallback class implements the callback methods for IGnss interface.
- */
-struct GnssCallback : public IGnssCallback_V2_1 {
- Return<void> gnssLocationCb(const GnssLocation_V1_0& location) override;
- Return<void> gnssStatusCb(const IGnssCallback_V1_0::GnssStatusValue status) override;
- Return<void> gnssSvStatusCb(const IGnssCallback_V1_0::GnssSvStatus& svStatus) override {
- return gnssSvStatusCbImpl<IGnssCallback_V1_0::GnssSvStatus, IGnssCallback_V1_0::GnssSvInfo>(
- svStatus);
- }
- Return<void> gnssNmeaCb(int64_t timestamp, const android::hardware::hidl_string& nmea) override;
- Return<void> gnssSetCapabilitesCb(uint32_t capabilities) override;
- Return<void> gnssAcquireWakelockCb() override;
- Return<void> gnssReleaseWakelockCb() override;
- Return<void> gnssRequestTimeCb() override;
- Return<void> gnssRequestLocationCb(const bool independentFromGnss) override;
-
- Return<void> gnssSetSystemInfoCb(const IGnssCallback_V1_0::GnssSystemInfo& info) override;
-
- // New in 1.1
- Return<void> gnssNameCb(const android::hardware::hidl_string& name) override;
-
- // New in 2.0
- Return<void> gnssRequestLocationCb_2_0(const bool independentFromGnss, const bool isUserEmergency)
- override;
- Return<void> gnssSetCapabilitiesCb_2_0(uint32_t capabilities) override;
- Return<void> gnssLocationCb_2_0(const GnssLocation_V2_0& location) override;
- Return<void> gnssSvStatusCb_2_0(const hidl_vec<IGnssCallback_V2_0::GnssSvInfo>& svInfoList) override {
- return gnssSvStatusCbImpl<hidl_vec<IGnssCallback_V2_0::GnssSvInfo>,
- IGnssCallback_V1_0::GnssSvInfo>(svInfoList);
- }
-
- // New in 2.1
- Return<void> gnssSvStatusCb_2_1(const hidl_vec<IGnssCallback_V2_1::GnssSvInfo>& svInfoList) override {
- return gnssSvStatusCbImpl<hidl_vec<IGnssCallback_V2_1::GnssSvInfo>,
- IGnssCallback_V1_0::GnssSvInfo>(svInfoList);
- }
- Return<void> gnssSetCapabilitiesCb_2_1(uint32_t capabilities) override;
-
- // TODO: Reconsider allocation cost vs threadsafety on these statics
- static const char* sNmeaString;
- static size_t sNmeaStringLength;
-
- template <class T>
- static Return<void> gnssLocationCbImpl(const T& location);
-
- template <class T_list, class T_sv_info>
- static Return<void> gnssSvStatusCbImpl(const T_list& svStatus);
-
-private:
- template <class T>
- static uint32_t getHasBasebandCn0DbHzFlag(const T& svStatus) {
- return 0;
- }
-
- template <class T>
- static double getBasebandCn0DbHz(const T& svStatus, size_t i) {
- return 0.0;
- }
-
- template <class T>
- static uint32_t getGnssSvInfoListSize(const T& svInfoList) {
- return svInfoList.size();
- }
-
- static const IGnssCallbackAidl::GnssSvInfo& getGnssSvInfoOfIndex(
- const std::vector<IGnssCallbackAidl::GnssSvInfo>& svInfoList, size_t i) {
- return svInfoList[i];
- }
-
- static const IGnssCallback_V1_0::GnssSvInfo& getGnssSvInfoOfIndex(
- const IGnssCallback_V1_0::GnssSvStatus& svStatus, size_t i) {
- return svStatus.gnssSvList.data()[i];
- }
-
- static const IGnssCallback_V1_0::GnssSvInfo& getGnssSvInfoOfIndex(
- const hidl_vec<IGnssCallback_V2_0::GnssSvInfo>& svInfoList, size_t i) {
- return svInfoList[i].v1_0;
- }
-
- static const IGnssCallback_V1_0::GnssSvInfo& getGnssSvInfoOfIndex(
- const hidl_vec<IGnssCallback_V2_1::GnssSvInfo>& svInfoList, size_t i) {
- return svInfoList[i].v2_0.v1_0;
- }
-
- template <class T>
- static uint32_t getConstellationType(const T& svInfoList, size_t i) {
- return static_cast<uint32_t>(svInfoList[i].constellation);
- }
-};
-
-Return<void> GnssCallback::gnssNameCb(const android::hardware::hidl_string& name) {
- ALOGD("%s: name=%s\n", __func__, name.c_str());
-
- JNIEnv* env = getJniEnv();
- jstring jstringName = env->NewStringUTF(name.c_str());
- env->CallVoidMethod(mCallbacksObj, method_setGnssHardwareModelName, jstringName);
- if (jstringName) {
- env->DeleteLocalRef(jstringName);
- }
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
-
- return Void();
-}
-
-const char* GnssCallback::sNmeaString = nullptr;
-size_t GnssCallback::sNmeaStringLength = 0;
-
-template<class T>
-Return<void> GnssCallback::gnssLocationCbImpl(const T& location) {
- JNIEnv* env = getJniEnv();
-
- jobject jLocation = translateGnssLocation(env, location);
-
- env->CallVoidMethod(mCallbacksObj,
- method_reportLocation,
- boolToJbool(hasLatLong(location)),
- jLocation);
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
- env->DeleteLocalRef(jLocation);
- return Void();
-}
-
-Return<void> GnssCallback::gnssLocationCb(const GnssLocation_V1_0& location) {
- return gnssLocationCbImpl<GnssLocation_V1_0>(location);
-}
-
-Return<void>
-GnssCallback::gnssLocationCb_2_0(const GnssLocation_V2_0& location) {
- return gnssLocationCbImpl<GnssLocation_V2_0>(location);
-}
-
-Return<void> GnssCallback::gnssStatusCb(const IGnssCallback_V2_0::GnssStatusValue status) {
- JNIEnv* env = getJniEnv();
- env->CallVoidMethod(mCallbacksObj, method_reportStatus, status);
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
- return Void();
-}
-
-template<>
-uint32_t GnssCallback::getHasBasebandCn0DbHzFlag(const hidl_vec<IGnssCallback_V2_1::GnssSvInfo>&
- svStatus) {
- return SVID_FLAGS_HAS_BASEBAND_CN0;
-}
-
-template <>
-uint32_t GnssCallback::getHasBasebandCn0DbHzFlag(
- const std::vector<IGnssCallbackAidl::GnssSvInfo>& svStatus) {
- return SVID_FLAGS_HAS_BASEBAND_CN0;
-}
-
-template <>
-double GnssCallback::getBasebandCn0DbHz(
- const std::vector<IGnssCallbackAidl::GnssSvInfo>& svInfoList, size_t i) {
- return svInfoList[i].basebandCN0DbHz;
-}
-
-template<>
-double GnssCallback::getBasebandCn0DbHz(const hidl_vec<IGnssCallback_V2_1::GnssSvInfo>& svInfoList,
- size_t i) {
- return svInfoList[i].basebandCN0DbHz;
-}
-
-template <>
-uint32_t GnssCallback::getGnssSvInfoListSize(const IGnssCallback_V1_0::GnssSvStatus& svStatus) {
- return svStatus.numSvs;
-}
-
-template <>
-uint32_t GnssCallback::getConstellationType(const IGnssCallback_V1_0::GnssSvStatus& svStatus,
- size_t i) {
- return static_cast<uint32_t>(svStatus.gnssSvList.data()[i].constellation);
-}
-
-template <>
-uint32_t GnssCallback::getConstellationType(
- const hidl_vec<IGnssCallback_V2_1::GnssSvInfo>& svInfoList, size_t i) {
- return static_cast<uint32_t>(svInfoList[i].v2_0.constellation);
-}
-
-template <class T_list, class T_sv_info>
-Return<void> GnssCallback::gnssSvStatusCbImpl(const T_list& svStatus) {
- // In HIDL or AIDL v1, if no listener is registered, do not report svInfoList to the framework.
- if (gnssHalAidl == nullptr || gnssHalAidl->getInterfaceVersion() <= 1) {
- if (!isSvStatusRegistered) {
- return Void();
- }
- }
-
- JNIEnv* env = getJniEnv();
-
- uint32_t listSize = getGnssSvInfoListSize(svStatus);
-
- jintArray svidWithFlagArray = env->NewIntArray(listSize);
- jfloatArray cn0Array = env->NewFloatArray(listSize);
- jfloatArray elevArray = env->NewFloatArray(listSize);
- jfloatArray azimArray = env->NewFloatArray(listSize);
- jfloatArray carrierFreqArray = env->NewFloatArray(listSize);
- jfloatArray basebandCn0Array = env->NewFloatArray(listSize);
-
- jint* svidWithFlags = env->GetIntArrayElements(svidWithFlagArray, 0);
- jfloat* cn0s = env->GetFloatArrayElements(cn0Array, 0);
- jfloat* elev = env->GetFloatArrayElements(elevArray, 0);
- jfloat* azim = env->GetFloatArrayElements(azimArray, 0);
- jfloat* carrierFreq = env->GetFloatArrayElements(carrierFreqArray, 0);
- jfloat* basebandCn0s = env->GetFloatArrayElements(basebandCn0Array, 0);
-
- /*
- * Read GNSS SV info.
- */
- for (size_t i = 0; i < listSize; ++i) {
- enum ShiftWidth: uint8_t {
- SVID_SHIFT_WIDTH = 12,
- CONSTELLATION_TYPE_SHIFT_WIDTH = 8
- };
-
- const T_sv_info& info = getGnssSvInfoOfIndex(svStatus, i);
- svidWithFlags[i] = (info.svid << SVID_SHIFT_WIDTH) |
- (getConstellationType(svStatus, i) << CONSTELLATION_TYPE_SHIFT_WIDTH) |
- static_cast<uint32_t>(info.svFlag);
- cn0s[i] = info.cN0Dbhz;
- elev[i] = info.elevationDegrees;
- azim[i] = info.azimuthDegrees;
- carrierFreq[i] = info.carrierFrequencyHz;
- svidWithFlags[i] |= getHasBasebandCn0DbHzFlag(svStatus);
- basebandCn0s[i] = getBasebandCn0DbHz(svStatus, i);
- }
-
- env->ReleaseIntArrayElements(svidWithFlagArray, svidWithFlags, 0);
- env->ReleaseFloatArrayElements(cn0Array, cn0s, 0);
- env->ReleaseFloatArrayElements(elevArray, elev, 0);
- env->ReleaseFloatArrayElements(azimArray, azim, 0);
- env->ReleaseFloatArrayElements(carrierFreqArray, carrierFreq, 0);
- env->ReleaseFloatArrayElements(basebandCn0Array, basebandCn0s, 0);
-
- env->CallVoidMethod(mCallbacksObj, method_reportSvStatus,
- static_cast<jint>(listSize), svidWithFlagArray, cn0Array, elevArray, azimArray,
- carrierFreqArray, basebandCn0Array);
-
- env->DeleteLocalRef(svidWithFlagArray);
- env->DeleteLocalRef(cn0Array);
- env->DeleteLocalRef(elevArray);
- env->DeleteLocalRef(azimArray);
- env->DeleteLocalRef(carrierFreqArray);
- env->DeleteLocalRef(basebandCn0Array);
-
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
- return Void();
-}
-
-Return<void> GnssCallback::gnssNmeaCb(int64_t timestamp,
- const ::android::hardware::hidl_string& nmea) {
- // In HIDL, if no listener is registered, do not report nmea to the framework.
- if (!isNmeaRegistered) {
- return Void();
- }
- JNIEnv* env = getJniEnv();
- /*
- * The Java code will call back to read these values.
- * We do this to avoid creating unnecessary String objects.
- */
- sNmeaString = nmea.c_str();
- sNmeaStringLength = nmea.size();
-
- env->CallVoidMethod(mCallbacksObj, method_reportNmea, timestamp);
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
- return Void();
-}
-
-Return<void> GnssCallback::gnssSetCapabilitesCb(uint32_t capabilities) {
- ALOGD("%s: %du\n", __func__, capabilities);
-
- JNIEnv* env = getJniEnv();
- env->CallVoidMethod(mCallbacksObj, method_setTopHalCapabilities, capabilities);
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
- return Void();
-}
-
-Return<void> GnssCallback::gnssSetCapabilitiesCb_2_0(uint32_t capabilities) {
- return GnssCallback::gnssSetCapabilitesCb(capabilities);
-}
-
-Return<void> GnssCallback::gnssSetCapabilitiesCb_2_1(uint32_t capabilities) {
- return GnssCallback::gnssSetCapabilitesCb(capabilities);
-}
-
-Return<void> GnssCallback::gnssAcquireWakelockCb() {
- acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME);
- return Void();
-}
-
-Return<void> GnssCallback::gnssReleaseWakelockCb() {
- release_wake_lock(WAKE_LOCK_NAME);
- return Void();
-}
-
-Return<void> GnssCallback::gnssRequestTimeCb() {
- JNIEnv* env = getJniEnv();
- env->CallVoidMethod(mCallbacksObj, method_requestUtcTime);
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
- return Void();
-}
-
-Return<void> GnssCallback::gnssRequestLocationCb(const bool independentFromGnss) {
- return GnssCallback::gnssRequestLocationCb_2_0(independentFromGnss, /* isUserEmergency= */
- false);
-}
-
-Return<void> GnssCallback::gnssRequestLocationCb_2_0(const bool independentFromGnss, const bool
- isUserEmergency) {
- JNIEnv* env = getJniEnv();
- env->CallVoidMethod(mCallbacksObj, method_requestLocation, boolToJbool(independentFromGnss),
- boolToJbool(isUserEmergency));
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
- return Void();
-}
-
-Return<void> GnssCallback::gnssSetSystemInfoCb(const IGnssCallback_V2_0::GnssSystemInfo& info) {
- ALOGD("%s: yearOfHw=%d\n", __func__, info.yearOfHw);
-
- JNIEnv* env = getJniEnv();
- env->CallVoidMethod(mCallbacksObj, method_setGnssYearOfHardware,
- info.yearOfHw);
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
- return Void();
-}
-
-class GnssCallbackAidl : public android::hardware::gnss::BnGnssCallback {
-public:
- Status gnssSetCapabilitiesCb(const int capabilities) override;
- Status gnssStatusCb(const GnssStatusValue status) override;
- Status gnssSvStatusCb(const std::vector<GnssSvInfo>& svInfoList) override;
- Status gnssLocationCb(const GnssLocationAidl& location) override;
- Status gnssNmeaCb(const int64_t timestamp, const std::string& nmea) override;
- Status gnssAcquireWakelockCb() override;
- Status gnssReleaseWakelockCb() override;
- Status gnssSetSystemInfoCb(const GnssSystemInfo& info) override;
- Status gnssRequestTimeCb() override;
- Status gnssRequestLocationCb(const bool independentFromGnss,
- const bool isUserEmergency) override;
-};
-
-Status GnssCallbackAidl::gnssSetCapabilitiesCb(const int capabilities) {
- ALOGD("GnssCallbackAidl::%s: %du\n", __func__, capabilities);
- JNIEnv* env = getJniEnv();
- env->CallVoidMethod(mCallbacksObj, method_setTopHalCapabilities, capabilities);
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
- return Status::ok();
-}
-
-Status GnssCallbackAidl::gnssStatusCb(const GnssStatusValue status) {
- JNIEnv* env = getJniEnv();
- env->CallVoidMethod(mCallbacksObj, method_reportStatus, status);
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
- return Status::ok();
-}
-
-Status GnssCallbackAidl::gnssSvStatusCb(const std::vector<GnssSvInfo>& svInfoList) {
- GnssCallback::gnssSvStatusCbImpl<std::vector<GnssSvInfo>, GnssSvInfo>(svInfoList);
- return Status::ok();
-}
-
-Status GnssCallbackAidl::gnssLocationCb(const GnssLocationAidl& location) {
- GnssCallback::gnssLocationCbImpl<GnssLocationAidl>(location);
- return Status::ok();
-}
-
-Status GnssCallbackAidl::gnssNmeaCb(const int64_t timestamp, const std::string& nmea) {
- // In AIDL v1, if no listener is registered, do not report nmea to the framework.
- if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() <= 1) {
- if (!isNmeaRegistered) {
- return Status::ok();
- }
- }
- JNIEnv* env = getJniEnv();
- /*
- * The Java code will call back to read these values.
- * We do this to avoid creating unnecessary String objects.
- */
- GnssCallback::sNmeaString = nmea.c_str();
- GnssCallback::sNmeaStringLength = nmea.size();
-
- env->CallVoidMethod(mCallbacksObj, method_reportNmea, timestamp);
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
- return Status::ok();
-}
-
-Status GnssCallbackAidl::gnssAcquireWakelockCb() {
- acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME);
- return Status::ok();
-}
-
-Status GnssCallbackAidl::gnssReleaseWakelockCb() {
- release_wake_lock(WAKE_LOCK_NAME);
- return Status::ok();
-}
-
-Status GnssCallbackAidl::gnssSetSystemInfoCb(const GnssSystemInfo& info) {
- ALOGD("%s: yearOfHw=%d, name=%s\n", __func__, info.yearOfHw, info.name.c_str());
- JNIEnv* env = getJniEnv();
- env->CallVoidMethod(mCallbacksObj, method_setGnssYearOfHardware, info.yearOfHw);
- jstring jstringName = env->NewStringUTF(info.name.c_str());
- env->CallVoidMethod(mCallbacksObj, method_setGnssHardwareModelName, jstringName);
- if (jstringName) {
- env->DeleteLocalRef(jstringName);
- }
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
- return Status::ok();
-}
-
-Status GnssCallbackAidl::gnssRequestTimeCb() {
- JNIEnv* env = getJniEnv();
- env->CallVoidMethod(mCallbacksObj, method_requestUtcTime);
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
- return Status::ok();
-}
-
-Status GnssCallbackAidl::gnssRequestLocationCb(const bool independentFromGnss,
- const bool isUserEmergency) {
- JNIEnv* env = getJniEnv();
- env->CallVoidMethod(mCallbacksObj, method_requestLocation, boolToJbool(independentFromGnss),
- boolToJbool(isUserEmergency));
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
- return Status::ok();
-}
-
/*
* GnssPowerIndicationCallback class implements the callback methods for the IGnssPowerIndication
* interface.
@@ -756,35 +196,6 @@
}
/*
- * GnssPsdsCallback class implements the callback methods for the IGnssPsds
- * interface.
- */
-struct GnssPsdsCallbackAidl : public android::hardware::gnss::BnGnssPsdsCallback {
- Status downloadRequestCb(PsdsType psdsType) override {
- ALOGD("%s. psdsType: %d", __func__, static_cast<int32_t>(psdsType));
- JNIEnv* env = getJniEnv();
- env->CallVoidMethod(mCallbacksObj, method_psdsDownloadRequest, psdsType);
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
- return Status::ok();
- }
-};
-
-/**
- * GnssXtraCallback class implements the callback methods for the IGnssXtra
- * interface.
- */
-class GnssXtraCallback : public IGnssXtraCallback {
- Return<void> downloadRequestCb() override;
-};
-
-Return<void> GnssXtraCallback::downloadRequestCb() {
- JNIEnv* env = getJniEnv();
- env->CallVoidMethod(mCallbacksObj, method_psdsDownloadRequest, /* psdsType= */ 1);
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
- return Void();
-}
-
-/*
* GnssNiCallback implements callback methods required by the IGnssNi interface.
*/
struct GnssNiCallback : public IGnssNiCallback {
@@ -822,41 +233,7 @@
/* Initializes the GNSS service handle. */
static void android_location_gnss_hal_GnssNative_set_gps_service_handle() {
- gnssHalAidl = waitForVintfService<IGnssAidl>();
- if (gnssHalAidl != nullptr) {
- ALOGD("Successfully got GNSS AIDL handle. Version=%d.", gnssHalAidl->getInterfaceVersion());
- if (gnssHalAidl->getInterfaceVersion() >= 2) {
- return;
- }
- }
-
- ALOGD("Trying IGnss_V2_1::getService()");
- gnssHal_V2_1 = IGnss_V2_1::getService();
- if (gnssHal_V2_1 != nullptr) {
- gnssHal = gnssHal_V2_1;
- gnssHal_V2_0 = gnssHal_V2_1;
- gnssHal_V1_1 = gnssHal_V2_1;
- gnssHal = gnssHal_V2_1;
- return;
- }
-
- ALOGD("gnssHal 2.1 was null, trying 2.0");
- gnssHal_V2_0 = IGnss_V2_0::getService();
- if (gnssHal_V2_0 != nullptr) {
- gnssHal = gnssHal_V2_0;
- gnssHal_V1_1 = gnssHal_V2_0;
- return;
- }
-
- ALOGD("gnssHal 2.0 was null, trying 1.1");
- gnssHal_V1_1 = IGnss_V1_1::getService();
- if (gnssHal_V1_1 != nullptr) {
- gnssHal = gnssHal_V1_1;
- return;
- }
-
- ALOGD("gnssHal 1.1 was null, trying 1.0");
- gnssHal = IGnss_V1_0::getService();
+ gnssHal = std::make_unique<gnss::GnssHal>();
}
/* One time initialization at system boot */
@@ -865,21 +242,10 @@
android_location_gnss_hal_GnssNative_set_gps_service_handle();
// Cache methodIDs and class IDs.
- method_reportLocation = env->GetMethodID(clazz, "reportLocation",
- "(ZLandroid/location/Location;)V");
- method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V");
- method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "(I[I[F[F[F[F[F)V");
- method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(J)V");
- method_setTopHalCapabilities = env->GetMethodID(clazz, "setTopHalCapabilities", "(I)V");
- method_setGnssYearOfHardware = env->GetMethodID(clazz, "setGnssYearOfHardware", "(I)V");
- method_setGnssHardwareModelName = env->GetMethodID(clazz, "setGnssHardwareModelName",
- "(Ljava/lang/String;)V");
- method_psdsDownloadRequest = env->GetMethodID(clazz, "psdsDownloadRequest", "(I)V");
+
method_reportNiNotification = env->GetMethodID(clazz, "reportNiNotification",
"(IIIIILjava/lang/String;Ljava/lang/String;II)V");
- method_requestLocation = env->GetMethodID(clazz, "requestLocation", "(ZZ)V");
- method_requestUtcTime = env->GetMethodID(clazz, "requestUtcTime", "()V");
- method_reportGnssServiceDied = env->GetMethodID(clazz, "reportGnssServiceDied", "()V");
+
method_reportNfwNotification = env->GetMethodID(clazz, "reportNfwNotification",
"(Ljava/lang/String;BLjava/lang/String;BLjava/lang/String;BZZ)V");
method_reportGnssPowerStats =
@@ -894,17 +260,19 @@
class_gnssPowerStats = (jclass)env->NewGlobalRef(gnssPowerStatsClass);
method_gnssPowerStatsCtor = env->GetMethodID(class_gnssPowerStats, "<init>", "(IJDDDDDD[D)V");
+ gnss::AGnss_class_init_once(env, clazz);
+ gnss::AGnssRil_class_init_once(env, clazz);
+ gnss::Gnss_class_init_once(env, clazz);
gnss::GnssAntennaInfo_class_init_once(env, clazz);
gnss::GnssBatching_class_init_once(env, clazz);
gnss::GnssConfiguration_class_init_once(env);
gnss::GnssGeofence_class_init_once(env, clazz);
gnss::GnssMeasurement_class_init_once(env, clazz);
gnss::GnssNavigationMessage_class_init_once(env, clazz);
+ gnss::GnssPsds_class_init_once(env, clazz);
gnss::GnssVisibilityControl_class_init_once(env, clazz);
gnss::MeasurementCorrections_class_init_once(env, clazz);
gnss::MeasurementCorrectionsCallback_class_init_once(env, clazz);
- gnss::AGnss_class_init_once(env, clazz);
- gnss::AGnssRil_class_init_once(env, clazz);
gnss::Utils_class_init_once(env);
}
@@ -923,313 +291,26 @@
android_location_gnss_hal_GnssNative_set_gps_service_handle();
}
- if (gnssHal == nullptr && gnssHalAidl == nullptr) {
+ if (gnssHal == nullptr || !gnssHal->isSupported()) {
ALOGE("Unable to get GPS service\n");
return;
}
- // TODO: linkToDeath for AIDL HAL
-
- if (gnssHal != nullptr) {
- gnssHalDeathRecipient = new GnssDeathRecipient();
- hardware::Return<bool> linked = gnssHal->linkToDeath(gnssHalDeathRecipient, /*cookie*/ 0);
- if (!linked.isOk()) {
- ALOGE("Transaction error in linking to GnssHAL death: %s",
- linked.description().c_str());
- } else if (!linked) {
- ALOGW("Unable to link to GnssHal death notifications");
- } else {
- ALOGD("Link to death notification successful");
- }
- }
-
- if (gnssHalAidl != nullptr) {
- sp<IGnssPsdsAidl> gnssPsdsAidl;
- auto status = gnssHalAidl->getExtensionPsds(&gnssPsdsAidl);
- if (status.isOk()) {
- gnssPsdsAidlIface = gnssPsdsAidl;
- } else {
- ALOGD("Unable to get a handle to PSDS AIDL interface.");
- }
- } else if (gnssHal != nullptr) {
- auto gnssXtra = gnssHal->getExtensionXtra();
- if (!gnssXtra.isOk()) {
- ALOGD("Unable to get a handle to Xtra");
- } else {
- gnssXtraIface = gnssXtra;
- }
- }
-
- if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
- sp<IAGnssRilAidl> agnssRilAidl;
- auto status = gnssHalAidl->getExtensionAGnssRil(&agnssRilAidl);
- if (checkAidlStatus(status, "Unable to get a handle to AGnssRil interface.")) {
- agnssRilIface = std::make_unique<gnss::AGnssRil>(agnssRilAidl);
- }
- } else if (gnssHal_V2_0 != nullptr) {
- auto agnssRil_V2_0 = gnssHal_V2_0->getExtensionAGnssRil_2_0();
- if (checkHidlReturn(agnssRil_V2_0, "Unable to get a handle to AGnssRil_V2_0")) {
- agnssRilIface = std::make_unique<gnss::AGnssRil_V2_0>(agnssRil_V2_0);
- }
- } else if (gnssHal != nullptr) {
- auto agnssRil_V1_0 = gnssHal->getExtensionAGnssRil();
- if (checkHidlReturn(agnssRil_V1_0, "Unable to get a handle to AGnssRil_V1_0")) {
- agnssRilIface = std::make_unique<gnss::AGnssRil_V1_0>(agnssRil_V1_0);
- }
- }
-
- if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
- sp<IAGnssAidl> agnssAidl;
- auto status = gnssHalAidl->getExtensionAGnss(&agnssAidl);
- if (checkAidlStatus(status, "Unable to get a handle to AGnss interface.")) {
- agnssIface = std::make_unique<gnss::AGnss>(agnssAidl);
- }
- } else if (gnssHal_V2_0 != nullptr) {
- auto agnss_V2_0 = gnssHal_V2_0->getExtensionAGnss_2_0();
- if (checkHidlReturn(agnss_V2_0, "Unable to get a handle to AGnss_V2_0")) {
- agnssIface = std::make_unique<gnss::AGnss_V2_0>(agnss_V2_0);
- }
- } else if (gnssHal != nullptr) {
- auto agnss_V1_0 = gnssHal->getExtensionAGnss();
- if (checkHidlReturn(agnss_V1_0, "Unable to get a handle to AGnss_V1_0")) {
- agnssIface = std::make_unique<gnss::AGnss_V1_0>(agnss_V1_0);
- }
- }
-
- if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
- sp<hardware::gnss::IGnssNavigationMessageInterface> gnssNavigationMessage;
- auto status = gnssHalAidl->getExtensionGnssNavigationMessage(&gnssNavigationMessage);
- if (checkAidlStatus(status,
- "Unable to get a handle to GnssNavigationMessage AIDL interface.")) {
- gnssNavigationMessageIface =
- std::make_unique<gnss::GnssNavigationMessageAidl>(gnssNavigationMessage);
- }
- } else if (gnssHal != nullptr) {
- auto gnssNavigationMessage = gnssHal->getExtensionGnssNavigationMessage();
- if (checkHidlReturn(gnssNavigationMessage,
- "Unable to get a handle to GnssNavigationMessage interface.")) {
- gnssNavigationMessageIface =
- std::make_unique<gnss::GnssNavigationMessageHidl>(gnssNavigationMessage);
- }
- }
-
- // Allow all causal combinations between IGnss.hal and IGnssMeasurement.hal. That means,
- // 2.1@IGnss can be paired with {1.0, 1,1, 2.0, 2.1}@IGnssMeasurement
- // 2.0@IGnss can be paired with {1.0, 1,1, 2.0}@IGnssMeasurement
- // 1.1@IGnss can be paired {1.0, 1.1}@IGnssMeasurement
- // 1.0@IGnss is paired with 1.0@IGnssMeasurement
- gnssMeasurementIface = nullptr;
- if (gnssHalAidl != nullptr) {
- sp<hardware::gnss::IGnssMeasurementInterface> gnssMeasurement;
- auto status = gnssHalAidl->getExtensionGnssMeasurement(&gnssMeasurement);
- if (checkAidlStatus(status, "Unable to get a handle to GnssMeasurement AIDL interface.")) {
- gnssMeasurementIface =
- std::make_unique<android::gnss::GnssMeasurement>(gnssMeasurement);
- }
- }
- if (gnssHal_V2_1 != nullptr && gnssMeasurementIface == nullptr) {
- auto gnssMeasurement = gnssHal_V2_1->getExtensionGnssMeasurement_2_1();
- if (checkHidlReturn(gnssMeasurement, "Unable to get a handle to GnssMeasurement_V2_1")) {
- gnssMeasurementIface =
- std::make_unique<android::gnss::GnssMeasurement_V2_1>(gnssMeasurement);
- }
- }
- if (gnssHal_V2_0 != nullptr && gnssMeasurementIface == nullptr) {
- auto gnssMeasurement = gnssHal_V2_0->getExtensionGnssMeasurement_2_0();
- if (checkHidlReturn(gnssMeasurement, "Unable to get a handle to GnssMeasurement_V2_0")) {
- gnssMeasurementIface =
- std::make_unique<android::gnss::GnssMeasurement_V2_0>(gnssMeasurement);
- }
- }
- if (gnssHal_V1_1 != nullptr && gnssMeasurementIface == nullptr) {
- auto gnssMeasurement = gnssHal_V1_1->getExtensionGnssMeasurement_1_1();
- if (checkHidlReturn(gnssMeasurement, "Unable to get a handle to GnssMeasurement_V1_1")) {
- gnssMeasurementIface =
- std::make_unique<android::gnss::GnssMeasurement_V1_1>(gnssMeasurement);
- }
- }
- if (gnssHal != nullptr && gnssMeasurementIface == nullptr) {
- auto gnssMeasurement = gnssHal->getExtensionGnssMeasurement();
- if (checkHidlReturn(gnssMeasurement, "Unable to get a handle to GnssMeasurement_V1_0")) {
- gnssMeasurementIface =
- std::make_unique<android::gnss::GnssMeasurement_V1_0>(gnssMeasurement);
- }
- }
-
- if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
- sp<IGnssAntennaInfoAidl> gnssAntennaInfoAidl;
- auto status = gnssHalAidl->getExtensionGnssAntennaInfo(&gnssAntennaInfoAidl);
- if (checkAidlStatus(status, "Unable to get a handle to GnssAntennaInfo interface.")) {
- gnssAntennaInfoIface = std::make_unique<gnss::GnssAntennaInfoAidl>(gnssAntennaInfoAidl);
- }
- } else if (gnssHal_V2_1 != nullptr) {
- auto gnssAntennaInfo_V2_1 = gnssHal_V2_1->getExtensionGnssAntennaInfo();
- if (checkHidlReturn(gnssAntennaInfo_V2_1,
- "Unable to get a handle to GnssAntennaInfo_V2_1")) {
- gnssAntennaInfoIface =
- std::make_unique<gnss::GnssAntennaInfo_V2_1>(gnssAntennaInfo_V2_1);
- }
- }
-
- if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
- sp<android::hardware::gnss::measurement_corrections::IMeasurementCorrectionsInterface>
- gnssMeasurementCorrectionsAidl;
- auto status =
- gnssHalAidl->getExtensionMeasurementCorrections(&gnssMeasurementCorrectionsAidl);
- if (checkAidlStatus(status,
- "Unable to get a handle to GnssVisibilityControl AIDL interface.")) {
- gnssMeasurementCorrectionsIface =
- std::make_unique<gnss::MeasurementCorrectionsIface_Aidl>(
- gnssMeasurementCorrectionsAidl);
- }
- }
- if (gnssHal_V2_1 != nullptr && gnssMeasurementCorrectionsIface == nullptr) {
- auto gnssCorrections = gnssHal_V2_1->getExtensionMeasurementCorrections_1_1();
- if (checkHidlReturn(gnssCorrections,
- "Unable to get a handle to GnssMeasurementCorrections HIDL "
- "interface")) {
- gnssMeasurementCorrectionsIface =
- std::make_unique<gnss::MeasurementCorrectionsIface_V1_1>(gnssCorrections);
- }
- }
- if (gnssHal_V2_0 != nullptr && gnssMeasurementCorrectionsIface == nullptr) {
- auto gnssCorrections = gnssHal_V2_0->getExtensionMeasurementCorrections();
- if (checkHidlReturn(gnssCorrections,
- "Unable to get a handle to GnssMeasurementCorrections HIDL "
- "interface")) {
- gnssMeasurementCorrectionsIface =
- std::make_unique<gnss::MeasurementCorrectionsIface_V1_0>(gnssCorrections);
- }
- }
-
- // Allow all causal combinations between IGnss.hal and IGnssDebug.hal. That means,
- // 2.0@IGnss can be paired with {1.0, 2.0}@IGnssDebug
- // 1.0@IGnss is paired with 1.0@IGnssDebug
-
- if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
- sp<IGnssDebugAidl> gnssDebugAidl;
- auto status = gnssHalAidl->getExtensionGnssDebug(&gnssDebugAidl);
- if (checkAidlStatus(status, "Unable to get a handle to GnssDebug interface.")) {
- gnssDebugIface = std::make_unique<gnss::GnssDebug>(gnssDebugAidl);
- }
- }
- if (gnssHal_V2_0 != nullptr && gnssDebugIface == nullptr) {
- auto gnssDebug_V2_0 = gnssHal_V2_0->getExtensionGnssDebug_2_0();
- if (checkHidlReturn(gnssDebug_V2_0, "Unable to get a handle to GnssDebug_V2_0.")) {
- gnssDebugIface = std::make_unique<gnss::GnssDebug_V2_0>(gnssDebug_V2_0);
- }
- }
- if (gnssHal != nullptr && gnssDebugIface == nullptr) {
- auto gnssDebug_V1_0 = gnssHal->getExtensionGnssDebug();
- if (checkHidlReturn(gnssDebug_V1_0, "Unable to get a handle to GnssDebug_V1_0.")) {
- gnssDebugIface = std::make_unique<gnss::GnssDebug_V1_0>(gnssDebug_V1_0);
- }
- }
-
- if (gnssHal != nullptr) {
- auto gnssNi = gnssHal->getExtensionGnssNi();
- if (!gnssNi.isOk()) {
- ALOGD("Unable to get a handle to GnssNi");
- } else {
- gnssNiIface = gnssNi;
- }
- }
-
- if (gnssHalAidl != nullptr) {
- sp<IGnssConfigurationAidl> gnssConfigurationAidl;
- auto status = gnssHalAidl->getExtensionGnssConfiguration(&gnssConfigurationAidl);
- if (checkAidlStatus(status,
- "Unable to get a handle to GnssConfiguration AIDL interface.")) {
- gnssConfigurationIface =
- std::make_unique<android::gnss::GnssConfiguration>(gnssConfigurationAidl);
- }
- } else if (gnssHal_V2_1 != nullptr) {
- auto gnssConfiguration = gnssHal_V2_1->getExtensionGnssConfiguration_2_1();
- if (checkHidlReturn(gnssConfiguration,
- "Unable to get a handle to GnssConfiguration_V2_1")) {
- gnssConfigurationIface =
- std::make_unique<android::gnss::GnssConfiguration_V2_1>(gnssConfiguration);
- }
- } else if (gnssHal_V2_0 != nullptr) {
- auto gnssConfiguration = gnssHal_V2_0->getExtensionGnssConfiguration_2_0();
- if (checkHidlReturn(gnssConfiguration,
- "Unable to get a handle to GnssConfiguration_V2_0")) {
- gnssConfigurationIface =
- std::make_unique<android::gnss::GnssConfiguration_V2_0>(gnssConfiguration);
- }
- } else if (gnssHal_V1_1 != nullptr) {
- auto gnssConfiguration = gnssHal_V1_1->getExtensionGnssConfiguration_1_1();
- if (checkHidlReturn(gnssConfiguration,
- "Unable to get a handle to GnssConfiguration_V1_1")) {
- gnssConfigurationIface =
- std::make_unique<gnss::GnssConfiguration_V1_1>(gnssConfiguration);
- }
- } else if (gnssHal != nullptr) {
- auto gnssConfiguration = gnssHal->getExtensionGnssConfiguration();
- if (checkHidlReturn(gnssConfiguration,
- "Unable to get a handle to GnssConfiguration_V1_0")) {
- gnssConfigurationIface =
- std::make_unique<gnss::GnssConfiguration_V1_0>(gnssConfiguration);
- }
- }
-
- if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
- sp<hardware::gnss::IGnssGeofence> gnssGeofence;
- auto status = gnssHalAidl->getExtensionGnssGeofence(&gnssGeofence);
- if (checkAidlStatus(status, "Unable to get a handle to GnssGeofence AIDL interface.")) {
- gnssGeofencingIface = std::make_unique<gnss::GnssGeofenceAidl>(gnssGeofence);
- }
- } else if (gnssHal != nullptr) {
- auto gnssGeofencing = gnssHal->getExtensionGnssGeofencing();
- if (checkHidlReturn(gnssGeofencing, "Unable to get a handle to GnssGeofencing")) {
- gnssGeofencingIface = std::make_unique<gnss::GnssGeofenceHidl>(gnssGeofencing);
- }
- }
-
- if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
- sp<android::hardware::gnss::IGnssBatching> gnssBatchingAidl;
- auto status = gnssHalAidl->getExtensionGnssBatching(&gnssBatchingAidl);
- if (checkAidlStatus(status, "Unable to get a handle to GnssBatching interface.")) {
- gnssBatchingIface = std::make_unique<gnss::GnssBatching>(gnssBatchingAidl);
- }
- } else if (gnssHal_V2_0 != nullptr) {
- auto gnssBatching_V2_0 = gnssHal_V2_0->getExtensionGnssBatching_2_0();
- if (checkHidlReturn(gnssBatching_V2_0, "Unable to get a handle to GnssBatching_V2_0")) {
- gnssBatchingIface = std::make_unique<gnss::GnssBatching_V2_0>(gnssBatching_V2_0);
- }
- }
- if (gnssHal != nullptr && gnssBatchingIface == nullptr) {
- auto gnssBatching_V1_0 = gnssHal->getExtensionGnssBatching();
- if (checkHidlReturn(gnssBatching_V1_0, "Unable to get a handle to GnssBatching")) {
- gnssBatchingIface = std::make_unique<gnss::GnssBatching_V1_0>(gnssBatching_V1_0);
- }
- }
-
- if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
- sp<android::hardware::gnss::visibility_control::IGnssVisibilityControl>
- gnssVisibilityControlAidl;
- auto status = gnssHalAidl->getExtensionGnssVisibilityControl(&gnssVisibilityControlAidl);
- if (checkAidlStatus(status,
- "Unable to get a handle to GnssVisibilityControl AIDL interface.")) {
- gnssVisibilityControlIface =
- std::make_unique<gnss::GnssVisibilityControlAidl>(gnssVisibilityControlAidl);
- }
- } else if (gnssHal_V2_0 != nullptr) {
- auto gnssVisibilityControlHidl = gnssHal_V2_0->getExtensionVisibilityControl();
- if (checkHidlReturn(gnssVisibilityControlHidl,
- "Unable to get a handle to GnssVisibilityControl HIDL interface")) {
- gnssVisibilityControlIface =
- std::make_unique<gnss::GnssVisibilityControlHidl>(gnssVisibilityControlHidl);
- }
- }
-
- if (gnssHalAidl != nullptr) {
- sp<IGnssPowerIndication> gnssPowerIndication;
- auto status = gnssHalAidl->getExtensionGnssPowerIndication(&gnssPowerIndication);
- if (checkAidlStatus(status, "Unable to get a handle to GnssPowerIndication interface.")) {
- gnssPowerIndicationIface = gnssPowerIndication;
- }
- }
+ gnssHal->linkToDeath();
+ gnssPsdsIface = gnssHal->getGnssPsdsInterface();
+ agnssRilIface = gnssHal->getAGnssRilInterface();
+ agnssIface = gnssHal->getAGnssInterface();
+ gnssNavigationMessageIface = gnssHal->getGnssNavigationMessageInterface();
+ gnssMeasurementIface = gnssHal->getGnssMeasurementInterface();
+ gnssAntennaInfoIface = gnssHal->getGnssAntennaInfoInterface();
+ gnssMeasurementCorrectionsIface = gnssHal->getMeasurementCorrectionsInterface();
+ gnssDebugIface = gnssHal->getGnssDebugInterface();
+ gnssNiIface = gnssHal->getGnssNiInterface();
+ gnssConfigurationIface = gnssHal->getGnssConfigurationInterface();
+ gnssGeofencingIface = gnssHal->getGnssGeofenceInterface();
+ gnssBatchingIface = gnssHal->getGnssBatchingInterface();
+ gnssVisibilityControlIface = gnssHal->getGnssVisibilityControlInterface();
+ gnssPowerIndicationIface = gnssHal->getGnssPowerIndicationInterface();
if (mCallbacksObj) {
ALOGE("Callbacks already initialized");
@@ -1239,7 +320,7 @@
}
static jboolean android_location_gnss_hal_GnssNative_is_supported(JNIEnv* /* env */, jclass) {
- return (gnssHalAidl != nullptr || gnssHal != nullptr) ? JNI_TRUE : JNI_FALSE;
+ return (gnssHal != nullptr && gnssHal->isSupported()) ? JNI_TRUE : JNI_FALSE;
}
static jboolean android_location_GnssNetworkConnectivityHandler_is_agps_ril_supported(
@@ -1268,52 +349,18 @@
/*
* Fail if the main interface fails to initialize
*/
- if (gnssHal == nullptr && gnssHalAidl == nullptr) {
+ if (!gnssHal->isSupported()) {
ALOGE("Unable to initialize GNSS HAL.");
return JNI_FALSE;
}
- // Set top level IGnss.hal callback.
- if (gnssHal != nullptr) {
- Return<bool> result = false;
- sp<IGnssCallback_V2_1> gnssCbIface = new GnssCallback();
- if (gnssHal_V2_1 != nullptr) {
- result = gnssHal_V2_1->setCallback_2_1(gnssCbIface);
- } else if (gnssHal_V2_0 != nullptr) {
- result = gnssHal_V2_0->setCallback_2_0(gnssCbIface);
- } else if (gnssHal_V1_1 != nullptr) {
- result = gnssHal_V1_1->setCallback_1_1(gnssCbIface);
- } else {
- result = gnssHal->setCallback(gnssCbIface);
- }
- if (!checkHidlReturn(result, "IGnss setCallback() failed.")) {
- return JNI_FALSE;
- }
- }
+ // Set top level IGnss HAL callback.
+ gnssHal->setCallback();
- if (gnssHalAidl != nullptr) {
- sp<IGnssCallbackAidl> gnssCbIfaceAidl = new GnssCallbackAidl();
- auto status = gnssHalAidl->setCallback(gnssCbIfaceAidl);
- if (!checkAidlStatus(status, "IGnssAidl setCallback() failed.")) {
- return JNI_FALSE;
- }
- }
-
- // Set IGnssPsds or IGnssXtra callback.
- if (gnssPsdsAidlIface != nullptr) {
- sp<IGnssPsdsCallbackAidl> gnssPsdsCallbackAidl = new GnssPsdsCallbackAidl();
- auto status = gnssPsdsAidlIface->setCallback(gnssPsdsCallbackAidl);
- if (!checkAidlStatus(status, "IGnssPsdsAidl setCallback() failed.")) {
- gnssPsdsAidlIface = nullptr;
- }
- } else if (gnssXtraIface != nullptr) {
- sp<IGnssXtraCallback> gnssXtraCbIface = new GnssXtraCallback();
- auto result = gnssXtraIface->setCallback(gnssXtraCbIface);
- if (!checkHidlReturn(result, "IGnssXtra setCallback() failed.")) {
- gnssXtraIface = nullptr;
- } else {
- ALOGI("Unable to initialize IGnssXtra interface.");
- }
+ // Set IGnssPsds callback.
+ if (gnssPsdsIface == nullptr ||
+ !gnssPsdsIface->setCallback(std::make_unique<gnss::GnssPsdsCallback>())) {
+ ALOGI("Unable to initialize IGnssPsds interface.");
}
// Set IAGnss callback.
@@ -1373,145 +420,47 @@
}
static void android_location_gnss_hal_GnssNative_cleanup(JNIEnv* /* env */, jclass) {
- if (gnssHalAidl != nullptr) {
- auto status = gnssHalAidl->close();
- checkAidlStatus(status, "IGnssAidl close() failed.");
- }
-
- if (gnssHal != nullptr) {
- auto result = gnssHal->cleanup();
- checkHidlReturn(result, "IGnss cleanup() failed.");
- }
+ gnssHal->close();
}
static jboolean android_location_gnss_hal_GnssNative_set_position_mode(
JNIEnv* /* env */, jclass, jint mode, jint recurrence, jint min_interval,
jint preferred_accuracy, jint preferred_time, jboolean low_power_mode) {
- if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
- IGnssAidl::PositionModeOptions options;
- options.mode = static_cast<IGnssAidl::GnssPositionMode>(mode);
- options.recurrence = static_cast<IGnssAidl::GnssPositionRecurrence>(recurrence);
- options.minIntervalMs = min_interval;
- options.preferredAccuracyMeters = preferred_accuracy;
- options.preferredTimeMs = preferred_time;
- options.lowPowerMode = low_power_mode;
- auto status = gnssHalAidl->setPositionMode(options);
- return checkAidlStatus(status, "IGnssAidl setPositionMode() failed.");
- }
-
- Return<bool> result = false;
- if (gnssHal_V1_1 != nullptr) {
- result = gnssHal_V1_1->setPositionMode_1_1(static_cast<IGnss_V1_0::GnssPositionMode>(mode),
- static_cast<IGnss_V1_0::GnssPositionRecurrence>(recurrence),
- min_interval,
- preferred_accuracy,
- preferred_time,
- low_power_mode);
- } else if (gnssHal != nullptr) {
- result = gnssHal->setPositionMode(static_cast<IGnss_V1_0::GnssPositionMode>(mode),
- static_cast<IGnss_V1_0::GnssPositionRecurrence>(recurrence),
- min_interval,
- preferred_accuracy,
- preferred_time);
- }
-
- return checkHidlReturn(result, "IGnss setPositionMode() failed.");
+ return gnssHal->setPositionMode(mode, recurrence, min_interval, preferred_accuracy,
+ preferred_time, low_power_mode);
}
static jboolean android_location_gnss_hal_GnssNative_start(JNIEnv* /* env */, jclass) {
- if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
- auto status = gnssHalAidl->start();
- return checkAidlStatus(status, "IGnssAidl start() failed.");
- }
-
- if (gnssHal == nullptr) {
- return JNI_FALSE;
- }
-
- auto result = gnssHal->start();
- return checkHidlReturn(result, "IGnss start() failed.");
+ return gnssHal->start();
}
static jboolean android_location_gnss_hal_GnssNative_stop(JNIEnv* /* env */, jclass) {
- if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
- auto status = gnssHalAidl->stop();
- return checkAidlStatus(status, "IGnssAidl stop() failed.");
- }
-
- if (gnssHal == nullptr) {
- return JNI_FALSE;
- }
-
- auto result = gnssHal->stop();
- return checkHidlReturn(result, "IGnss stop() failed.");
+ return gnssHal->stop();
}
static jboolean android_location_gnss_hal_GnssNative_start_sv_status_collection(JNIEnv* /* env */,
jclass) {
- isSvStatusRegistered = true;
- if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
- auto status = gnssHalAidl->startSvStatus();
- return checkAidlStatus(status, "IGnssAidl startSvStatus() failed.");
- }
- if (gnssHal == nullptr) {
- return JNI_FALSE;
- }
- return JNI_TRUE;
+ return gnssHal->startSvStatus();
}
static jboolean android_location_gnss_hal_GnssNative_stop_sv_status_collection(JNIEnv* /* env */,
jclass) {
- isSvStatusRegistered = false;
- if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
- auto status = gnssHalAidl->stopSvStatus();
- return checkAidlStatus(status, "IGnssAidl stopSvStatus() failed.");
- }
- if (gnssHal == nullptr) {
- return JNI_FALSE;
- }
- return JNI_TRUE;
+ return gnssHal->stopSvStatus();
}
static jboolean android_location_gnss_hal_GnssNative_start_nmea_message_collection(
JNIEnv* /* env */, jclass) {
- isNmeaRegistered = true;
- if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
- auto status = gnssHalAidl->startNmea();
- return checkAidlStatus(status, "IGnssAidl startNmea() failed.");
- }
- if (gnssHal == nullptr) {
- return JNI_FALSE;
- }
- return JNI_TRUE;
+ return gnssHal->startNmea();
}
static jboolean android_location_gnss_hal_GnssNative_stop_nmea_message_collection(JNIEnv* /* env */,
jclass) {
- isNmeaRegistered = false;
- if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
- auto status = gnssHalAidl->stopNmea();
- return checkAidlStatus(status, "IGnssAidl stopNmea() failed.");
- }
- if (gnssHal == nullptr) {
- return JNI_FALSE;
- }
- return JNI_TRUE;
+ return gnssHal->stopNmea();
}
static void android_location_gnss_hal_GnssNative_delete_aiding_data(JNIEnv* /* env */, jclass,
jint flags) {
- if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
- auto status = gnssHalAidl->deleteAidingData(static_cast<IGnssAidl::GnssAidingData>(flags));
- checkAidlStatus(status, "IGnssAidl deleteAidingData() failed.");
- return;
- }
-
- if (gnssHal == nullptr) {
- return;
- }
-
- auto result = gnssHal->deleteAidingData(static_cast<IGnss_V1_0::GnssAidingData>(flags));
- checkHidlReturn(result, "IGnss deleteAidingData() failed.");
+ gnssHal->deleteAidingData(flags);
}
static void android_location_gnss_hal_GnssNative_agps_set_reference_location_cellid(
@@ -1535,30 +484,13 @@
static jint android_location_gnss_hal_GnssNative_read_nmea(JNIEnv* env, jclass,
jbyteArray nmeaArray, jint buffer_size) {
- // this should only be called from within a call to reportNmea
- jbyte* nmea = reinterpret_cast<jbyte *>(env->GetPrimitiveArrayCritical(nmeaArray, 0));
- int length = GnssCallback::sNmeaStringLength;
- if (length > buffer_size)
- length = buffer_size;
- memcpy(nmea, GnssCallback::sNmeaString, length);
- env->ReleasePrimitiveArrayCritical(nmeaArray, nmea, JNI_ABORT);
- return (jint) length;
+ return gnssHal->readNmea(nmeaArray, buffer_size);
}
static void android_location_gnss_hal_GnssNative_inject_time(JNIEnv* /* env */, jclass, jlong time,
jlong timeReference,
jint uncertainty) {
- if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
- auto status = gnssHalAidl->injectTime(time, timeReference, uncertainty);
- checkAidlStatus(status, "IGnssAidl injectTime() failed.");
- return;
- }
-
- if (gnssHal == nullptr) {
- return;
- }
- auto result = gnssHal->injectTime(time, timeReference, uncertainty);
- checkHidlReturn(result, "IGnss injectTime() failed.");
+ gnssHal->injectTime(time, timeReference, uncertainty);
}
static void android_location_gnss_hal_GnssNative_inject_best_location(
@@ -1568,58 +500,12 @@
jfloat speedAccuracyMetersPerSecond, jfloat bearingAccuracyDegrees, jlong timestamp,
jint elapsedRealtimeFlags, jlong elapsedRealtimeNanos,
jdouble elapsedRealtimeUncertaintyNanos) {
- if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
- GnssLocationAidl location =
- createGnssLocation(gnssLocationFlags, latitudeDegrees, longitudeDegrees,
- altitudeMeters, speedMetersPerSec, bearingDegrees,
- horizontalAccuracyMeters, verticalAccuracyMeters,
- speedAccuracyMetersPerSecond, bearingAccuracyDegrees, timestamp,
- elapsedRealtimeFlags, elapsedRealtimeNanos,
- elapsedRealtimeUncertaintyNanos);
- auto status = gnssHalAidl->injectBestLocation(location);
- checkAidlStatus(status, "IGnssAidl injectBestLocation() failed.");
- return;
- }
-
- if (gnssHal_V2_0 != nullptr) {
- GnssLocation_V2_0 location = createGnssLocation_V2_0(
- gnssLocationFlags,
- latitudeDegrees,
- longitudeDegrees,
- altitudeMeters,
- speedMetersPerSec,
- bearingDegrees,
- horizontalAccuracyMeters,
- verticalAccuracyMeters,
- speedAccuracyMetersPerSecond,
- bearingAccuracyDegrees,
- timestamp,
- elapsedRealtimeFlags,
- elapsedRealtimeNanos,
- elapsedRealtimeUncertaintyNanos);
- auto result = gnssHal_V2_0->injectBestLocation_2_0(location);
- checkHidlReturn(result, "IGnss injectBestLocation_2_0() failed.");
- return;
- }
-
- if (gnssHal_V1_1 != nullptr) {
- GnssLocation_V1_0 location = createGnssLocation_V1_0(
- gnssLocationFlags,
- latitudeDegrees,
- longitudeDegrees,
- altitudeMeters,
- speedMetersPerSec,
- bearingDegrees,
- horizontalAccuracyMeters,
- verticalAccuracyMeters,
- speedAccuracyMetersPerSecond,
- bearingAccuracyDegrees,
- timestamp);
- auto result = gnssHal_V1_1->injectBestLocation(location);
- checkHidlReturn(result, "IGnss injectBestLocation() failed.");
- }
-
- ALOGE("IGnss injectBestLocation() is called but gnssHal_V1_1 is not available.");
+ gnssHal->injectBestLocation(gnssLocationFlags, latitudeDegrees, longitudeDegrees,
+ altitudeMeters, speedMetersPerSec, bearingDegrees,
+ horizontalAccuracyMeters, verticalAccuracyMeters,
+ speedAccuracyMetersPerSecond, bearingAccuracyDegrees, timestamp,
+ elapsedRealtimeFlags, elapsedRealtimeNanos,
+ elapsedRealtimeUncertaintyNanos);
}
static void android_location_gnss_hal_GnssNative_inject_location(
@@ -1629,51 +515,25 @@
jfloat speedAccuracyMetersPerSecond, jfloat bearingAccuracyDegrees, jlong timestamp,
jint elapsedRealtimeFlags, jlong elapsedRealtimeNanos,
jdouble elapsedRealtimeUncertaintyNanos) {
- if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
- GnssLocationAidl location =
- createGnssLocation(gnssLocationFlags, latitudeDegrees, longitudeDegrees,
- altitudeMeters, speedMetersPerSec, bearingDegrees,
- horizontalAccuracyMeters, verticalAccuracyMeters,
- speedAccuracyMetersPerSecond, bearingAccuracyDegrees, timestamp,
- elapsedRealtimeFlags, elapsedRealtimeNanos,
- elapsedRealtimeUncertaintyNanos);
- auto status = gnssHalAidl->injectLocation(location);
- checkAidlStatus(status, "IGnssAidl injectLocation() failed.");
- return;
- }
-
- if (gnssHal == nullptr) {
- return;
- }
- auto result =
- gnssHal->injectLocation(latitudeDegrees, longitudeDegrees, horizontalAccuracyMeters);
- checkHidlReturn(result, "IGnss injectLocation() failed.");
+ gnssHal->injectLocation(gnssLocationFlags, latitudeDegrees, longitudeDegrees, altitudeMeters,
+ speedMetersPerSec, bearingDegrees, horizontalAccuracyMeters,
+ verticalAccuracyMeters, speedAccuracyMetersPerSecond,
+ bearingAccuracyDegrees, timestamp, elapsedRealtimeFlags,
+ elapsedRealtimeNanos, elapsedRealtimeUncertaintyNanos);
}
static jboolean android_location_gnss_hal_GnssNative_supports_psds(JNIEnv* /* env */, jclass) {
- return (gnssPsdsAidlIface != nullptr || gnssXtraIface != nullptr) ? JNI_TRUE : JNI_FALSE;
+ return (gnssPsdsIface != nullptr) ? JNI_TRUE : JNI_FALSE;
}
static void android_location_gnss_hal_GnssNative_inject_psds_data(JNIEnv* env, jclass,
jbyteArray data, jint length,
jint psdsType) {
- if (gnssPsdsAidlIface == nullptr && gnssXtraIface == nullptr) {
- ALOGE("%s: IGnssPsdsAidl or IGnssXtra interface not available.", __func__);
+ if (gnssPsdsIface == nullptr) {
+ ALOGE("%s: IGnssPsds or IGnssXtra interface not available.", __func__);
return;
}
-
- jbyte* bytes = reinterpret_cast<jbyte *>(env->GetPrimitiveArrayCritical(data, 0));
- if (gnssPsdsAidlIface != nullptr) {
- auto status = gnssPsdsAidlIface->injectPsdsData(static_cast<PsdsType>(psdsType),
- std::vector<uint8_t>((const uint8_t*)bytes,
- (const uint8_t*)bytes +
- length));
- checkAidlStatus(status, "IGnssPsdsAidl injectPsdsData() failed.");
- } else if (gnssXtraIface != nullptr) {
- auto result = gnssXtraIface->injectXtraData(std::string((const char*)bytes, length));
- checkHidlReturn(result, "IGnssXtra injectXtraData() failed.");
- }
- env->ReleasePrimitiveArrayCritical(data, bytes, JNI_ABORT);
+ gnssPsdsIface->injectPsdsData(data, length, psdsType);
}
static void android_location_GnssNetworkConnectivityHandler_agps_data_conn_open(
diff --git a/services/core/jni/gnss/Android.bp b/services/core/jni/gnss/Android.bp
index e52df15..0531ae2 100644
--- a/services/core/jni/gnss/Android.bp
+++ b/services/core/jni/gnss/Android.bp
@@ -28,6 +28,8 @@
"AGnssRil.cpp",
"AGnssRilCallback.cpp",
"GnssAntennaInfo.cpp",
+ "Gnss.cpp",
+ "GnssCallback.cpp",
"GnssAntennaInfoCallback.cpp",
"GnssBatching.cpp",
"GnssBatchingCallback.cpp",
@@ -39,6 +41,8 @@
"GnssMeasurementCallback.cpp",
"GnssNavigationMessage.cpp",
"GnssNavigationMessageCallback.cpp",
+ "GnssPsds.cpp",
+ "GnssPsdsCallback.cpp",
"GnssVisibilityControl.cpp",
"GnssVisibilityControlCallback.cpp",
"MeasurementCorrections.cpp",
@@ -55,6 +59,7 @@
"libhidlbase",
"liblog",
"libnativehelper",
+ "libhardware_legacy",
"libutils",
"android.hardware.gnss-V2-cpp",
"android.hardware.gnss@1.0",
diff --git a/services/core/jni/gnss/Gnss.cpp b/services/core/jni/gnss/Gnss.cpp
new file mode 100644
index 0000000..f6459ea
--- /dev/null
+++ b/services/core/jni/gnss/Gnss.cpp
@@ -0,0 +1,759 @@
+/*
+ * 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.
+ */
+
+// Define LOG_TAG before <log/log.h> to overwrite the default value.
+#define LOG_TAG "GnssJni"
+
+#include "Gnss.h"
+
+#include <binder/IServiceManager.h>
+
+#include "Utils.h"
+
+namespace android::gnss {
+
+using hardware::Return;
+
+using GnssLocationAidl = hardware::gnss::GnssLocation;
+using GnssLocation_V1_0 = hardware::gnss::V1_0::GnssLocation;
+using GnssLocation_V2_0 = hardware::gnss::V2_0::GnssLocation;
+using IAGnssAidl = hardware::gnss::IAGnss;
+using IAGnssRilAidl = hardware::gnss::IAGnssRil;
+using IGnssAidl = hardware::gnss::IGnss;
+using IGnss_V1_0 = hardware::gnss::V1_0::IGnss;
+using IGnss_V1_1 = hardware::gnss::V1_1::IGnss;
+using IGnss_V2_0 = hardware::gnss::V2_0::IGnss;
+using IGnss_V2_1 = hardware::gnss::V2_1::IGnss;
+using IGnssAntennaInfoAidl = hardware::gnss::IGnssAntennaInfo;
+using IGnssCallbackAidl = hardware::gnss::IGnssCallback;
+using IGnssCallback_V1_0 = hardware::gnss::V1_0::IGnssCallback;
+using IGnssCallback_V2_0 = hardware::gnss::V2_0::IGnssCallback;
+using IGnssCallback_V2_1 = hardware::gnss::V2_1::IGnssCallback;
+using IGnssConfigurationAidl = android::hardware::gnss::IGnssConfiguration;
+using IGnssDebugAidl = hardware::gnss::IGnssDebug;
+using android::hardware::gnss::IGnssPsds;
+
+namespace {
+
+GnssLocationAidl createGnssLocation(jint gnssLocationFlags, jdouble latitudeDegrees,
+ jdouble longitudeDegrees, jdouble altitudeMeters,
+ jfloat speedMetersPerSec, jfloat bearingDegrees,
+ jfloat horizontalAccuracyMeters, jfloat verticalAccuracyMeters,
+ jfloat speedAccuracyMetersPerSecond,
+ jfloat bearingAccuracyDegrees, jlong timestamp,
+ jint elapsedRealtimeFlags, jlong elapsedRealtimeNanos,
+ jdouble elapsedRealtimeUncertaintyNanos) {
+ GnssLocationAidl location;
+ location.gnssLocationFlags = static_cast<int>(gnssLocationFlags);
+ location.latitudeDegrees = static_cast<double>(latitudeDegrees);
+ location.longitudeDegrees = static_cast<double>(longitudeDegrees);
+ location.altitudeMeters = static_cast<double>(altitudeMeters);
+ location.speedMetersPerSec = static_cast<double>(speedMetersPerSec);
+ location.bearingDegrees = static_cast<double>(bearingDegrees);
+ location.horizontalAccuracyMeters = static_cast<double>(horizontalAccuracyMeters);
+ location.verticalAccuracyMeters = static_cast<double>(verticalAccuracyMeters);
+ location.speedAccuracyMetersPerSecond = static_cast<double>(speedAccuracyMetersPerSecond);
+ location.bearingAccuracyDegrees = static_cast<double>(bearingAccuracyDegrees);
+ location.timestampMillis = static_cast<uint64_t>(timestamp);
+
+ location.elapsedRealtime.flags = static_cast<int>(elapsedRealtimeFlags);
+ location.elapsedRealtime.timestampNs = static_cast<uint64_t>(elapsedRealtimeNanos);
+ location.elapsedRealtime.timeUncertaintyNs =
+ static_cast<double>(elapsedRealtimeUncertaintyNanos);
+
+ return location;
+}
+
+GnssLocation_V1_0 createGnssLocation_V1_0(jint gnssLocationFlags, jdouble latitudeDegrees,
+ jdouble longitudeDegrees, jdouble altitudeMeters,
+ jfloat speedMetersPerSec, jfloat bearingDegrees,
+ jfloat horizontalAccuracyMeters,
+ jfloat verticalAccuracyMeters,
+ jfloat speedAccuracyMetersPerSecond,
+ jfloat bearingAccuracyDegrees, jlong timestamp) {
+ GnssLocation_V1_0 location;
+ location.gnssLocationFlags = static_cast<uint16_t>(gnssLocationFlags);
+ location.latitudeDegrees = static_cast<double>(latitudeDegrees);
+ location.longitudeDegrees = static_cast<double>(longitudeDegrees);
+ location.altitudeMeters = static_cast<double>(altitudeMeters);
+ location.speedMetersPerSec = static_cast<float>(speedMetersPerSec);
+ location.bearingDegrees = static_cast<float>(bearingDegrees);
+ location.horizontalAccuracyMeters = static_cast<float>(horizontalAccuracyMeters);
+ location.verticalAccuracyMeters = static_cast<float>(verticalAccuracyMeters);
+ location.speedAccuracyMetersPerSecond = static_cast<float>(speedAccuracyMetersPerSecond);
+ location.bearingAccuracyDegrees = static_cast<float>(bearingAccuracyDegrees);
+ location.timestamp = static_cast<uint64_t>(timestamp);
+
+ return location;
+}
+
+GnssLocation_V2_0 createGnssLocation_V2_0(jint gnssLocationFlags, jdouble latitudeDegrees,
+ jdouble longitudeDegrees, jdouble altitudeMeters,
+ jfloat speedMetersPerSec, jfloat bearingDegrees,
+ jfloat horizontalAccuracyMeters,
+ jfloat verticalAccuracyMeters,
+ jfloat speedAccuracyMetersPerSecond,
+ jfloat bearingAccuracyDegrees, jlong timestamp,
+ jint elapsedRealtimeFlags, jlong elapsedRealtimeNanos,
+ jdouble elapsedRealtimeUncertaintyNanos) {
+ GnssLocation_V2_0 location;
+ location.v1_0 = createGnssLocation_V1_0(gnssLocationFlags, latitudeDegrees, longitudeDegrees,
+ altitudeMeters, speedMetersPerSec, bearingDegrees,
+ horizontalAccuracyMeters, verticalAccuracyMeters,
+ speedAccuracyMetersPerSecond, bearingAccuracyDegrees,
+ timestamp);
+
+ location.elapsedRealtime.flags = static_cast<uint16_t>(elapsedRealtimeFlags);
+ location.elapsedRealtime.timestampNs = static_cast<uint64_t>(elapsedRealtimeNanos);
+ location.elapsedRealtime.timeUncertaintyNs =
+ static_cast<uint64_t>(elapsedRealtimeUncertaintyNanos);
+
+ return location;
+}
+
+} // anonymous namespace
+
+// Implementation of GnssHal, which unifies all versions of GNSS HALs
+
+GnssHal::GnssHal() {
+ gnssHalAidl = waitForVintfService<IGnssAidl>();
+ if (gnssHalAidl != nullptr) {
+ ALOGD("Successfully got GNSS AIDL handle. Version=%d.", gnssHalAidl->getInterfaceVersion());
+ if (gnssHalAidl->getInterfaceVersion() >= 2) {
+ return;
+ }
+ }
+
+ ALOGD("Trying IGnss_V2_1::getService()");
+ gnssHal_V2_1 = IGnss_V2_1::getService();
+ if (gnssHal_V2_1 != nullptr) {
+ gnssHal_V2_0 = gnssHal_V2_1;
+ gnssHal_V1_1 = gnssHal_V2_1;
+ gnssHal = gnssHal_V2_1;
+ return;
+ }
+
+ ALOGD("gnssHal 2.1 was null, trying 2.0");
+ gnssHal_V2_0 = IGnss_V2_0::getService();
+ if (gnssHal_V2_0 != nullptr) {
+ gnssHal_V1_1 = gnssHal_V2_0;
+ gnssHal = gnssHal_V2_0;
+ return;
+ }
+
+ ALOGD("gnssHal 2.0 was null, trying 1.1");
+ gnssHal_V1_1 = IGnss_V1_1::getService();
+ if (gnssHal_V1_1 != nullptr) {
+ gnssHal = gnssHal_V1_1;
+ return;
+ }
+
+ ALOGD("gnssHal 1.1 was null, trying 1.0");
+ gnssHal = IGnss_V1_0::getService();
+}
+
+jboolean GnssHal::isSupported() {
+ return (gnssHalAidl != nullptr || gnssHal != nullptr) ? JNI_TRUE : JNI_FALSE;
+}
+
+void GnssHal::linkToDeath() {
+ // TODO: linkToDeath for AIDL HAL
+
+ if (gnssHal != nullptr) {
+ gnssHalDeathRecipient = new GnssDeathRecipient();
+ hardware::Return<bool> linked = gnssHal->linkToDeath(gnssHalDeathRecipient, /*cookie*/ 0);
+ if (!linked.isOk()) {
+ ALOGE("Transaction error in linking to GnssHAL death: %s",
+ linked.description().c_str());
+ } else if (!linked) {
+ ALOGW("Unable to link to GnssHal death notifications");
+ } else {
+ ALOGD("Link to death notification successful");
+ }
+ }
+}
+
+jboolean GnssHal::setCallback() {
+ if (gnssHalAidl != nullptr) {
+ sp<IGnssCallbackAidl> gnssCbIfaceAidl = new GnssCallbackAidl();
+ auto status = gnssHalAidl->setCallback(gnssCbIfaceAidl);
+ if (!checkAidlStatus(status, "IGnssAidl setCallback() failed.")) {
+ return JNI_FALSE;
+ }
+ }
+ if (gnssHal != nullptr) {
+ Return<bool> result = false;
+ sp<IGnssCallback_V2_1> gnssCbIface = new GnssCallbackHidl();
+ if (gnssHal_V2_1 != nullptr) {
+ result = gnssHal_V2_1->setCallback_2_1(gnssCbIface);
+ } else if (gnssHal_V2_0 != nullptr) {
+ result = gnssHal_V2_0->setCallback_2_0(gnssCbIface);
+ } else if (gnssHal_V1_1 != nullptr) {
+ result = gnssHal_V1_1->setCallback_1_1(gnssCbIface);
+ } else {
+ result = gnssHal->setCallback(gnssCbIface);
+ }
+ if (!checkHidlReturn(result, "IGnss setCallback() failed.")) {
+ return JNI_FALSE;
+ }
+ }
+ return JNI_TRUE;
+}
+
+void GnssHal::close() {
+ if (gnssHalAidl != nullptr) {
+ auto status = gnssHalAidl->close();
+ checkAidlStatus(status, "IGnssAidl close() failed.");
+ }
+
+ if (gnssHal != nullptr) {
+ auto result = gnssHal->cleanup();
+ checkHidlReturn(result, "IGnss cleanup() failed.");
+ }
+}
+
+jboolean GnssHal::start() {
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ auto status = gnssHalAidl->start();
+ return checkAidlStatus(status, "IGnssAidl start() failed.");
+ }
+
+ if (gnssHal == nullptr) {
+ return JNI_FALSE;
+ }
+
+ auto result = gnssHal->start();
+ return checkHidlReturn(result, "IGnss start() failed.");
+}
+
+jboolean GnssHal::stop() {
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ auto status = gnssHalAidl->stop();
+ return checkAidlStatus(status, "IGnssAidl stop() failed.");
+ }
+
+ if (gnssHal == nullptr) {
+ return JNI_FALSE;
+ }
+
+ auto result = gnssHal->stop();
+ return checkHidlReturn(result, "IGnss stop() failed.");
+}
+
+jboolean GnssHal::startSvStatus() {
+ isSvStatusRegistered = true;
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ auto status = gnssHalAidl->startSvStatus();
+ return checkAidlStatus(status, "IGnssAidl startSvStatus() failed.");
+ }
+ if (gnssHal == nullptr) {
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+}
+
+jboolean GnssHal::stopSvStatus() {
+ isSvStatusRegistered = false;
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ auto status = gnssHalAidl->stopSvStatus();
+ return checkAidlStatus(status, "IGnssAidl stopSvStatus() failed.");
+ }
+ if (gnssHal == nullptr) {
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+}
+
+jboolean GnssHal::startNmea() {
+ isNmeaRegistered = true;
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ auto status = gnssHalAidl->startNmea();
+ return checkAidlStatus(status, "IGnssAidl startNmea() failed.");
+ }
+ if (gnssHal == nullptr) {
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+}
+
+jboolean GnssHal::stopNmea() {
+ isNmeaRegistered = false;
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ auto status = gnssHalAidl->stopNmea();
+ return checkAidlStatus(status, "IGnssAidl stopNmea() failed.");
+ }
+ if (gnssHal == nullptr) {
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+}
+
+jint GnssHal::readNmea(jbyteArray& nmeaArray, jint& buffer_size) {
+ // this should only be called from within a call to reportNmea
+ JNIEnv* env = getJniEnv();
+ jbyte* nmea = reinterpret_cast<jbyte*>(env->GetPrimitiveArrayCritical(nmeaArray, 0));
+ int length = GnssCallbackHidl::sNmeaStringLength;
+ if (length > buffer_size) {
+ length = buffer_size;
+ }
+ memcpy(nmea, GnssCallbackHidl::sNmeaString, length);
+ env->ReleasePrimitiveArrayCritical(nmeaArray, nmea, JNI_ABORT);
+ return (jint)length;
+}
+
+jboolean GnssHal::setPositionMode(jint mode, jint recurrence, jint min_interval,
+ jint preferred_accuracy, jint preferred_time,
+ jboolean low_power_mode) {
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ IGnssAidl::PositionModeOptions options;
+ options.mode = static_cast<IGnssAidl::GnssPositionMode>(mode);
+ options.recurrence = static_cast<IGnssAidl::GnssPositionRecurrence>(recurrence);
+ options.minIntervalMs = min_interval;
+ options.preferredAccuracyMeters = preferred_accuracy;
+ options.preferredTimeMs = preferred_time;
+ options.lowPowerMode = low_power_mode;
+ auto status = gnssHalAidl->setPositionMode(options);
+ return checkAidlStatus(status, "IGnssAidl setPositionMode() failed.");
+ }
+
+ Return<bool> result = false;
+ if (gnssHal_V1_1 != nullptr) {
+ result = gnssHal_V1_1->setPositionMode_1_1(static_cast<IGnss_V1_0::GnssPositionMode>(mode),
+ static_cast<IGnss_V1_0::GnssPositionRecurrence>(
+ recurrence),
+ min_interval, preferred_accuracy, preferred_time,
+ low_power_mode);
+ } else if (gnssHal != nullptr) {
+ result = gnssHal->setPositionMode(static_cast<IGnss_V1_0::GnssPositionMode>(mode),
+ static_cast<IGnss_V1_0::GnssPositionRecurrence>(
+ recurrence),
+ min_interval, preferred_accuracy, preferred_time);
+ }
+ return checkHidlReturn(result, "IGnss setPositionMode() failed.");
+}
+
+void GnssHal::deleteAidingData(jint flags) {
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ auto status = gnssHalAidl->deleteAidingData(static_cast<IGnssAidl::GnssAidingData>(flags));
+ checkAidlStatus(status, "IGnssAidl deleteAidingData() failed.");
+ return;
+ }
+
+ if (gnssHal == nullptr) {
+ return;
+ }
+
+ auto result = gnssHal->deleteAidingData(static_cast<IGnss_V1_0::GnssAidingData>(flags));
+ checkHidlReturn(result, "IGnss deleteAidingData() failed.");
+}
+
+void GnssHal::injectTime(jlong time, jlong timeReference, jint uncertainty) {
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ auto status = gnssHalAidl->injectTime(time, timeReference, uncertainty);
+ checkAidlStatus(status, "IGnssAidl injectTime() failed.");
+ return;
+ }
+
+ if (gnssHal == nullptr) {
+ return;
+ }
+ auto result = gnssHal->injectTime(time, timeReference, uncertainty);
+ checkHidlReturn(result, "IGnss injectTime() failed.");
+}
+
+void GnssHal::injectLocation(jint gnssLocationFlags, jdouble latitudeDegrees,
+ jdouble longitudeDegrees, jdouble altitudeMeters,
+ jfloat speedMetersPerSec, jfloat bearingDegrees,
+ jfloat horizontalAccuracyMeters, jfloat verticalAccuracyMeters,
+ jfloat speedAccuracyMetersPerSecond, jfloat bearingAccuracyDegrees,
+ jlong timestamp, jint elapsedRealtimeFlags, jlong elapsedRealtimeNanos,
+ jdouble elapsedRealtimeUncertaintyNanos) {
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ GnssLocationAidl location =
+ createGnssLocation(gnssLocationFlags, latitudeDegrees, longitudeDegrees,
+ altitudeMeters, speedMetersPerSec, bearingDegrees,
+ horizontalAccuracyMeters, verticalAccuracyMeters,
+ speedAccuracyMetersPerSecond, bearingAccuracyDegrees, timestamp,
+ elapsedRealtimeFlags, elapsedRealtimeNanos,
+ elapsedRealtimeUncertaintyNanos);
+ auto status = gnssHalAidl->injectLocation(location);
+ checkAidlStatus(status, "IGnssAidl injectLocation() failed.");
+ return;
+ }
+
+ if (gnssHal == nullptr) {
+ return;
+ }
+ auto result =
+ gnssHal->injectLocation(latitudeDegrees, longitudeDegrees, horizontalAccuracyMeters);
+ checkHidlReturn(result, "IGnss injectLocation() failed.");
+}
+
+void GnssHal::injectBestLocation(jint gnssLocationFlags, jdouble latitudeDegrees,
+ jdouble longitudeDegrees, jdouble altitudeMeters,
+ jfloat speedMetersPerSec, jfloat bearingDegrees,
+ jfloat horizontalAccuracyMeters, jfloat verticalAccuracyMeters,
+ jfloat speedAccuracyMetersPerSecond, jfloat bearingAccuracyDegrees,
+ jlong timestamp, jint elapsedRealtimeFlags,
+ jlong elapsedRealtimeNanos,
+ jdouble elapsedRealtimeUncertaintyNanos) {
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ GnssLocationAidl location =
+ createGnssLocation(gnssLocationFlags, latitudeDegrees, longitudeDegrees,
+ altitudeMeters, speedMetersPerSec, bearingDegrees,
+ horizontalAccuracyMeters, verticalAccuracyMeters,
+ speedAccuracyMetersPerSecond, bearingAccuracyDegrees, timestamp,
+ elapsedRealtimeFlags, elapsedRealtimeNanos,
+ elapsedRealtimeUncertaintyNanos);
+ auto status = gnssHalAidl->injectBestLocation(location);
+ checkAidlStatus(status, "IGnssAidl injectBestLocation() failed.");
+ return;
+ }
+
+ if (gnssHal_V2_0 != nullptr) {
+ GnssLocation_V2_0 location =
+ createGnssLocation_V2_0(gnssLocationFlags, latitudeDegrees, longitudeDegrees,
+ altitudeMeters, speedMetersPerSec, bearingDegrees,
+ horizontalAccuracyMeters, verticalAccuracyMeters,
+ speedAccuracyMetersPerSecond, bearingAccuracyDegrees,
+ timestamp, elapsedRealtimeFlags, elapsedRealtimeNanos,
+ elapsedRealtimeUncertaintyNanos);
+ auto result = gnssHal_V2_0->injectBestLocation_2_0(location);
+ checkHidlReturn(result, "IGnss injectBestLocation_2_0() failed.");
+ return;
+ }
+
+ if (gnssHal_V1_1 != nullptr) {
+ GnssLocation_V1_0 location =
+ createGnssLocation_V1_0(gnssLocationFlags, latitudeDegrees, longitudeDegrees,
+ altitudeMeters, speedMetersPerSec, bearingDegrees,
+ horizontalAccuracyMeters, verticalAccuracyMeters,
+ speedAccuracyMetersPerSecond, bearingAccuracyDegrees,
+ timestamp);
+ auto result = gnssHal_V1_1->injectBestLocation(location);
+ checkHidlReturn(result, "IGnss injectBestLocation() failed.");
+ return;
+ }
+
+ ALOGE("IGnss injectBestLocation() is called but gnssHal_V1_1 is not available.");
+}
+
+std::unique_ptr<AGnssInterface> GnssHal::getAGnssInterface() {
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ sp<IAGnssAidl> agnssAidl;
+ auto status = gnssHalAidl->getExtensionAGnss(&agnssAidl);
+ if (checkAidlStatus(status, "Unable to get a handle to AGnss interface.")) {
+ return std::make_unique<gnss::AGnss>(agnssAidl);
+ }
+ } else if (gnssHal_V2_0 != nullptr) {
+ auto agnss_V2_0 = gnssHal_V2_0->getExtensionAGnss_2_0();
+ if (checkHidlReturn(agnss_V2_0, "Unable to get a handle to AGnss_V2_0")) {
+ return std::make_unique<gnss::AGnss_V2_0>(agnss_V2_0);
+ }
+ } else if (gnssHal != nullptr) {
+ auto agnss_V1_0 = gnssHal->getExtensionAGnss();
+ if (checkHidlReturn(agnss_V1_0, "Unable to get a handle to AGnss_V1_0")) {
+ return std::make_unique<gnss::AGnss_V1_0>(agnss_V1_0);
+ }
+ }
+ return nullptr;
+}
+
+std::unique_ptr<AGnssRilInterface> GnssHal::getAGnssRilInterface() {
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ sp<IAGnssRilAidl> agnssRilAidl;
+ auto status = gnssHalAidl->getExtensionAGnssRil(&agnssRilAidl);
+ if (checkAidlStatus(status, "Unable to get a handle to AGnssRil interface.")) {
+ return std::make_unique<gnss::AGnssRil>(agnssRilAidl);
+ }
+ } else if (gnssHal_V2_0 != nullptr) {
+ auto agnssRil_V2_0 = gnssHal_V2_0->getExtensionAGnssRil_2_0();
+ if (checkHidlReturn(agnssRil_V2_0, "Unable to get a handle to AGnssRil_V2_0")) {
+ return std::make_unique<gnss::AGnssRil_V2_0>(agnssRil_V2_0);
+ }
+ } else if (gnssHal != nullptr) {
+ auto agnssRil_V1_0 = gnssHal->getExtensionAGnssRil();
+ if (checkHidlReturn(agnssRil_V1_0, "Unable to get a handle to AGnssRil_V1_0")) {
+ return std::make_unique<gnss::AGnssRil_V1_0>(agnssRil_V1_0);
+ }
+ }
+ return nullptr;
+}
+
+std::unique_ptr<GnssNavigationMessageInterface> GnssHal::getGnssNavigationMessageInterface() {
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ sp<hardware::gnss::IGnssNavigationMessageInterface> gnssNavigationMessage;
+ auto status = gnssHalAidl->getExtensionGnssNavigationMessage(&gnssNavigationMessage);
+ if (checkAidlStatus(status,
+ "Unable to get a handle to GnssNavigationMessage AIDL interface.")) {
+ return std::make_unique<gnss::GnssNavigationMessageAidl>(gnssNavigationMessage);
+ }
+ } else if (gnssHal != nullptr) {
+ auto gnssNavigationMessage = gnssHal->getExtensionGnssNavigationMessage();
+ if (checkHidlReturn(gnssNavigationMessage,
+ "Unable to get a handle to GnssNavigationMessage interface.")) {
+ return std::make_unique<gnss::GnssNavigationMessageHidl>(gnssNavigationMessage);
+ }
+ }
+ return nullptr;
+}
+
+std::unique_ptr<GnssMeasurementInterface> GnssHal::getGnssMeasurementInterface() {
+ // Allow all causal combinations between IGnss.hal and IGnssMeasurement.hal. That means,
+ // 2.1@IGnss can be paired with {1.0, 1,1, 2.0, 2.1}@IGnssMeasurement
+ // 2.0@IGnss can be paired with {1.0, 1,1, 2.0}@IGnssMeasurement
+ // 1.1@IGnss can be paired {1.0, 1.1}@IGnssMeasurement
+ // 1.0@IGnss is paired with 1.0@IGnssMeasurement
+ if (gnssHalAidl != nullptr) {
+ sp<hardware::gnss::IGnssMeasurementInterface> gnssMeasurement;
+ auto status = gnssHalAidl->getExtensionGnssMeasurement(&gnssMeasurement);
+ if (checkAidlStatus(status, "Unable to get a handle to GnssMeasurement AIDL interface.")) {
+ return std::make_unique<android::gnss::GnssMeasurement>(gnssMeasurement);
+ }
+ }
+ if (gnssHal_V2_1 != nullptr) {
+ auto gnssMeasurement = gnssHal_V2_1->getExtensionGnssMeasurement_2_1();
+ if (checkHidlReturn(gnssMeasurement, "Unable to get a handle to GnssMeasurement_V2_1")) {
+ return std::make_unique<android::gnss::GnssMeasurement_V2_1>(gnssMeasurement);
+ }
+ }
+ if (gnssHal_V2_0 != nullptr) {
+ auto gnssMeasurement = gnssHal_V2_0->getExtensionGnssMeasurement_2_0();
+ if (checkHidlReturn(gnssMeasurement, "Unable to get a handle to GnssMeasurement_V2_0")) {
+ return std::make_unique<android::gnss::GnssMeasurement_V2_0>(gnssMeasurement);
+ }
+ }
+ if (gnssHal_V1_1 != nullptr) {
+ auto gnssMeasurement = gnssHal_V1_1->getExtensionGnssMeasurement_1_1();
+ if (checkHidlReturn(gnssMeasurement, "Unable to get a handle to GnssMeasurement_V1_1")) {
+ return std::make_unique<android::gnss::GnssMeasurement_V1_1>(gnssMeasurement);
+ }
+ }
+ if (gnssHal != nullptr) {
+ auto gnssMeasurement = gnssHal->getExtensionGnssMeasurement();
+ if (checkHidlReturn(gnssMeasurement, "Unable to get a handle to GnssMeasurement_V1_0")) {
+ return std::make_unique<android::gnss::GnssMeasurement_V1_0>(gnssMeasurement);
+ }
+ }
+ return nullptr;
+}
+
+std::unique_ptr<GnssDebugInterface> GnssHal::getGnssDebugInterface() {
+ // Allow all causal combinations between IGnss.hal and IGnssDebug.hal. That means,
+ // 2.0@IGnss can be paired with {1.0, 2.0}@IGnssDebug
+ // 1.0@IGnss is paired with 1.0@IGnssDebug
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ sp<IGnssDebugAidl> gnssDebugAidl;
+ auto status = gnssHalAidl->getExtensionGnssDebug(&gnssDebugAidl);
+ if (checkAidlStatus(status, "Unable to get a handle to GnssDebug interface.")) {
+ return std::make_unique<gnss::GnssDebug>(gnssDebugAidl);
+ }
+ }
+ if (gnssHal_V2_0 != nullptr) {
+ auto gnssDebug_V2_0 = gnssHal_V2_0->getExtensionGnssDebug_2_0();
+ if (checkHidlReturn(gnssDebug_V2_0, "Unable to get a handle to GnssDebug_V2_0.")) {
+ return std::make_unique<gnss::GnssDebug_V2_0>(gnssDebug_V2_0);
+ }
+ }
+ if (gnssHal != nullptr) {
+ auto gnssDebug_V1_0 = gnssHal->getExtensionGnssDebug();
+ if (checkHidlReturn(gnssDebug_V1_0, "Unable to get a handle to GnssDebug_V1_0.")) {
+ return std::make_unique<gnss::GnssDebug_V1_0>(gnssDebug_V1_0);
+ }
+ }
+ return nullptr;
+}
+
+std::unique_ptr<GnssConfigurationInterface> GnssHal::getGnssConfigurationInterface() {
+ if (gnssHalAidl != nullptr) {
+ sp<IGnssConfigurationAidl> gnssConfigurationAidl;
+ auto status = gnssHalAidl->getExtensionGnssConfiguration(&gnssConfigurationAidl);
+ if (checkAidlStatus(status,
+ "Unable to get a handle to GnssConfiguration AIDL interface.")) {
+ return std::make_unique<android::gnss::GnssConfiguration>(gnssConfigurationAidl);
+ }
+ } else if (gnssHal_V2_1 != nullptr) {
+ auto gnssConfiguration = gnssHal_V2_1->getExtensionGnssConfiguration_2_1();
+ if (checkHidlReturn(gnssConfiguration,
+ "Unable to get a handle to GnssConfiguration_V2_1")) {
+ return std::make_unique<android::gnss::GnssConfiguration_V2_1>(gnssConfiguration);
+ }
+ } else if (gnssHal_V2_0 != nullptr) {
+ auto gnssConfiguration = gnssHal_V2_0->getExtensionGnssConfiguration_2_0();
+ if (checkHidlReturn(gnssConfiguration,
+ "Unable to get a handle to GnssConfiguration_V2_0")) {
+ return std::make_unique<android::gnss::GnssConfiguration_V2_0>(gnssConfiguration);
+ }
+ } else if (gnssHal_V1_1 != nullptr) {
+ auto gnssConfiguration = gnssHal_V1_1->getExtensionGnssConfiguration_1_1();
+ if (checkHidlReturn(gnssConfiguration,
+ "Unable to get a handle to GnssConfiguration_V1_1")) {
+ return std::make_unique<gnss::GnssConfiguration_V1_1>(gnssConfiguration);
+ }
+ } else if (gnssHal != nullptr) {
+ auto gnssConfiguration = gnssHal->getExtensionGnssConfiguration();
+ if (checkHidlReturn(gnssConfiguration,
+ "Unable to get a handle to GnssConfiguration_V1_0")) {
+ return std::make_unique<gnss::GnssConfiguration_V1_0>(gnssConfiguration);
+ }
+ }
+ return nullptr;
+}
+
+std::unique_ptr<GnssGeofenceInterface> GnssHal::getGnssGeofenceInterface() {
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ sp<hardware::gnss::IGnssGeofence> gnssGeofence;
+ auto status = gnssHalAidl->getExtensionGnssGeofence(&gnssGeofence);
+ if (checkAidlStatus(status, "Unable to get a handle to GnssGeofence AIDL interface.")) {
+ return std::make_unique<gnss::GnssGeofenceAidl>(gnssGeofence);
+ }
+ } else if (gnssHal != nullptr) {
+ auto gnssGeofencing = gnssHal->getExtensionGnssGeofencing();
+ if (checkHidlReturn(gnssGeofencing, "Unable to get a handle to GnssGeofencing")) {
+ return std::make_unique<gnss::GnssGeofenceHidl>(gnssGeofencing);
+ }
+ }
+ return nullptr;
+}
+
+std::unique_ptr<GnssBatchingInterface> GnssHal::getGnssBatchingInterface() {
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ sp<android::hardware::gnss::IGnssBatching> gnssBatchingAidl;
+ auto status = gnssHalAidl->getExtensionGnssBatching(&gnssBatchingAidl);
+ if (checkAidlStatus(status, "Unable to get a handle to GnssBatching interface.")) {
+ return std::make_unique<gnss::GnssBatching>(gnssBatchingAidl);
+ }
+ }
+ if (gnssHal_V2_0 != nullptr) {
+ auto gnssBatching_V2_0 = gnssHal_V2_0->getExtensionGnssBatching_2_0();
+ if (checkHidlReturn(gnssBatching_V2_0, "Unable to get a handle to GnssBatching_V2_0")) {
+ return std::make_unique<gnss::GnssBatching_V2_0>(gnssBatching_V2_0);
+ }
+ }
+ if (gnssHal != nullptr) {
+ auto gnssBatching_V1_0 = gnssHal->getExtensionGnssBatching();
+ if (checkHidlReturn(gnssBatching_V1_0, "Unable to get a handle to GnssBatching")) {
+ return std::make_unique<gnss::GnssBatching_V1_0>(gnssBatching_V1_0);
+ }
+ }
+ return nullptr;
+}
+
+std::unique_ptr<MeasurementCorrectionsInterface> GnssHal::getMeasurementCorrectionsInterface() {
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ sp<android::hardware::gnss::measurement_corrections::IMeasurementCorrectionsInterface>
+ gnssMeasurementCorrectionsAidl;
+ auto status =
+ gnssHalAidl->getExtensionMeasurementCorrections(&gnssMeasurementCorrectionsAidl);
+ if (checkAidlStatus(status,
+ "Unable to get a handle to GnssVisibilityControl AIDL interface.")) {
+ return std::make_unique<gnss::MeasurementCorrectionsIface_Aidl>(
+ gnssMeasurementCorrectionsAidl);
+ }
+ }
+ if (gnssHal_V2_1 != nullptr) {
+ auto gnssCorrections = gnssHal_V2_1->getExtensionMeasurementCorrections_1_1();
+ if (checkHidlReturn(gnssCorrections,
+ "Unable to get a handle to GnssMeasurementCorrections HIDL "
+ "interface")) {
+ return std::make_unique<gnss::MeasurementCorrectionsIface_V1_1>(gnssCorrections);
+ }
+ }
+ if (gnssHal_V2_0 != nullptr) {
+ auto gnssCorrections = gnssHal_V2_0->getExtensionMeasurementCorrections();
+ if (checkHidlReturn(gnssCorrections,
+ "Unable to get a handle to GnssMeasurementCorrections HIDL "
+ "interface")) {
+ return std::make_unique<gnss::MeasurementCorrectionsIface_V1_0>(gnssCorrections);
+ }
+ }
+ return nullptr;
+}
+
+std::unique_ptr<GnssVisibilityControlInterface> GnssHal::getGnssVisibilityControlInterface() {
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ sp<android::hardware::gnss::visibility_control::IGnssVisibilityControl>
+ gnssVisibilityControlAidl;
+ auto status = gnssHalAidl->getExtensionGnssVisibilityControl(&gnssVisibilityControlAidl);
+ if (checkAidlStatus(status,
+ "Unable to get a handle to GnssVisibilityControl AIDL interface.")) {
+ return std::make_unique<gnss::GnssVisibilityControlAidl>(gnssVisibilityControlAidl);
+ }
+ } else if (gnssHal_V2_0 != nullptr) {
+ auto gnssVisibilityControlHidl = gnssHal_V2_0->getExtensionVisibilityControl();
+ if (checkHidlReturn(gnssVisibilityControlHidl,
+ "Unable to get a handle to GnssVisibilityControl HIDL interface")) {
+ return std::make_unique<gnss::GnssVisibilityControlHidl>(gnssVisibilityControlHidl);
+ }
+ }
+ return nullptr;
+}
+
+std::unique_ptr<GnssAntennaInfoInterface> GnssHal::getGnssAntennaInfoInterface() {
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ sp<IGnssAntennaInfoAidl> gnssAntennaInfoAidl;
+ auto status = gnssHalAidl->getExtensionGnssAntennaInfo(&gnssAntennaInfoAidl);
+ if (checkAidlStatus(status, "Unable to get a handle to GnssAntennaInfo interface.")) {
+ return std::make_unique<gnss::GnssAntennaInfoAidl>(gnssAntennaInfoAidl);
+ }
+ } else if (gnssHal_V2_1 != nullptr) {
+ auto gnssAntennaInfo_V2_1 = gnssHal_V2_1->getExtensionGnssAntennaInfo();
+ if (checkHidlReturn(gnssAntennaInfo_V2_1,
+ "Unable to get a handle to GnssAntennaInfo_V2_1")) {
+ return std::make_unique<gnss::GnssAntennaInfo_V2_1>(gnssAntennaInfo_V2_1);
+ }
+ }
+ return nullptr;
+}
+
+std::unique_ptr<GnssPsdsInterface> GnssHal::getGnssPsdsInterface() {
+ if (gnssHalAidl != nullptr) {
+ sp<IGnssPsds> gnssPsdsAidl;
+ auto status = gnssHalAidl->getExtensionPsds(&gnssPsdsAidl);
+ if (checkAidlStatus(status, "Unable to get a handle to PSDS interface.")) {
+ return std::make_unique<gnss::GnssPsdsAidl>(gnssPsdsAidl);
+ }
+ } else if (gnssHal != nullptr) {
+ auto gnssXtra = gnssHal->getExtensionXtra();
+ if (checkHidlReturn(gnssXtra, "Unable to get a handle to XTRA interface.")) {
+ return std::make_unique<gnss::GnssPsdsHidl>(gnssXtra);
+ }
+ }
+ return nullptr;
+}
+
+sp<hardware::gnss::IGnssPowerIndication> GnssHal::getGnssPowerIndicationInterface() {
+ if (gnssHalAidl != nullptr) {
+ sp<hardware::gnss::IGnssPowerIndication> gnssPowerIndication;
+ auto status = gnssHalAidl->getExtensionGnssPowerIndication(&gnssPowerIndication);
+ if (checkAidlStatus(status, "Unable to get a handle to GnssPowerIndication")) {
+ return gnssPowerIndication;
+ }
+ }
+ return nullptr;
+}
+
+sp<hardware::gnss::V1_0::IGnssNi> GnssHal::getGnssNiInterface() {
+ if (gnssHal != nullptr) {
+ auto gnssNi = gnssHal->getExtensionGnssNi();
+ if (checkHidlReturn(gnssNi, "Unable to get a handle to GnssNi")) {
+ return gnssNi;
+ }
+ }
+ return nullptr;
+}
+
+} // namespace android::gnss
diff --git a/services/core/jni/gnss/Gnss.h b/services/core/jni/gnss/Gnss.h
new file mode 100644
index 0000000..c6743d6
--- /dev/null
+++ b/services/core/jni/gnss/Gnss.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ANDROID_SERVER_GNSS_GNSS_H
+#define _ANDROID_SERVER_GNSS_GNSS_H
+
+#pragma once
+
+#ifndef LOG_TAG
+#error LOG_TAG must be defined before including this file.
+#endif
+
+#include <android/hardware/gnss/1.0/IGnss.h>
+#include <android/hardware/gnss/1.1/IGnss.h>
+#include <android/hardware/gnss/2.0/IGnss.h>
+#include <android/hardware/gnss/2.1/IGnss.h>
+#include <android/hardware/gnss/BnGnss.h>
+#include <log/log.h>
+
+#include "AGnss.h"
+#include "AGnssRil.h"
+#include "GnssAntennaInfo.h"
+#include "GnssBatching.h"
+#include "GnssCallback.h"
+#include "GnssConfiguration.h"
+#include "GnssDebug.h"
+#include "GnssGeofence.h"
+#include "GnssMeasurement.h"
+#include "GnssNavigationMessage.h"
+#include "GnssPsds.h"
+#include "GnssVisibilityControl.h"
+#include "MeasurementCorrections.h"
+#include "jni.h"
+
+namespace android::gnss {
+
+struct GnssDeathRecipient : virtual public hardware::hidl_death_recipient {
+ // hidl_death_recipient interface
+ virtual void serviceDied(uint64_t cookie, const wp<hidl::base::V1_0::IBase>& who) override {
+ ALOGE("IGNSS hidl service failed, trying to recover...");
+
+ JNIEnv* env = android::AndroidRuntime::getJNIEnv();
+ env->CallVoidMethod(android::mCallbacksObj, method_reportGnssServiceDied);
+ }
+};
+
+class GnssHal {
+public:
+ GnssHal();
+ ~GnssHal() {}
+
+ jboolean isSupported();
+ jboolean setCallback();
+ jboolean start();
+ jboolean stop();
+ jboolean setPositionMode(jint mode, jint recurrence, jint min_interval, jint preferred_accuracy,
+ jint preferred_time, jboolean low_power_mode);
+ jboolean startSvStatus();
+ jboolean stopSvStatus();
+ jboolean startNmea();
+ jboolean stopNmea();
+ jint readNmea(jbyteArray& nmeaArray, jint& buffer_size);
+ void linkToDeath();
+ void close();
+ void deleteAidingData(jint flags);
+ void injectTime(jlong time, jlong timeReference, jint uncertainty);
+ void injectLocation(jint gnssLocationFlags, jdouble latitudeDegrees, jdouble longitudeDegrees,
+ jdouble altitudeMeters, jfloat speedMetersPerSec, jfloat bearingDegrees,
+ jfloat horizontalAccuracyMeters, jfloat verticalAccuracyMeters,
+ jfloat speedAccuracyMetersPerSecond, jfloat bearingAccuracyDegrees,
+ jlong timestamp, jint elapsedRealtimeFlags, jlong elapsedRealtimeNanos,
+ jdouble elapsedRealtimeUncertaintyNanos);
+ void injectBestLocation(jint gnssLocationFlags, jdouble latitudeDegrees,
+ jdouble longitudeDegrees, jdouble altitudeMeters,
+ jfloat speedMetersPerSec, jfloat bearingDegrees,
+ jfloat horizontalAccuracyMeters, jfloat verticalAccuracyMeters,
+ jfloat speedAccuracyMetersPerSecond, jfloat bearingAccuracyDegrees,
+ jlong timestamp, jint elapsedRealtimeFlags, jlong elapsedRealtimeNanos,
+ jdouble elapsedRealtimeUncertaintyNanos);
+
+ std::unique_ptr<AGnssInterface> getAGnssInterface();
+ std::unique_ptr<AGnssRilInterface> getAGnssRilInterface();
+ std::unique_ptr<GnssNavigationMessageInterface> getGnssNavigationMessageInterface();
+ std::unique_ptr<GnssMeasurementInterface> getGnssMeasurementInterface();
+ std::unique_ptr<GnssDebugInterface> getGnssDebugInterface();
+ std::unique_ptr<GnssConfigurationInterface> getGnssConfigurationInterface();
+ std::unique_ptr<GnssGeofenceInterface> getGnssGeofenceInterface();
+ std::unique_ptr<GnssBatchingInterface> getGnssBatchingInterface();
+ std::unique_ptr<MeasurementCorrectionsInterface> getMeasurementCorrectionsInterface();
+ std::unique_ptr<GnssVisibilityControlInterface> getGnssVisibilityControlInterface();
+ std::unique_ptr<GnssAntennaInfoInterface> getGnssAntennaInfoInterface();
+ std::unique_ptr<GnssPsdsInterface> getGnssPsdsInterface();
+
+ sp<hardware::gnss::IGnssPowerIndication> getGnssPowerIndicationInterface();
+ sp<hardware::gnss::V1_0::IGnssNi> getGnssNiInterface();
+
+private:
+ sp<GnssDeathRecipient> gnssHalDeathRecipient = nullptr;
+ sp<hardware::gnss::V1_0::IGnss> gnssHal = nullptr;
+ sp<hardware::gnss::V1_1::IGnss> gnssHal_V1_1 = nullptr;
+ sp<hardware::gnss::V2_0::IGnss> gnssHal_V2_0 = nullptr;
+ sp<hardware::gnss::V2_1::IGnss> gnssHal_V2_1 = nullptr;
+ sp<hardware::gnss::IGnss> gnssHalAidl = nullptr;
+};
+
+} // namespace android::gnss
+
+#endif // _ANDROID_SERVER_GNSS_Gnss_H
diff --git a/services/core/jni/gnss/GnssCallback.cpp b/services/core/jni/gnss/GnssCallback.cpp
new file mode 100644
index 0000000..b931e91
--- /dev/null
+++ b/services/core/jni/gnss/GnssCallback.cpp
@@ -0,0 +1,413 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "GnssCallbckJni"
+
+#include "GnssCallback.h"
+
+#include <hardware_legacy/power.h>
+
+#define WAKE_LOCK_NAME "GPS"
+
+namespace android::gnss {
+
+using android::hardware::gnss::V1_0::GnssLocationFlags;
+using binder::Status;
+using hardware::hidl_vec;
+using hardware::Return;
+using hardware::Void;
+
+using GnssLocationAidl = android::hardware::gnss::GnssLocation;
+using GnssLocation_V1_0 = android::hardware::gnss::V1_0::GnssLocation;
+using GnssLocation_V2_0 = android::hardware::gnss::V2_0::GnssLocation;
+using IGnssCallbackAidl = android::hardware::gnss::IGnssCallback;
+using IGnssCallback_V1_0 = android::hardware::gnss::V1_0::IGnssCallback;
+using IGnssCallback_V2_0 = android::hardware::gnss::V2_0::IGnssCallback;
+using IGnssCallback_V2_1 = android::hardware::gnss::V2_1::IGnssCallback;
+
+jmethodID method_reportGnssServiceDied;
+
+namespace {
+
+jmethodID method_reportLocation;
+jmethodID method_reportStatus;
+jmethodID method_reportSvStatus;
+jmethodID method_reportNmea;
+jmethodID method_setTopHalCapabilities;
+jmethodID method_setGnssYearOfHardware;
+jmethodID method_setGnssHardwareModelName;
+jmethodID method_requestLocation;
+jmethodID method_requestUtcTime;
+
+// Returns true if location has lat/long information.
+inline bool hasLatLong(const GnssLocationAidl& location) {
+ return (location.gnssLocationFlags & hardware::gnss::GnssLocation::HAS_LAT_LONG) != 0;
+}
+
+// Returns true if location has lat/long information.
+inline bool hasLatLong(const GnssLocation_V1_0& location) {
+ return (static_cast<uint32_t>(location.gnssLocationFlags) & GnssLocationFlags::HAS_LAT_LONG) !=
+ 0;
+}
+
+// Returns true if location has lat/long information.
+inline bool hasLatLong(const GnssLocation_V2_0& location) {
+ return hasLatLong(location.v1_0);
+}
+
+inline jboolean boolToJbool(bool value) {
+ return value ? JNI_TRUE : JNI_FALSE;
+}
+
+// Must match the value from GnssMeasurement.java
+const uint32_t SVID_FLAGS_HAS_BASEBAND_CN0 = (1 << 4);
+
+} // anonymous namespace
+
+bool isSvStatusRegistered = false;
+bool isNmeaRegistered = false;
+
+void Gnss_class_init_once(JNIEnv* env, jclass& clazz) {
+ method_reportLocation =
+ env->GetMethodID(clazz, "reportLocation", "(ZLandroid/location/Location;)V");
+ method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V");
+ method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "(I[I[F[F[F[F[F)V");
+ method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(J)V");
+
+ method_setTopHalCapabilities = env->GetMethodID(clazz, "setTopHalCapabilities", "(I)V");
+ method_setGnssYearOfHardware = env->GetMethodID(clazz, "setGnssYearOfHardware", "(I)V");
+ method_setGnssHardwareModelName =
+ env->GetMethodID(clazz, "setGnssHardwareModelName", "(Ljava/lang/String;)V");
+
+ method_requestLocation = env->GetMethodID(clazz, "requestLocation", "(ZZ)V");
+ method_requestUtcTime = env->GetMethodID(clazz, "requestUtcTime", "()V");
+ method_reportGnssServiceDied = env->GetMethodID(clazz, "reportGnssServiceDied", "()V");
+}
+
+Status GnssCallbackAidl::gnssSetCapabilitiesCb(const int capabilities) {
+ ALOGD("GnssCallbackAidl::%s: %du\n", __func__, capabilities);
+ JNIEnv* env = getJniEnv();
+ env->CallVoidMethod(mCallbacksObj, method_setTopHalCapabilities, capabilities);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ return Status::ok();
+}
+
+Status GnssCallbackAidl::gnssStatusCb(const GnssStatusValue status) {
+ JNIEnv* env = getJniEnv();
+ env->CallVoidMethod(mCallbacksObj, method_reportStatus, status);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ return Status::ok();
+}
+
+Status GnssCallbackAidl::gnssSvStatusCb(const std::vector<GnssSvInfo>& svInfoList) {
+ GnssCallbackHidl::gnssSvStatusCbImpl<std::vector<GnssSvInfo>, GnssSvInfo>(svInfoList);
+ return Status::ok();
+}
+
+Status GnssCallbackAidl::gnssLocationCb(const hardware::gnss::GnssLocation& location) {
+ GnssCallbackHidl::gnssLocationCbImpl<hardware::gnss::GnssLocation>(location);
+ return Status::ok();
+}
+
+Status GnssCallbackAidl::gnssNmeaCb(const int64_t timestamp, const std::string& nmea) {
+ // In AIDL v1, if no listener is registered, do not report nmea to the framework.
+ if (getInterfaceVersion() <= 1) {
+ if (!isNmeaRegistered) {
+ return Status::ok();
+ }
+ }
+ JNIEnv* env = getJniEnv();
+ /*
+ * The Java code will call back to read these values.
+ * We do this to avoid creating unnecessary String objects.
+ */
+ GnssCallbackHidl::sNmeaString = nmea.c_str();
+ GnssCallbackHidl::sNmeaStringLength = nmea.size();
+
+ env->CallVoidMethod(mCallbacksObj, method_reportNmea, timestamp);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ return Status::ok();
+}
+
+Status GnssCallbackAidl::gnssAcquireWakelockCb() {
+ acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME);
+ return Status::ok();
+}
+
+Status GnssCallbackAidl::gnssReleaseWakelockCb() {
+ release_wake_lock(WAKE_LOCK_NAME);
+ return Status::ok();
+}
+
+Status GnssCallbackAidl::gnssSetSystemInfoCb(const GnssSystemInfo& info) {
+ ALOGD("%s: yearOfHw=%d, name=%s\n", __func__, info.yearOfHw, info.name.c_str());
+ JNIEnv* env = getJniEnv();
+ env->CallVoidMethod(mCallbacksObj, method_setGnssYearOfHardware, info.yearOfHw);
+ jstring jstringName = env->NewStringUTF(info.name.c_str());
+ env->CallVoidMethod(mCallbacksObj, method_setGnssHardwareModelName, jstringName);
+ if (jstringName) {
+ env->DeleteLocalRef(jstringName);
+ }
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ return Status::ok();
+}
+
+Status GnssCallbackAidl::gnssRequestTimeCb() {
+ JNIEnv* env = getJniEnv();
+ env->CallVoidMethod(mCallbacksObj, method_requestUtcTime);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ return Status::ok();
+}
+
+Status GnssCallbackAidl::gnssRequestLocationCb(const bool independentFromGnss,
+ const bool isUserEmergency) {
+ JNIEnv* env = getJniEnv();
+ env->CallVoidMethod(mCallbacksObj, method_requestLocation, boolToJbool(independentFromGnss),
+ boolToJbool(isUserEmergency));
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ return Status::ok();
+}
+
+// Implementation of IGnssCallbackHidl
+
+Return<void> GnssCallbackHidl::gnssNameCb(const android::hardware::hidl_string& name) {
+ ALOGD("%s: name=%s\n", __func__, name.c_str());
+
+ JNIEnv* env = getJniEnv();
+ jstring jstringName = env->NewStringUTF(name.c_str());
+ env->CallVoidMethod(mCallbacksObj, method_setGnssHardwareModelName, jstringName);
+ if (jstringName) {
+ env->DeleteLocalRef(jstringName);
+ }
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+
+ return Void();
+}
+
+const char* GnssCallbackHidl::sNmeaString = nullptr;
+size_t GnssCallbackHidl::sNmeaStringLength = 0;
+
+template <class T>
+Return<void> GnssCallbackHidl::gnssLocationCbImpl(const T& location) {
+ JNIEnv* env = getJniEnv();
+
+ jobject jLocation = translateGnssLocation(env, location);
+
+ env->CallVoidMethod(mCallbacksObj, method_reportLocation, boolToJbool(hasLatLong(location)),
+ jLocation);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ env->DeleteLocalRef(jLocation);
+ return Void();
+}
+
+Return<void> GnssCallbackHidl::gnssLocationCb(const GnssLocation_V1_0& location) {
+ return gnssLocationCbImpl<GnssLocation_V1_0>(location);
+}
+
+Return<void> GnssCallbackHidl::gnssLocationCb_2_0(const GnssLocation_V2_0& location) {
+ return gnssLocationCbImpl<GnssLocation_V2_0>(location);
+}
+
+Return<void> GnssCallbackHidl::gnssStatusCb(const IGnssCallback_V2_0::GnssStatusValue status) {
+ JNIEnv* env = getJniEnv();
+ env->CallVoidMethod(mCallbacksObj, method_reportStatus, status);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ return Void();
+}
+
+template <>
+uint32_t GnssCallbackHidl::getHasBasebandCn0DbHzFlag(
+ const hidl_vec<IGnssCallback_V2_1::GnssSvInfo>& svStatus) {
+ return SVID_FLAGS_HAS_BASEBAND_CN0;
+}
+
+template <>
+uint32_t GnssCallbackHidl::getHasBasebandCn0DbHzFlag(
+ const std::vector<IGnssCallbackAidl::GnssSvInfo>& svStatus) {
+ return SVID_FLAGS_HAS_BASEBAND_CN0;
+}
+
+template <>
+double GnssCallbackHidl::getBasebandCn0DbHz(
+ const std::vector<IGnssCallbackAidl::GnssSvInfo>& svInfoList, size_t i) {
+ return svInfoList[i].basebandCN0DbHz;
+}
+
+template <>
+double GnssCallbackHidl::getBasebandCn0DbHz(
+ const hidl_vec<IGnssCallback_V2_1::GnssSvInfo>& svInfoList, size_t i) {
+ return svInfoList[i].basebandCN0DbHz;
+}
+
+template <>
+uint32_t GnssCallbackHidl::getGnssSvInfoListSize(const IGnssCallback_V1_0::GnssSvStatus& svStatus) {
+ return svStatus.numSvs;
+}
+
+template <>
+uint32_t GnssCallbackHidl::getConstellationType(const IGnssCallback_V1_0::GnssSvStatus& svStatus,
+ size_t i) {
+ return static_cast<uint32_t>(svStatus.gnssSvList.data()[i].constellation);
+}
+
+template <>
+uint32_t GnssCallbackHidl::getConstellationType(
+ const hidl_vec<IGnssCallback_V2_1::GnssSvInfo>& svInfoList, size_t i) {
+ return static_cast<uint32_t>(svInfoList[i].v2_0.constellation);
+}
+
+template <class T_list, class T_sv_info>
+Return<void> GnssCallbackHidl::gnssSvStatusCbImpl(const T_list& svStatus) {
+ // In HIDL or AIDL v1, if no listener is registered, do not report svInfoList to the framework.
+ if (!isSvStatusRegistered) {
+ return Void();
+ }
+
+ JNIEnv* env = getJniEnv();
+
+ uint32_t listSize = getGnssSvInfoListSize(svStatus);
+
+ jintArray svidWithFlagArray = env->NewIntArray(listSize);
+ jfloatArray cn0Array = env->NewFloatArray(listSize);
+ jfloatArray elevArray = env->NewFloatArray(listSize);
+ jfloatArray azimArray = env->NewFloatArray(listSize);
+ jfloatArray carrierFreqArray = env->NewFloatArray(listSize);
+ jfloatArray basebandCn0Array = env->NewFloatArray(listSize);
+
+ jint* svidWithFlags = env->GetIntArrayElements(svidWithFlagArray, 0);
+ jfloat* cn0s = env->GetFloatArrayElements(cn0Array, 0);
+ jfloat* elev = env->GetFloatArrayElements(elevArray, 0);
+ jfloat* azim = env->GetFloatArrayElements(azimArray, 0);
+ jfloat* carrierFreq = env->GetFloatArrayElements(carrierFreqArray, 0);
+ jfloat* basebandCn0s = env->GetFloatArrayElements(basebandCn0Array, 0);
+
+ /*
+ * Read GNSS SV info.
+ */
+ for (size_t i = 0; i < listSize; ++i) {
+ enum ShiftWidth : uint8_t { SVID_SHIFT_WIDTH = 12, CONSTELLATION_TYPE_SHIFT_WIDTH = 8 };
+
+ const T_sv_info& info = getGnssSvInfoOfIndex(svStatus, i);
+ svidWithFlags[i] = (info.svid << SVID_SHIFT_WIDTH) |
+ (getConstellationType(svStatus, i) << CONSTELLATION_TYPE_SHIFT_WIDTH) |
+ static_cast<uint32_t>(info.svFlag);
+ cn0s[i] = info.cN0Dbhz;
+ elev[i] = info.elevationDegrees;
+ azim[i] = info.azimuthDegrees;
+ carrierFreq[i] = info.carrierFrequencyHz;
+ svidWithFlags[i] |= getHasBasebandCn0DbHzFlag(svStatus);
+ basebandCn0s[i] = getBasebandCn0DbHz(svStatus, i);
+ }
+
+ env->ReleaseIntArrayElements(svidWithFlagArray, svidWithFlags, 0);
+ env->ReleaseFloatArrayElements(cn0Array, cn0s, 0);
+ env->ReleaseFloatArrayElements(elevArray, elev, 0);
+ env->ReleaseFloatArrayElements(azimArray, azim, 0);
+ env->ReleaseFloatArrayElements(carrierFreqArray, carrierFreq, 0);
+ env->ReleaseFloatArrayElements(basebandCn0Array, basebandCn0s, 0);
+
+ env->CallVoidMethod(mCallbacksObj, method_reportSvStatus, static_cast<jint>(listSize),
+ svidWithFlagArray, cn0Array, elevArray, azimArray, carrierFreqArray,
+ basebandCn0Array);
+
+ env->DeleteLocalRef(svidWithFlagArray);
+ env->DeleteLocalRef(cn0Array);
+ env->DeleteLocalRef(elevArray);
+ env->DeleteLocalRef(azimArray);
+ env->DeleteLocalRef(carrierFreqArray);
+ env->DeleteLocalRef(basebandCn0Array);
+
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ return Void();
+}
+
+Return<void> GnssCallbackHidl::gnssNmeaCb(int64_t timestamp,
+ const ::android::hardware::hidl_string& nmea) {
+ // In HIDL, if no listener is registered, do not report nmea to the framework.
+ if (!isNmeaRegistered) {
+ return Void();
+ }
+ JNIEnv* env = getJniEnv();
+ /*
+ * The Java code will call back to read these values.
+ * We do this to avoid creating unnecessary String objects.
+ */
+ sNmeaString = nmea.c_str();
+ sNmeaStringLength = nmea.size();
+
+ env->CallVoidMethod(mCallbacksObj, method_reportNmea, timestamp);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ return Void();
+}
+
+Return<void> GnssCallbackHidl::gnssSetCapabilitesCb(uint32_t capabilities) {
+ ALOGD("%s: %du\n", __func__, capabilities);
+
+ JNIEnv* env = getJniEnv();
+ env->CallVoidMethod(mCallbacksObj, method_setTopHalCapabilities, capabilities);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ return Void();
+}
+
+Return<void> GnssCallbackHidl::gnssSetCapabilitiesCb_2_0(uint32_t capabilities) {
+ return GnssCallbackHidl::gnssSetCapabilitesCb(capabilities);
+}
+
+Return<void> GnssCallbackHidl::gnssSetCapabilitiesCb_2_1(uint32_t capabilities) {
+ return GnssCallbackHidl::gnssSetCapabilitesCb(capabilities);
+}
+
+Return<void> GnssCallbackHidl::gnssAcquireWakelockCb() {
+ acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME);
+ return Void();
+}
+
+Return<void> GnssCallbackHidl::gnssReleaseWakelockCb() {
+ release_wake_lock(WAKE_LOCK_NAME);
+ return Void();
+}
+
+Return<void> GnssCallbackHidl::gnssRequestTimeCb() {
+ JNIEnv* env = getJniEnv();
+ env->CallVoidMethod(mCallbacksObj, method_requestUtcTime);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ return Void();
+}
+
+Return<void> GnssCallbackHidl::gnssRequestLocationCb(const bool independentFromGnss) {
+ return GnssCallbackHidl::gnssRequestLocationCb_2_0(independentFromGnss, /* isUserEmergency= */
+ false);
+}
+
+Return<void> GnssCallbackHidl::gnssRequestLocationCb_2_0(const bool independentFromGnss,
+ const bool isUserEmergency) {
+ JNIEnv* env = getJniEnv();
+ env->CallVoidMethod(mCallbacksObj, method_requestLocation, boolToJbool(independentFromGnss),
+ boolToJbool(isUserEmergency));
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ return Void();
+}
+
+Return<void> GnssCallbackHidl::gnssSetSystemInfoCb(const IGnssCallback_V2_0::GnssSystemInfo& info) {
+ ALOGD("%s: yearOfHw=%d\n", __func__, info.yearOfHw);
+
+ JNIEnv* env = getJniEnv();
+ env->CallVoidMethod(mCallbacksObj, method_setGnssYearOfHardware, info.yearOfHw);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ return Void();
+}
+
+} // namespace android::gnss
\ No newline at end of file
diff --git a/services/core/jni/gnss/GnssCallback.h b/services/core/jni/gnss/GnssCallback.h
new file mode 100644
index 0000000..a7f96fb
--- /dev/null
+++ b/services/core/jni/gnss/GnssCallback.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ANDROID_SERVER_GNSS_GNSSCALLBACK_H
+#define _ANDROID_SERVER_GNSS_GNSSCALLBACK_H
+
+#pragma once
+
+#ifndef LOG_TAG
+#error LOG_TAG must be defined before including this file.
+#endif
+
+#include <android/hardware/gnss/2.1/IGnss.h>
+#include <android/hardware/gnss/BnGnssCallback.h>
+#include <log/log.h>
+
+#include <vector>
+
+#include "Utils.h"
+#include "jni.h"
+
+namespace android::gnss {
+
+namespace {
+
+extern jmethodID method_reportLocation;
+extern jmethodID method_reportStatus;
+extern jmethodID method_reportSvStatus;
+extern jmethodID method_reportNmea;
+extern jmethodID method_setTopHalCapabilities;
+extern jmethodID method_setGnssYearOfHardware;
+extern jmethodID method_setGnssHardwareModelName;
+extern jmethodID method_requestLocation;
+extern jmethodID method_requestUtcTime;
+
+} // anonymous namespace
+
+extern bool isSvStatusRegistered;
+extern bool isNmeaRegistered;
+
+extern jmethodID method_reportGnssServiceDied;
+
+void Gnss_class_init_once(JNIEnv* env, jclass& clazz);
+
+/*
+ * GnssCallbackAidl class implements the callback methods for AIDL IGnssCallback interface.
+ */
+class GnssCallbackAidl : public hardware::gnss::BnGnssCallback {
+public:
+ binder::Status gnssSetCapabilitiesCb(const int capabilities) override;
+ binder::Status gnssStatusCb(const GnssStatusValue status) override;
+ binder::Status gnssSvStatusCb(const std::vector<GnssSvInfo>& svInfoList) override;
+ binder::Status gnssLocationCb(const hardware::gnss::GnssLocation& location) override;
+ binder::Status gnssNmeaCb(const int64_t timestamp, const std::string& nmea) override;
+ binder::Status gnssAcquireWakelockCb() override;
+ binder::Status gnssReleaseWakelockCb() override;
+ binder::Status gnssSetSystemInfoCb(const GnssSystemInfo& info) override;
+ binder::Status gnssRequestTimeCb() override;
+ binder::Status gnssRequestLocationCb(const bool independentFromGnss,
+ const bool isUserEmergency) override;
+};
+
+/*
+ * GnssCallbackHidl class implements the callback methods for HIDL IGnssCallback interface.
+ */
+struct GnssCallbackHidl : public hardware::gnss::V2_1::IGnssCallback {
+ hardware::Return<void> gnssLocationCb(
+ const hardware::gnss::V1_0::GnssLocation& location) override;
+ hardware::Return<void> gnssStatusCb(
+ const hardware::gnss::V1_0::IGnssCallback::GnssStatusValue status) override;
+ hardware::Return<void> gnssSvStatusCb(
+ const hardware::gnss::V1_0::IGnssCallback::GnssSvStatus& svStatus) override {
+ return gnssSvStatusCbImpl<hardware::gnss::V1_0::IGnssCallback::GnssSvStatus,
+ hardware::gnss::V1_0::IGnssCallback::GnssSvInfo>(svStatus);
+ }
+ hardware::Return<void> gnssNmeaCb(int64_t timestamp,
+ const hardware::hidl_string& nmea) override;
+ hardware::Return<void> gnssSetCapabilitesCb(uint32_t capabilities) override;
+ hardware::Return<void> gnssAcquireWakelockCb() override;
+ hardware::Return<void> gnssReleaseWakelockCb() override;
+ hardware::Return<void> gnssRequestTimeCb() override;
+ hardware::Return<void> gnssRequestLocationCb(const bool independentFromGnss) override;
+
+ hardware::Return<void> gnssSetSystemInfoCb(
+ const hardware::gnss::V1_0::IGnssCallback::GnssSystemInfo& info) override;
+
+ // New in 1.1
+ hardware::Return<void> gnssNameCb(const hardware::hidl_string& name) override;
+
+ // New in 2.0
+ hardware::Return<void> gnssRequestLocationCb_2_0(const bool independentFromGnss,
+ const bool isUserEmergency) override;
+ hardware::Return<void> gnssSetCapabilitiesCb_2_0(uint32_t capabilities) override;
+ hardware::Return<void> gnssLocationCb_2_0(
+ const hardware::gnss::V2_0::GnssLocation& location) override;
+ hardware::Return<void> gnssSvStatusCb_2_0(
+ const hardware::hidl_vec<hardware::gnss::V2_0::IGnssCallback::GnssSvInfo>& svInfoList)
+ override {
+ return gnssSvStatusCbImpl<
+ hardware::hidl_vec<hardware::gnss::V2_0::IGnssCallback::GnssSvInfo>,
+ hardware::gnss::V1_0::IGnssCallback::GnssSvInfo>(svInfoList);
+ }
+
+ // New in 2.1
+ hardware::Return<void> gnssSvStatusCb_2_1(
+ const hardware::hidl_vec<hardware::gnss::V2_1::IGnssCallback::GnssSvInfo>& svInfoList)
+ override {
+ return gnssSvStatusCbImpl<
+ hardware::hidl_vec<hardware::gnss::V2_1::IGnssCallback::GnssSvInfo>,
+ hardware::gnss::V1_0::IGnssCallback::GnssSvInfo>(svInfoList);
+ }
+ hardware::Return<void> gnssSetCapabilitiesCb_2_1(uint32_t capabilities) override;
+
+ // TODO: Reconsider allocation cost vs threadsafety on these statics
+ static const char* sNmeaString;
+ static size_t sNmeaStringLength;
+
+ template <class T>
+ static hardware::Return<void> gnssLocationCbImpl(const T& location);
+
+ template <class T_list, class T_sv_info>
+ static hardware::Return<void> gnssSvStatusCbImpl(const T_list& svStatus);
+
+private:
+ template <class T>
+ static uint32_t getHasBasebandCn0DbHzFlag(const T& svStatus) {
+ return 0;
+ }
+
+ template <class T>
+ static double getBasebandCn0DbHz(const T& svStatus, size_t i) {
+ return 0.0;
+ }
+
+ template <class T>
+ static uint32_t getGnssSvInfoListSize(const T& svInfoList) {
+ return svInfoList.size();
+ }
+
+ static const hardware::gnss::IGnssCallback::GnssSvInfo& getGnssSvInfoOfIndex(
+ const std::vector<hardware::gnss::IGnssCallback::GnssSvInfo>& svInfoList, size_t i) {
+ return svInfoList[i];
+ }
+
+ static const hardware::gnss::V1_0::IGnssCallback::GnssSvInfo& getGnssSvInfoOfIndex(
+ const hardware::gnss::V1_0::IGnssCallback::GnssSvStatus& svStatus, size_t i) {
+ return svStatus.gnssSvList.data()[i];
+ }
+
+ static const hardware::gnss::V1_0::IGnssCallback::GnssSvInfo& getGnssSvInfoOfIndex(
+ const hardware::hidl_vec<hardware::gnss::V2_0::IGnssCallback::GnssSvInfo>& svInfoList,
+ size_t i) {
+ return svInfoList[i].v1_0;
+ }
+
+ static const hardware::gnss::V1_0::IGnssCallback::GnssSvInfo& getGnssSvInfoOfIndex(
+ const hardware::hidl_vec<hardware::gnss::V2_1::IGnssCallback::GnssSvInfo>& svInfoList,
+ size_t i) {
+ return svInfoList[i].v2_0.v1_0;
+ }
+
+ template <class T>
+ static uint32_t getConstellationType(const T& svInfoList, size_t i) {
+ return static_cast<uint32_t>(svInfoList[i].constellation);
+ }
+};
+
+} // namespace android::gnss
+
+#endif // _ANDROID_SERVER_GNSS_GNSSCALLBACK_H
\ No newline at end of file
diff --git a/services/core/jni/gnss/GnssDebug.cpp b/services/core/jni/gnss/GnssDebug.cpp
index da53317..263a6c6 100644
--- a/services/core/jni/gnss/GnssDebug.cpp
+++ b/services/core/jni/gnss/GnssDebug.cpp
@@ -104,4 +104,10 @@
return satelliteDataArray[i];
}
+template <>
+int64_t GnssDebugUtil::getTimeEstimateMs(
+ const android::hardware::gnss::IGnssDebug::DebugData& data) {
+ return data.time.timeEstimateMs;
+}
+
} // namespace android::gnss
diff --git a/services/core/jni/gnss/GnssDebug.h b/services/core/jni/gnss/GnssDebug.h
index 1e1a7b4..e02c2ac 100644
--- a/services/core/jni/gnss/GnssDebug.h
+++ b/services/core/jni/gnss/GnssDebug.h
@@ -113,12 +113,6 @@
return data.time.timeEstimate;
}
-template <>
-int64_t GnssDebugUtil::getTimeEstimateMs(
- const android::hardware::gnss::IGnssDebug::DebugData& data) {
- return data.time.timeEstimateMs;
-}
-
template <class T_DebugData, class T_SatelliteData>
jstring GnssDebugUtil::parseDebugData(JNIEnv* env, std::stringstream& internalState,
const T_DebugData& data) {
diff --git a/services/core/jni/gnss/GnssPsds.cpp b/services/core/jni/gnss/GnssPsds.cpp
new file mode 100644
index 0000000..51a1450
--- /dev/null
+++ b/services/core/jni/gnss/GnssPsds.cpp
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+// Define LOG_TAG before <log/log.h> to overwrite the default value.
+#define LOG_TAG "GnssPsdsJni"
+
+#include "GnssPsds.h"
+
+#include "Utils.h"
+
+using android::hardware::hidl_bitfield;
+using android::hardware::gnss::PsdsType;
+using IGnssPsdsAidl = android::hardware::gnss::IGnssPsds;
+using IGnssPsdsHidl = android::hardware::gnss::V1_0::IGnssXtra;
+
+namespace android::gnss {
+
+// Implementation of GnssPsds (AIDL HAL)
+
+GnssPsdsAidl::GnssPsdsAidl(const sp<IGnssPsdsAidl>& iGnssPsds) : mIGnssPsds(iGnssPsds) {
+ assert(mIGnssPsds != nullptr);
+}
+
+jboolean GnssPsdsAidl::setCallback(const std::unique_ptr<GnssPsdsCallback>& callback) {
+ auto status = mIGnssPsds->setCallback(callback->getAidl());
+ return checkAidlStatus(status, "IGnssPsdsAidl setCallback() failed.");
+}
+
+void GnssPsdsAidl::injectPsdsData(const jbyteArray& data, const jint& length,
+ const jint& psdsType) {
+ JNIEnv* env = getJniEnv();
+ jbyte* bytes = reinterpret_cast<jbyte*>(env->GetPrimitiveArrayCritical(data, 0));
+ auto status = mIGnssPsds->injectPsdsData(static_cast<PsdsType>(psdsType),
+ std::vector<uint8_t>((const uint8_t*)bytes,
+ (const uint8_t*)bytes + length));
+ checkAidlStatus(status, "IGnssPsdsAidl injectPsdsData() failed.");
+ env->ReleasePrimitiveArrayCritical(data, bytes, JNI_ABORT);
+}
+
+// Implementation of GnssPsdsHidl
+
+GnssPsdsHidl::GnssPsdsHidl(const sp<android::hardware::gnss::V1_0::IGnssXtra>& iGnssXtra)
+ : mIGnssXtra(iGnssXtra) {
+ assert(mIGnssXtra != nullptr);
+}
+
+jboolean GnssPsdsHidl::setCallback(const std::unique_ptr<GnssPsdsCallback>& callback) {
+ auto result = mIGnssXtra->setCallback(callback->getHidl());
+ return checkHidlReturn(result, "IGnssPsdsHidl setCallback() failed.");
+}
+
+void GnssPsdsHidl::injectPsdsData(const jbyteArray& data, const jint& length, const jint&) {
+ JNIEnv* env = getJniEnv();
+ jbyte* bytes = reinterpret_cast<jbyte*>(env->GetPrimitiveArrayCritical(data, 0));
+ auto result = mIGnssXtra->injectXtraData(std::string((const char*)bytes, length));
+ checkHidlReturn(result, "IGnssXtra injectXtraData() failed.");
+ env->ReleasePrimitiveArrayCritical(data, bytes, JNI_ABORT);
+}
+
+} // namespace android::gnss
diff --git a/services/core/jni/gnss/GnssPsds.h b/services/core/jni/gnss/GnssPsds.h
new file mode 100644
index 0000000..6b65ee8
--- /dev/null
+++ b/services/core/jni/gnss/GnssPsds.h
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+#ifndef _ANDROID_SERVER_GNSS_GNSSPSDS_H
+#define _ANDROID_SERVER_GNSS_GNSSPSDS_H
+
+#pragma once
+
+#ifndef LOG_TAG
+#error LOG_TAG must be defined before including this file.
+#endif
+
+#include <android/hardware/gnss/1.0/IGnssXtra.h>
+#include <android/hardware/gnss/BnGnssPsds.h>
+#include <log/log.h>
+
+#include "GnssPsdsCallback.h"
+#include "jni.h"
+
+namespace android::gnss {
+
+class GnssPsdsInterface {
+public:
+ virtual ~GnssPsdsInterface() {}
+ virtual jboolean setCallback(const std::unique_ptr<GnssPsdsCallback>& callback);
+ virtual void injectPsdsData(const jbyteArray& data, const jint& length, const jint& psdsType);
+};
+
+class GnssPsdsAidl : public GnssPsdsInterface {
+public:
+ GnssPsdsAidl(const sp<android::hardware::gnss::IGnssPsds>& iGnssPsds);
+ jboolean setCallback(const std::unique_ptr<GnssPsdsCallback>& callback) override;
+ void injectPsdsData(const jbyteArray& data, const jint& length, const jint& psdsType) override;
+
+private:
+ const sp<android::hardware::gnss::IGnssPsds> mIGnssPsds;
+};
+
+class GnssPsdsHidl : public GnssPsdsInterface {
+public:
+ GnssPsdsHidl(const sp<android::hardware::gnss::V1_0::IGnssXtra>& iGnssXtra);
+ jboolean setCallback(const std::unique_ptr<GnssPsdsCallback>& callback) override;
+ void injectPsdsData(const jbyteArray& data, const jint& length, const jint& psdsType) override;
+
+private:
+ const sp<android::hardware::gnss::V1_0::IGnssXtra> mIGnssXtra;
+};
+
+} // namespace android::gnss
+
+#endif // _ANDROID_SERVER_GNSS_GNSSPSDS_H
diff --git a/services/core/jni/gnss/GnssPsdsCallback.cpp b/services/core/jni/gnss/GnssPsdsCallback.cpp
new file mode 100644
index 0000000..1dd7022
--- /dev/null
+++ b/services/core/jni/gnss/GnssPsdsCallback.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "GnssPsdsCbJni"
+
+#include "GnssPsdsCallback.h"
+
+#include <vector>
+
+#include "Utils.h"
+
+namespace android::gnss {
+
+namespace {
+jmethodID method_psdsDownloadRequest;
+} // anonymous namespace
+
+using binder::Status;
+using hardware::Return;
+using hardware::Void;
+using hardware::gnss::PsdsType;
+
+void GnssPsds_class_init_once(JNIEnv* env, jclass clazz) {
+ method_psdsDownloadRequest = env->GetMethodID(clazz, "psdsDownloadRequest", "(I)V");
+}
+
+// Implementation of android::hardware::gnss::IGnssPsdsCallback
+
+Status GnssPsdsCallbackAidl::downloadRequestCb(PsdsType psdsType) {
+ ALOGD("%s. psdsType: %d", __func__, static_cast<int32_t>(psdsType));
+ JNIEnv* env = getJniEnv();
+ env->CallVoidMethod(mCallbacksObj, method_psdsDownloadRequest, psdsType);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ return Status::ok();
+}
+
+// Implementation of android::hardware::gnss::V1_0::IGnssPsdsCallback
+
+Return<void> GnssPsdsCallbackHidl::downloadRequestCb() {
+ JNIEnv* env = getJniEnv();
+ env->CallVoidMethod(mCallbacksObj, method_psdsDownloadRequest, /* psdsType= */ 1);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ return Void();
+}
+
+} // namespace android::gnss
diff --git a/services/core/jni/gnss/GnssPsdsCallback.h b/services/core/jni/gnss/GnssPsdsCallback.h
new file mode 100644
index 0000000..3ac7473
--- /dev/null
+++ b/services/core/jni/gnss/GnssPsdsCallback.h
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+#ifndef _ANDROID_SERVER_GNSS_GNSSPSDSCALLBACK_H
+#define _ANDROID_SERVER_GNSS_GNSSPSDSCALLBACK_H
+
+#pragma once
+
+#ifndef LOG_TAG
+#error LOG_TAG must be defined before including this file.
+#endif
+
+#include <android/hardware/gnss/1.0/IGnssXtraCallback.h>
+#include <android/hardware/gnss/BnGnssPsdsCallback.h>
+#include <log/log.h>
+
+#include "jni.h"
+
+namespace android::gnss {
+
+namespace {
+extern jmethodID method_psdsDownloadRequest;
+} // anonymous namespace
+
+void GnssPsds_class_init_once(JNIEnv* env, jclass clazz);
+
+class GnssPsdsCallbackAidl : public hardware::gnss::BnGnssPsdsCallback {
+public:
+ GnssPsdsCallbackAidl() {}
+ binder::Status downloadRequestCb(hardware::gnss::PsdsType psdsType) override;
+};
+
+class GnssPsdsCallbackHidl : public hardware::gnss::V1_0::IGnssXtraCallback {
+public:
+ GnssPsdsCallbackHidl() {}
+ hardware::Return<void> downloadRequestCb() override;
+};
+
+class GnssPsdsCallback {
+public:
+ GnssPsdsCallback() {}
+ sp<GnssPsdsCallbackAidl> getAidl() {
+ if (callbackAidl == nullptr) {
+ callbackAidl = sp<GnssPsdsCallbackAidl>::make();
+ }
+ return callbackAidl;
+ }
+
+ sp<GnssPsdsCallbackHidl> getHidl() {
+ if (callbackHidl == nullptr) {
+ callbackHidl = sp<GnssPsdsCallbackHidl>::make();
+ }
+ return callbackHidl;
+ }
+
+private:
+ sp<GnssPsdsCallbackAidl> callbackAidl;
+ sp<GnssPsdsCallbackHidl> callbackHidl;
+};
+
+} // namespace android::gnss
+
+#endif // _ANDROID_SERVER_GNSS_GNSSPSDSCALLBACK_H
\ No newline at end of file
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 33e97aa..ef61fbf 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -45,7 +45,8 @@
import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_DEFAULT;
import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED;
import static android.app.admin.DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_PER_USER;
-import static android.app.admin.DevicePolicyManager.EXTRA_RESOURCE_ID;
+import static android.app.admin.DevicePolicyManager.EXTRA_RESOURCE_IDS;
+import static android.app.admin.DevicePolicyManager.EXTRA_RESOURCE_TYPE;
import static android.app.admin.DevicePolicyManager.EXTRA_RESOURCE_TYPE_DRAWABLE;
import static android.app.admin.DevicePolicyManager.EXTRA_RESOURCE_TYPE_STRING;
import static android.app.admin.DevicePolicyManager.ID_TYPE_BASE_INFO;
@@ -1999,9 +2000,6 @@
mOwners.load();
setDeviceOwnershipSystemPropertyLocked();
findOwnerComponentIfNecessaryLocked();
-
- // TODO PO may not have a class name either due to b/17652534. Address that too.
- updateDeviceOwnerLocked();
}
}
@@ -3142,23 +3140,6 @@
}
}
- private void updateDeviceOwnerLocked() {
- long ident = mInjector.binderClearCallingIdentity();
- try {
- // TODO This is to prevent DO from getting "clear data"ed, but it should also check the
- // user id and also protect all other DAs too.
- final ComponentName deviceOwnerComponent = mOwners.getDeviceOwnerComponent();
- if (deviceOwnerComponent != null) {
- mInjector.getIActivityManager()
- .updateDeviceOwner(deviceOwnerComponent.getPackageName());
- }
- } catch (RemoteException e) {
- // Not gonna happen.
- } finally {
- mInjector.binderRestoreCallingIdentity(ident);
- }
- }
-
static void validateQualityConstant(int quality) {
switch (quality) {
case PASSWORD_QUALITY_UNSPECIFIED:
@@ -5957,6 +5938,7 @@
* (1.1) The caller is the Device Owner
* (1.2) The caller is another app in the same user as the device owner, AND
* The caller is the delegated certificate installer.
+ * (1.3) The caller is a Profile Owner and the calling user is affiliated.
* (2) The user has a profile owner, AND:
* (2.1) The profile owner has been granted access to Device IDs and one of the following
* holds:
@@ -5982,12 +5964,14 @@
* If the caller is from the work profile, then it must be the PO or the delegate, and
* it must have the right permission to access device identifiers.
*/
- if (hasProfileOwner(caller.getUserId())) {
+ int callerUserId = caller.getUserId();
+ if (hasProfileOwner(callerUserId)) {
// Make sure that the caller is the profile owner or delegate.
Preconditions.checkCallAuthorization(canInstallCertificates(caller));
- // Verify that the managed profile is on an organization-owned device and as such
- // the profile owner can access Device IDs.
- if (isProfileOwnerOfOrganizationOwnedDevice(caller.getUserId())) {
+ // Verify that the managed profile is on an organization-owned device (or is affiliated
+ // with the device owner user) and as such the profile owner can access Device IDs.
+ if (isProfileOwnerOfOrganizationOwnedDevice(callerUserId)
+ || isUserAffiliatedWithDevice(callerUserId)) {
return;
}
throw new SecurityException(
@@ -8590,7 +8574,6 @@
mOwners.setDeviceOwner(admin, ownerName, userId);
mOwners.writeDeviceOwner();
- updateDeviceOwnerLocked();
setDeviceOwnershipSystemPropertyLocked();
//TODO(b/180371154): when provisionFullyManagedDevice is used in tests, remove this
@@ -8951,7 +8934,6 @@
mOwners.clearDeviceOwner();
mOwners.writeDeviceOwner();
- updateDeviceOwnerLocked();
clearDeviceOwnerUserRestriction(UserHandle.of(userId));
mInjector.securityLogSetLoggingEnabledProperty(false);
@@ -9492,10 +9474,11 @@
return false;
}
- // Allow access to the device owner or delegate cert installer.
+ // Allow access to the device owner or delegate cert installer or profile owner of an
+ // affiliated user
ComponentName deviceOwner = getDeviceOwnerComponent(true);
if (deviceOwner != null && (deviceOwner.getPackageName().equals(packageName)
- || isCallerDelegate(packageName, uid, DELEGATION_CERT_INSTALL))) {
+ || isCallerDelegate(packageName, uid, DELEGATION_CERT_INSTALL))) {
return true;
}
final int userId = UserHandle.getUserId(uid);
@@ -9505,7 +9488,8 @@
final boolean isCallerProfileOwnerOrDelegate = profileOwner != null
&& (profileOwner.getPackageName().equals(packageName)
|| isCallerDelegate(packageName, uid, DELEGATION_CERT_INSTALL));
- if (isCallerProfileOwnerOrDelegate && isProfileOwnerOfOrganizationOwnedDevice(userId)) {
+ if (isCallerProfileOwnerOrDelegate && (isProfileOwnerOfOrganizationOwnedDevice(userId)
+ || isUserAffiliatedWithDevice(userId))) {
return true;
}
@@ -14960,7 +14944,13 @@
final CallerIdentity caller = getCallerIdentity();
Preconditions.checkCallAuthorization(hasCrossUsersPermission(caller, userId));
- return isUserAffiliatedWithDeviceLocked(userId);
+ return isUserAffiliatedWithDevice(userId);
+ }
+
+ private boolean isUserAffiliatedWithDevice(@UserIdInt int userId) {
+ synchronized (getLockObject()) {
+ return isUserAffiliatedWithDeviceLocked(userId);
+ }
}
private boolean isUserAffiliatedWithDeviceLocked(@UserIdInt int userId) {
@@ -18714,10 +18704,10 @@
sendResourceUpdatedBroadcast(EXTRA_RESOURCE_TYPE_STRING, stringIds);
}
- private void sendResourceUpdatedBroadcast(String resourceType, String[] resourceIds) {
+ private void sendResourceUpdatedBroadcast(int resourceType, String[] resourceIds) {
final Intent intent = new Intent(ACTION_DEVICE_POLICY_RESOURCE_UPDATED);
- intent.putExtra(EXTRA_RESOURCE_ID, resourceIds);
- intent.putExtra(resourceType, /* value= */ true);
+ intent.putExtra(EXTRA_RESOURCE_IDS, resourceIds);
+ intent.putExtra(EXTRA_RESOURCE_TYPE, resourceType);
intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index e895d37..a14e14b 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -386,8 +386,8 @@
"com.android.server.DeviceIdleController";
private static final String BLOB_STORE_MANAGER_SERVICE_CLASS =
"com.android.server.blob.BlobStoreManagerService";
- private static final String APP_SEARCH_MANAGER_SERVICE_CLASS =
- "com.android.server.appsearch.AppSearchManagerService";
+ private static final String APPSEARCH_MODULE_LIFECYCLE_CLASS =
+ "com.android.server.appsearch.AppSearchModule$Lifecycle";
private static final String ISOLATED_COMPILATION_SERVICE_CLASS =
"com.android.server.compos.IsolatedCompilationService";
private static final String ROLLBACK_MANAGER_SERVICE_CLASS =
@@ -415,10 +415,12 @@
private static final String UWB_APEX_SERVICE_JAR_PATH =
"/apex/com.android.uwb/javalib/service-uwb.jar";
private static final String UWB_SERVICE_CLASS = "com.android.server.uwb.UwbService";
- private static final String SAFETY_CENTER_SERVICE_CLASS =
- "com.android.safetycenter.SafetyCenterService";
+ private static final String BLUETOOTH_APEX_SERVICE_JAR_PATH =
+ "/apex/com.android.bluetooth/javalib/service-bluetooth.jar";
private static final String BLUETOOTH_SERVICE_CLASS =
"com.android.server.bluetooth.BluetoothService";
+ private static final String SAFETY_CENTER_SERVICE_CLASS =
+ "com.android.safetycenter.SafetyCenterService";
private static final String SUPPLEMENTALPROCESS_SERVICE_CLASS =
"com.android.server.supplementalprocess.SupplementalProcessManagerService$Lifecycle";
@@ -1626,7 +1628,8 @@
Slog.i(TAG, "No Bluetooth Service (Bluetooth Hardware Not Present)");
} else {
t.traceBegin("StartBluetoothService");
- mSystemServiceManager.startService(BLUETOOTH_SERVICE_CLASS);
+ mSystemServiceManager.startServiceFromJar(BLUETOOTH_SERVICE_CLASS,
+ BLUETOOTH_APEX_SERVICE_JAR_PATH);
t.traceEnd();
}
@@ -2764,8 +2767,8 @@
mSystemServiceManager.startService(SAFETY_CENTER_SERVICE_CLASS);
t.traceEnd();
- t.traceBegin("AppSearchManagerService");
- mSystemServiceManager.startService(APP_SEARCH_MANAGER_SERVICE_CLASS);
+ t.traceBegin("AppSearchModule");
+ mSystemServiceManager.startService(APPSEARCH_MODULE_LIFECYCLE_CLASS);
t.traceEnd();
if (SystemProperties.getBoolean("ro.config.isolated_compilation_enabled", false)) {
diff --git a/services/midi/java/com/android/server/midi/MidiService.java b/services/midi/java/com/android/server/midi/MidiService.java
index 2d082e1..ca67bcb 100644
--- a/services/midi/java/com/android/server/midi/MidiService.java
+++ b/services/midi/java/com/android/server/midi/MidiService.java
@@ -50,6 +50,7 @@
import android.util.EventLog;
import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.PackageMonitor;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.IndentingPrintWriter;
@@ -136,10 +137,12 @@
private final Object mUsbMidiLock = new Object();
// Number of times a USB MIDI 1.0 device has opened, based on the device name.
+ @GuardedBy("mUsbMidiLock")
private final HashMap<String, Integer> mUsbMidiLegacyDeviceOpenCount =
new HashMap<String, Integer>();
// Whether a USB MIDI device has opened, based on the device name.
+ @GuardedBy("mUsbMidiLock")
private final HashSet<String> mUsbMidiUniversalDeviceInUse = new HashSet<String>();
// UID of BluetoothMidiService
@@ -768,7 +771,6 @@
synchronized (mDevicesByInfo) {
for (Device device : mDevicesByInfo.values()) {
if (device.isUidAllowed(uid)) {
- deviceInfos.add(device.getDeviceInfo());
// UMP devices have protocols that are not PROTOCOL_UNKNOWN
if (transport == MidiManager.TRANSPORT_UNIVERSAL_MIDI_PACKETS) {
if (device.getDeviceInfo().getDefaultProtocol()
@@ -1247,7 +1249,7 @@
pw.decreaseIndent();
}
- // hold mUsbMidiLock before calling this
+ @GuardedBy("mUsbMidiLock")
private boolean isUsbMidiDeviceInUseLocked(MidiDeviceInfo info) {
String name = info.getProperties().getString(MidiDeviceInfo.PROPERTY_NAME);
if (name.length() < MIDI_LEGACY_STRING.length()) {
@@ -1266,7 +1268,7 @@
return false;
}
- // hold mUsbMidiLock before calling this
+ @GuardedBy("mUsbMidiLock")
void addUsbMidiDeviceLocked(MidiDeviceInfo info) {
String name = info.getProperties().getString(MidiDeviceInfo.PROPERTY_NAME);
if (name.length() < MIDI_LEGACY_STRING.length()) {
@@ -1283,7 +1285,7 @@
}
}
- // hold mUsbMidiLock before calling this
+ @GuardedBy("mUsbMidiLock")
void removeUsbMidiDeviceLocked(MidiDeviceInfo info) {
String name = info.getProperties().getString(MidiDeviceInfo.PROPERTY_NAME);
if (name.length() < MIDI_LEGACY_STRING.length()) {
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
index cd2d0fc..83ccabf 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
@@ -238,6 +238,7 @@
AndroidPackage::isVendor,
AndroidPackage::isVisibleToInstantApps,
AndroidPackage::isVmSafeMode,
+ AndroidPackage::isLeavingSharedUid,
AndroidPackage::isResetEnabledSettingsOnAppDataCleared,
AndroidPackage::getMaxAspectRatio,
AndroidPackage::getMinAspectRatio,
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
index e6bb0ce..0535513 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
@@ -345,6 +345,7 @@
@After
public void tearDown() {
+ mBgRestrictionController.tearDown();
mBgRestrictionController.getBackgroundHandlerThread().quitSafely();
}
@@ -561,6 +562,7 @@
DeviceConfigSession<Float> bgCurrentDrainRestrictedBucketThreshold = null;
DeviceConfigSession<Float> bgCurrentDrainBgRestrictedThreshold = null;
DeviceConfigSession<Boolean> bgPromptFgsWithNotiToBgRestricted = null;
+ DeviceConfigSession<Long> bgNotificationMinInterval = null;
mBgRestrictionController.addAppBackgroundRestrictionListener(listener);
@@ -615,6 +617,13 @@
R.bool.config_bg_prompt_fgs_with_noti_to_bg_restricted));
bgPromptFgsWithNotiToBgRestricted.set(true);
+ bgNotificationMinInterval = new DeviceConfigSession<>(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ ConstantsObserver.KEY_BG_ABUSIVE_NOTIFICATION_MINIMAL_INTERVAL,
+ DeviceConfig::getLong,
+ ConstantsObserver.DEFAULT_BG_ABUSIVE_NOTIFICATION_MINIMAL_INTERVAL_MS);
+ bgNotificationMinInterval.set(windowMs);
+
mCurrentTimeMillis = 10_000L;
doReturn(mCurrentTimeMillis - windowMs).when(stats).getStatsStartTimestamp();
doReturn(mCurrentTimeMillis).when(stats).getStatsEndTimestamp();
@@ -754,6 +763,7 @@
// Sleep a while and set a higher drain
Thread.sleep(windowMs);
clearInvocations(mInjector.getAppStandbyInternal());
+ clearInvocations(mInjector.getNotificationManager());
clearInvocations(mBgRestrictionController);
// We're not going to prompt the user if the abusive app has a FGS with notification.
@@ -794,6 +804,7 @@
mAppFGSTracker.onForegroundServiceNotificationUpdated(
testPkgName, testUid, -notificationId);
clearInvocations(mInjector.getAppStandbyInternal());
+ clearInvocations(mInjector.getNotificationManager());
clearInvocations(mBgRestrictionController);
runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
@@ -832,6 +843,7 @@
// Now we'll prompt the user even it has a FGS with notification.
bgPromptFgsWithNotiToBgRestricted.set(true);
clearInvocations(mInjector.getAppStandbyInternal());
+ clearInvocations(mInjector.getNotificationManager());
clearInvocations(mBgRestrictionController);
runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
@@ -899,6 +911,7 @@
closeIfNotNull(bgCurrentDrainRestrictedBucketThreshold);
closeIfNotNull(bgCurrentDrainBgRestrictedThreshold);
closeIfNotNull(bgPromptFgsWithNotiToBgRestricted);
+ closeIfNotNull(bgNotificationMinInterval);
}
}
@@ -1921,6 +1934,7 @@
.checkUidPermission(uid, perm);
mInjector.getAppPermissionTracker().onPermissionsChanged(uid);
}
+ waitForIdleHandler(mBgRestrictionController.getBackgroundHandler());
runExemptionTestOnce(
packageName, uid, pid, serviceType, sleepMs, stopAfterSleep,
perm, mediaControllers, topStateChanges, resetFGSTracker, false,
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
index d2358a0..023608c 100644
--- a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
@@ -1167,7 +1167,14 @@
startUser(gameManagerService, USER_ID_1);
gameManagerService.setGameMode(
mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1);
- GameState gameState = new GameState(isLoading, GameState.MODE_NONE);
+ int testMode = GameState.MODE_NONE;
+ int testLabel = 99;
+ int testQuality = 123;
+ GameState gameState = new GameState(isLoading, testMode, testLabel, testQuality);
+ assertEquals(isLoading, gameState.isLoading());
+ assertEquals(testMode, gameState.getMode());
+ assertEquals(testLabel, gameState.getLabel());
+ assertEquals(testQuality, gameState.getQuality());
gameManagerService.setGameState(mPackageName, gameState, USER_ID_1);
mTestLooper.dispatchAll();
verify(mMockPowerManager, times(1)).setPowerMode(Mode.GAME_LOADING, isLoading);
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 a0ac506..9a4f8e2 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 @@
}
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 @@
}
}
- 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
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 @@
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 @@
// 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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
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 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
index 890a549..d8f409d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
@@ -213,7 +213,7 @@
public void testProperties() {
assertThat(mManager.getName()).isEqualTo(NAME);
assertThat(mManager.getProperties()).isEqualTo(PROPERTIES);
- assertThat(mManager.getIdentity()).isEqualTo(IDENTITY);
+ assertThat(mManager.getProviderIdentity()).isEqualTo(IDENTITY);
assertThat(mManager.hasProvider()).isTrue();
ProviderProperties newProperties = new ProviderProperties.Builder()
@@ -230,7 +230,7 @@
CallerIdentity newIdentity = CallerIdentity.forTest(OTHER_USER, 1, "otherpackage",
"otherattribution");
mProvider.setIdentity(newIdentity);
- assertThat(mManager.getIdentity()).isEqualTo(newIdentity);
+ assertThat(mManager.getProviderIdentity()).isEqualTo(newIdentity);
mManager.setRealProvider(null);
assertThat(mManager.hasProvider()).isFalse();
@@ -333,6 +333,10 @@
@Test
public void testGetLastLocation_Bypass() {
+ mInjector.getSettingsHelper().setIgnoreSettingsAllowlist(
+ new PackageTagsList.Builder().add(
+ IDENTITY.getPackageName()).build());
+
assertThat(mManager.getLastLocation(new LastLocationRequest.Builder().build(), IDENTITY,
PERMISSION_FINE)).isNull();
assertThat(mManager.getLastLocation(
@@ -381,6 +385,14 @@
new LastLocationRequest.Builder().setLocationSettingsIgnored(true).build(),
IDENTITY, PERMISSION_FINE)).isEqualTo(
loc);
+
+ mInjector.getSettingsHelper().setIgnoreSettingsAllowlist(
+ new PackageTagsList.Builder().build());
+ mProvider.setProviderAllowed(false);
+
+ assertThat(mManager.getLastLocation(
+ new LastLocationRequest.Builder().setLocationSettingsIgnored(true).build(),
+ IDENTITY, PERMISSION_FINE)).isNull();
}
@Test
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index a6c81a0..152f3b3 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -25,7 +25,6 @@
"test-apps/JobTestApp/src/**/*.java",
"test-apps/SuspendTestApp/src/**/*.java",
- ":service-bluetooth-tests-sources", // TODO(b/214988855) : Remove once framework-bluetooth jar is ready
],
static_libs: [
"frameworks-base-testutils",
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 3160272..f0c907d 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 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 @@
/* 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/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 2398e36..b601d14 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -1137,9 +1137,6 @@
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
// Verify internal calls.
- verify(getServices().iactivityManager, times(1)).updateDeviceOwner(
- eq(admin1.getPackageName()));
-
verify(getServices().userManager, times(1)).setUserRestriction(
eq(UserManager.DISALLOW_ADD_MANAGED_PROFILE),
eq(true), eq(UserHandle.SYSTEM));
@@ -1205,9 +1202,6 @@
assertThat(dpm.getDeviceOwnerComponentOnAnyUser()).isEqualTo(admin1);
// Verify internal calls.
- verify(getServices().iactivityManager).updateDeviceOwner(
- eq(admin1.getPackageName()));
-
verify(mContext.spiedContext).sendBroadcastAsUser(
MockUtils.checkIntentAction(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED),
MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));
@@ -1392,11 +1386,6 @@
setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
dpm.setActiveAdmin(admin1, /* replace =*/ false);
assertThat(dpm.setDeviceOwner(admin1, "owner-name", UserHandle.USER_SYSTEM)).isTrue();
-
- // Verify internal calls.
- verify(getServices().iactivityManager, times(1)).updateDeviceOwner(
- eq(admin1.getPackageName()));
-
assertThat(dpm.getDeviceOwnerComponentOnAnyUser()).isEqualTo(admin1);
dpm.addUserRestriction(admin1, UserManager.DISALLOW_ADD_USER);
@@ -1501,11 +1490,6 @@
setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
dpm.setActiveAdmin(admin1, /* replace =*/ false);
assertThat(dpm.setDeviceOwner(admin1, "owner-name", UserHandle.USER_SYSTEM)).isTrue();
-
- // Verify internal calls.
- verify(getServices().iactivityManager, times(1)).updateDeviceOwner(
- eq(admin1.getPackageName()));
-
assertThat(dpm.getDeviceOwnerComponentOnAnyUser()).isEqualTo(admin1);
// Now call clear from the secondary user, which should throw.
diff --git a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleBinaryParserTest.java b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleBinaryParserTest.java
index ab21ab0..03363a1 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleBinaryParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleBinaryParserTest.java
@@ -71,9 +71,11 @@
private static final String PACKAGE_NAME = getBits(AtomicFormula.PACKAGE_NAME, KEY_BITS);
private static final String APP_CERTIFICATE = getBits(AtomicFormula.APP_CERTIFICATE, KEY_BITS);
+ private static final String APP_CERTIFICATE_LINEAGE =
+ getBits(AtomicFormula.APP_CERTIFICATE_LINEAGE, KEY_BITS);
private static final String VERSION_CODE = getBits(AtomicFormula.VERSION_CODE, KEY_BITS);
private static final String PRE_INSTALLED = getBits(AtomicFormula.PRE_INSTALLED, KEY_BITS);
- private static final int INVALID_KEY_VALUE = 8;
+ private static final int INVALID_KEY_VALUE = 9;
private static final String INVALID_KEY = getBits(INVALID_KEY_VALUE, KEY_BITS);
private static final String EQ = getBits(AtomicFormula.EQ, OPERATOR_BITS);
@@ -337,6 +339,40 @@
}
@Test
+ public void testBinaryString_validAtomicFormulaWithCertificateLineage() throws Exception {
+ String appCertificate = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
+ String ruleBits =
+ START_BIT
+ + ATOMIC_FORMULA_START_BITS
+ + APP_CERTIFICATE_LINEAGE
+ + EQ
+ + IS_HASHED
+ + getBits(appCertificate.length(), VALUE_SIZE_BITS)
+ + getValueBits(appCertificate)
+ + DENY
+ + END_BIT;
+ byte[] ruleBytes = getBytes(ruleBits);
+ ByteBuffer rule =
+ ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length);
+ rule.put(DEFAULT_FORMAT_VERSION_BYTES);
+ rule.put(ruleBytes);
+
+ RuleParser binaryParser = new RuleBinaryParser();
+ Rule expectedRule =
+ new Rule(
+ new AtomicFormula.StringAtomicFormula(
+ AtomicFormula.APP_CERTIFICATE_LINEAGE,
+ IntegrityUtils.getHexDigest(
+ appCertificate.getBytes(StandardCharsets.UTF_8)),
+ /* isHashedValue= */ true),
+ Rule.DENY);
+
+ List<Rule> rules = binaryParser.parse(rule.array());
+
+ assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
+ }
+
+ @Test
public void testBinaryString_validAtomicFormula_integerValue_noIndexing() throws Exception {
int versionCode = 1;
String ruleBits =
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 c771000..bd35be4 100644
--- a/services/tests/servicestests/src/com/android/server/locales/LocaleManagerBackupRestoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/locales/LocaleManagerBackupRestoreTest.java
@@ -41,7 +41,9 @@
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.os.Binder;
+import android.os.HandlerThread;
import android.os.LocaleList;
+import android.os.Process;
import android.os.RemoteException;
import android.os.SimpleClock;
import android.util.SparseArray;
@@ -78,6 +80,7 @@
*/
@RunWith(AndroidJUnit4.class)
public class LocaleManagerBackupRestoreTest {
+ private static final String TAG = "LocaleManagerBackupRestoreTest";
private static final String DEFAULT_PACKAGE_NAME = "com.android.myapp";
private static final String DEFAULT_LOCALE_TAGS = "en-XC,ar-XB";
private static final String TEST_LOCALES_XML_TAG = "locales";
@@ -104,6 +107,7 @@
private PackageManager mMockPackageManager;
@Mock
private LocaleManagerService mMockLocaleManagerService;
+
BroadcastReceiver mUserMonitor;
PackageMonitor mPackageMonitor;
@@ -128,15 +132,22 @@
mMockPackageManagerInternal = mock(PackageManagerInternal.class);
mMockPackageManager = mock(PackageManager.class);
mMockLocaleManagerService = mock(LocaleManagerService.class);
+ SystemAppUpdateTracker systemAppUpdateTracker = mock(SystemAppUpdateTracker.class);
doReturn(mMockPackageManager).when(mMockContext).getPackageManager();
+ HandlerThread broadcastHandlerThread = new HandlerThread(TAG,
+ Process.THREAD_PRIORITY_BACKGROUND);
+ broadcastHandlerThread.start();
+
mBackupHelper = spy(new ShadowLocaleManagerBackupHelper(mMockContext,
- mMockLocaleManagerService, mMockPackageManagerInternal, mClock, STAGE_DATA));
+ mMockLocaleManagerService, mMockPackageManagerInternal, mClock, STAGE_DATA,
+ broadcastHandlerThread));
doNothing().when(mBackupHelper).notifyBackupManager();
mUserMonitor = mBackupHelper.getUserMonitor();
- mPackageMonitor = mBackupHelper.getPackageMonitor();
+ mPackageMonitor = new LocaleManagerServicePackageMonitor(mBackupHelper,
+ systemAppUpdateTracker);
setCurrentTimeMillis(DEFAULT_CREATION_TIME_MILLIS);
}
diff --git a/services/tests/servicestests/src/com/android/server/locales/LocaleManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/locales/LocaleManagerServiceTest.java
index ca5b0cb..0b3ef45 100644
--- a/services/tests/servicestests/src/com/android/server/locales/LocaleManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/locales/LocaleManagerServiceTest.java
@@ -46,6 +46,7 @@
import androidx.test.ext.junit.runners.AndroidJUnit4;
+import com.android.internal.content.PackageMonitor;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.ActivityTaskManagerInternal.PackageConfig;
@@ -86,6 +87,8 @@
private ActivityTaskManagerInternal mMockActivityTaskManager;
@Mock
private ActivityManagerInternal mMockActivityManager;
+ @Mock
+ PackageMonitor mMockPackageMonitor;
@Before
public void setUp() throws Exception {
@@ -93,6 +96,7 @@
mMockActivityTaskManager = mock(ActivityTaskManagerInternal.class);
mMockActivityManager = mock(ActivityManagerInternal.class);
mMockPackageManagerInternal = mock(PackageManagerInternal.class);
+ mMockPackageMonitor = mock(PackageMonitor.class);
// For unit tests, set the default installer info
PackageManager mockPackageManager = mock(PackageManager.class);
@@ -113,7 +117,8 @@
mMockBackupHelper = mock(ShadowLocaleManagerBackupHelper.class);
mLocaleManagerService = new LocaleManagerService(mMockContext, mMockActivityTaskManager,
- mMockActivityManager, mMockPackageManagerInternal, mMockBackupHelper);
+ mMockActivityManager, mMockPackageManagerInternal,
+ mMockBackupHelper, mMockPackageMonitor);
}
@Test(expected = SecurityException.class)
diff --git a/services/tests/servicestests/src/com/android/server/locales/ShadowLocaleManagerBackupHelper.java b/services/tests/servicestests/src/com/android/server/locales/ShadowLocaleManagerBackupHelper.java
index b0fc636..ad9be0d 100644
--- a/services/tests/servicestests/src/com/android/server/locales/ShadowLocaleManagerBackupHelper.java
+++ b/services/tests/servicestests/src/com/android/server/locales/ShadowLocaleManagerBackupHelper.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.content.pm.PackageManagerInternal;
+import android.os.HandlerThread;
import android.util.SparseArray;
import java.time.Clock;
@@ -31,7 +32,8 @@
ShadowLocaleManagerBackupHelper(Context context,
LocaleManagerService localeManagerService,
PackageManagerInternal pmInternal, Clock clock,
- SparseArray<LocaleManagerBackupHelper.StagedData> stagedData) {
- super(context, localeManagerService, pmInternal, clock, stagedData);
+ SparseArray<LocaleManagerBackupHelper.StagedData> stagedData,
+ HandlerThread broadcastHandlerThread) {
+ super(context, localeManagerService, pmInternal, clock, stagedData, broadcastHandlerThread);
}
}
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 0000000..5185e15
--- /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/pm/ApexManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
index 5d3da43..c7a903b 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
@@ -489,6 +489,20 @@
assertThat(e).hasMessageThat().contains("Failed to collect certificates from ");
}
+ @Test
+ public void testGetActivePackageNameForApexModuleName() throws Exception {
+ final String moduleName = "com.android.module_name";
+
+ ApexInfo[] apexInfo = createApexInfoForTestPkg(true, false);
+ apexInfo[0].moduleName = moduleName;
+ when(mApexService.getAllPackages()).thenReturn(apexInfo);
+ mApexManager.scanApexPackagesTraced(mPackageParser2,
+ ParallelPackageParser.makeExecutorService());
+
+ assertThat(mApexManager.getActivePackageNameForApexModuleName(moduleName))
+ .isEqualTo(TEST_APEX_PKG);
+ }
+
private ApexInfo createApexInfoForTestPkg(boolean isActive, boolean isFactory, int version) {
File apexFile = extractResource(TEST_APEX_PKG, TEST_APEX_FILE_NAME);
ApexInfo apexInfo = new ApexInfo();
diff --git a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundHw2CompatTest.java b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundHw2CompatTest.java
index 16cfd13..6bdd88c 100644
--- a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundHw2CompatTest.java
+++ b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundHw2CompatTest.java
@@ -31,7 +31,6 @@
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -49,7 +48,6 @@
import android.os.IHwBinder;
import android.os.IHwInterface;
import android.os.RemoteException;
-import android.system.OsConstants;
import org.junit.After;
import org.junit.Before;
@@ -60,6 +58,7 @@
import java.util.LinkedList;
import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
@RunWith(Parameterized.class)
public class SoundHw2CompatTest {
@@ -240,14 +239,15 @@
(android.hardware.soundtrigger.V2_1.ISoundTriggerHw) mHalDriver;
final int handle = 29;
- ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHw.SoundModel> modelCaptor =
- ArgumentCaptor.forClass(
- android.hardware.soundtrigger.V2_1.ISoundTriggerHw.SoundModel.class);
+ AtomicReference<android.hardware.soundtrigger.V2_1.ISoundTriggerHw.SoundModel> model =
+ new AtomicReference<>();
ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback> callbackCaptor =
ArgumentCaptor.forClass(
android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.class);
doAnswer(invocation -> {
+ // We need to dup the model, as it gets invalidated after the call returns.
+ model.set(TestUtil.dupModel_2_1(invocation.getArgument(0)));
android.hardware.soundtrigger.V2_1.ISoundTriggerHw.loadSoundModel_2_1Callback
resultCallback = invocation.getArgument(3);
@@ -259,10 +259,9 @@
assertEquals(handle,
mCanonical.loadSoundModel(TestUtil.createGenericSoundModel(), canonicalCallback));
- verify(driver_2_1).loadSoundModel_2_1(modelCaptor.capture(), callbackCaptor.capture(),
- anyInt(), any());
+ verify(driver_2_1).loadSoundModel_2_1(any(), callbackCaptor.capture(), anyInt(), any());
- TestUtil.validateGenericSoundModel_2_1(modelCaptor.getValue());
+ TestUtil.validateGenericSoundModel_2_1(model.get());
validateCallback_2_1(callbackCaptor.getValue(), canonicalCallback);
return handle;
}
@@ -355,14 +354,16 @@
(android.hardware.soundtrigger.V2_1.ISoundTriggerHw) mHalDriver;
final int handle = 29;
- ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHw.PhraseSoundModel>
- modelCaptor = ArgumentCaptor.forClass(
- android.hardware.soundtrigger.V2_1.ISoundTriggerHw.PhraseSoundModel.class);
+ AtomicReference<android.hardware.soundtrigger.V2_1.ISoundTriggerHw.PhraseSoundModel> model =
+ new AtomicReference<>();
ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback> callbackCaptor =
ArgumentCaptor.forClass(
android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.class);
doAnswer(invocation -> {
+ // We need to dup the model, as it gets invalidated after the call returns.
+ model.set(TestUtil.dupPhraseModel_2_1(invocation.getArgument(0)));
+
android.hardware.soundtrigger.V2_1.ISoundTriggerHw.loadPhraseSoundModel_2_1Callback
resultCallback = invocation.getArgument(3);
@@ -374,10 +375,10 @@
assertEquals(handle, mCanonical.loadPhraseSoundModel(TestUtil.createPhraseSoundModel(),
canonicalCallback));
- verify(driver_2_1).loadPhraseSoundModel_2_1(modelCaptor.capture(), callbackCaptor.capture(),
- anyInt(), any());
+ verify(driver_2_1).loadPhraseSoundModel_2_1(any(), callbackCaptor.capture(), anyInt(),
+ any());
- TestUtil.validatePhraseSoundModel_2_1(modelCaptor.getValue());
+ TestUtil.validatePhraseSoundModel_2_1(model.get());
validateCallback_2_1(callbackCaptor.getValue(), canonicalCallback);
return handle;
}
diff --git a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/TestUtil.java b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/TestUtil.java
index e687a2a..30b4a59 100644
--- a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/TestUtil.java
+++ b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/TestUtil.java
@@ -47,6 +47,7 @@
import android.os.ParcelFileDescriptor;
import android.os.SharedMemory;
+import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.List;
@@ -82,6 +83,19 @@
HidlMemoryUtil.hidlMemoryToByteArray(model.data));
}
+ static android.hardware.soundtrigger.V2_1.ISoundTriggerHw.SoundModel dupModel_2_1(
+ android.hardware.soundtrigger.V2_1.ISoundTriggerHw.SoundModel model) {
+ android.hardware.soundtrigger.V2_1.ISoundTriggerHw.SoundModel dup =
+ new android.hardware.soundtrigger.V2_1.ISoundTriggerHw.SoundModel();
+ dup.header = model.header;
+ try {
+ dup.data = model.data.dup();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ return dup;
+ }
+
private static void validateSoundModel_2_0(
android.hardware.soundtrigger.V2_0.ISoundTriggerHw.SoundModel model, int type) {
assertEquals(type, model.type);
@@ -121,6 +135,15 @@
validatePhrases_2_0(model.phrases);
}
+ static android.hardware.soundtrigger.V2_1.ISoundTriggerHw.PhraseSoundModel dupPhraseModel_2_1(
+ android.hardware.soundtrigger.V2_1.ISoundTriggerHw.PhraseSoundModel model) {
+ android.hardware.soundtrigger.V2_1.ISoundTriggerHw.PhraseSoundModel dup =
+ new android.hardware.soundtrigger.V2_1.ISoundTriggerHw.PhraseSoundModel();
+ dup.common = dupModel_2_1(model.common);
+ dup.phrases = model.phrases;
+ return dup;
+ }
+
static void validatePhraseSoundModel_2_0(
android.hardware.soundtrigger.V2_0.ISoundTriggerHw.PhraseSoundModel model) {
validateSoundModel_2_0(model.common,
@@ -190,31 +213,27 @@
properties.maxKeyPhrases = 567;
properties.maxUsers = 678;
properties.recognitionModes =
- RecognitionMode.VOICE_TRIGGER
- | RecognitionMode.USER_IDENTIFICATION
- | RecognitionMode.USER_AUTHENTICATION
- | RecognitionMode.GENERIC_TRIGGER;
+ RecognitionMode.VOICE_TRIGGER | RecognitionMode.USER_IDENTIFICATION
+ | RecognitionMode.USER_AUTHENTICATION | RecognitionMode.GENERIC_TRIGGER;
properties.captureTransition = true;
properties.maxBufferMs = 321;
properties.concurrentCapture = supportConcurrentCapture;
properties.triggerInEvent = true;
properties.powerConsumptionMw = 432;
properties.supportedModelArch = "supportedModelArch";
- properties.audioCapabilities = AudioCapabilities.ECHO_CANCELLATION
- | AudioCapabilities.NOISE_SUPPRESSION;
+ properties.audioCapabilities =
+ AudioCapabilities.ECHO_CANCELLATION | AudioCapabilities.NOISE_SUPPRESSION;
return properties;
}
- static void validateDefaultProperties(Properties properties,
- boolean supportConcurrentCapture) {
+ static void validateDefaultProperties(Properties properties, boolean supportConcurrentCapture) {
validateDefaultProperties(properties, supportConcurrentCapture,
AudioCapabilities.ECHO_CANCELLATION | AudioCapabilities.NOISE_SUPPRESSION,
"supportedModelArch");
}
- static void validateDefaultProperties(Properties properties,
- boolean supportConcurrentCapture, @AudioCapabilities int audioCapabilities,
- @NonNull String supportedModelArch) {
+ static void validateDefaultProperties(Properties properties, boolean supportConcurrentCapture,
+ @AudioCapabilities int audioCapabilities, @NonNull String supportedModelArch) {
assertEquals("implementor", properties.implementor);
assertEquals("description", properties.description);
assertEquals(123, properties.version);
@@ -222,10 +241,9 @@
assertEquals(456, properties.maxSoundModels);
assertEquals(567, properties.maxKeyPhrases);
assertEquals(678, properties.maxUsers);
- assertEquals(RecognitionMode.GENERIC_TRIGGER
- | RecognitionMode.USER_AUTHENTICATION
- | RecognitionMode.USER_IDENTIFICATION
- | RecognitionMode.VOICE_TRIGGER, properties.recognitionModes);
+ assertEquals(RecognitionMode.GENERIC_TRIGGER | RecognitionMode.USER_AUTHENTICATION
+ | RecognitionMode.USER_IDENTIFICATION | RecognitionMode.VOICE_TRIGGER,
+ properties.recognitionModes);
assertTrue(properties.captureTransition);
assertEquals(321, properties.maxBufferMs);
assertEquals(supportConcurrentCapture, properties.concurrentCapture);
@@ -246,8 +264,8 @@
config.phraseRecognitionExtras[0].levels[0].userId = 234;
config.phraseRecognitionExtras[0].levels[0].levelPercent = 34;
config.data = new byte[]{5, 4, 3, 2, 1};
- config.audioCapabilities = AudioCapabilities.ECHO_CANCELLATION
- | AudioCapabilities.NOISE_SUPPRESSION;
+ config.audioCapabilities =
+ AudioCapabilities.ECHO_CANCELLATION | AudioCapabilities.NOISE_SUPPRESSION;
return config;
}
@@ -295,13 +313,12 @@
int captureHandle) {
validateRecognitionConfig_2_1(config.base, captureDevice, captureHandle);
- assertEquals(AudioCapabilities.ECHO_CANCELLATION
- | AudioCapabilities.NOISE_SUPPRESSION, config.audioCapabilities);
+ assertEquals(AudioCapabilities.ECHO_CANCELLATION | AudioCapabilities.NOISE_SUPPRESSION,
+ config.audioCapabilities);
}
static android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionEvent createRecognitionEvent_2_0(
- int hwHandle,
- int status) {
+ int hwHandle, int status) {
android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionEvent halEvent =
new android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionEvent();
halEvent.status = status;
@@ -351,8 +368,7 @@
return event;
}
- static ISoundTriggerHwCallback.RecognitionEvent createRecognitionEvent_2_1(
- int hwHandle,
+ static ISoundTriggerHwCallback.RecognitionEvent createRecognitionEvent_2_1(int hwHandle,
int status) {
ISoundTriggerHwCallback.RecognitionEvent halEvent =
new ISoundTriggerHwCallback.RecognitionEvent();
@@ -386,8 +402,7 @@
PhraseRecognitionExtra extra = new PhraseRecognitionExtra();
extra.id = 123;
extra.confidenceLevel = 52;
- extra.recognitionModes = RecognitionMode.VOICE_TRIGGER
- | RecognitionMode.GENERIC_TRIGGER;
+ extra.recognitionModes = RecognitionMode.VOICE_TRIGGER | RecognitionMode.GENERIC_TRIGGER;
ConfidenceLevel level = new ConfidenceLevel();
level.userId = 31;
level.levelPercent = 43;
@@ -396,8 +411,8 @@
return event;
}
- static android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.PhraseRecognitionEvent
- createPhraseRecognitionEvent_2_0(int hwHandle, int status) {
+ static android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.PhraseRecognitionEvent createPhraseRecognitionEvent_2_0(
+ int hwHandle, int status) {
android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.PhraseRecognitionEvent halEvent =
new android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.PhraseRecognitionEvent();
halEvent.common = createRecognitionEvent_2_0(hwHandle, status);
diff --git a/services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java
index 0e98b5e..1442f1c 100644
--- a/services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java
@@ -584,55 +584,55 @@
}
@Test
- public void testSetNavBarModeOverride_setsOverrideModeKids() throws RemoteException {
- int navBarModeOverrideKids = StatusBarManager.NAV_BAR_MODE_OVERRIDE_KIDS;
+ public void testSetNavBarMode_setsModeKids() throws RemoteException {
+ int navBarModeKids = StatusBarManager.NAV_BAR_MODE_KIDS;
- mStatusBarManagerService.setNavBarModeOverride(navBarModeOverrideKids);
+ mStatusBarManagerService.setNavBarMode(navBarModeKids);
- assertEquals(navBarModeOverrideKids, mStatusBarManagerService.getNavBarModeOverride());
+ assertEquals(navBarModeKids, mStatusBarManagerService.getNavBarMode());
verify(mOverlayManager).setEnabledExclusiveInCategory(anyString(), anyInt());
}
@Test
- public void testSetNavBarModeOverride_setsOverrideModeNone() throws RemoteException {
- int navBarModeOverrideNone = StatusBarManager.NAV_BAR_MODE_OVERRIDE_NONE;
+ public void testSetNavBarMode_setsModeNone() throws RemoteException {
+ int navBarModeNone = StatusBarManager.NAV_BAR_MODE_DEFAULT;
- mStatusBarManagerService.setNavBarModeOverride(navBarModeOverrideNone);
+ mStatusBarManagerService.setNavBarMode(navBarModeNone);
- assertEquals(navBarModeOverrideNone, mStatusBarManagerService.getNavBarModeOverride());
+ assertEquals(navBarModeNone, mStatusBarManagerService.getNavBarMode());
verify(mOverlayManager, never()).setEnabledExclusiveInCategory(anyString(), anyInt());
}
@Test
- public void testSetNavBarModeOverride_invalidInputThrowsError() throws RemoteException {
- int navBarModeOverrideInvalid = -1;
+ public void testSetNavBarMode_invalidInputThrowsError() throws RemoteException {
+ int navBarModeInvalid = -1;
assertThrows(UnsupportedOperationException.class,
- () -> mStatusBarManagerService.setNavBarModeOverride(navBarModeOverrideInvalid));
+ () -> mStatusBarManagerService.setNavBarMode(navBarModeInvalid));
verify(mOverlayManager, never()).setEnabledExclusiveInCategory(anyString(), anyInt());
}
@Test
- public void testSetNavBarModeOverride_noOverlayManagerDoesNotEnable() throws RemoteException {
+ public void testSetNavBarMode_noOverlayManagerDoesNotEnable() throws RemoteException {
mOverlayManager = null;
- int navBarModeOverrideKids = StatusBarManager.NAV_BAR_MODE_OVERRIDE_KIDS;
+ int navBarModeKids = StatusBarManager.NAV_BAR_MODE_KIDS;
- mStatusBarManagerService.setNavBarModeOverride(navBarModeOverrideKids);
+ mStatusBarManagerService.setNavBarMode(navBarModeKids);
- assertEquals(navBarModeOverrideKids, mStatusBarManagerService.getNavBarModeOverride());
+ assertEquals(navBarModeKids, mStatusBarManagerService.getNavBarMode());
verify(mOverlayManager, never()).setEnabledExclusiveInCategory(anyString(), anyInt());
}
@Test
- public void testSetNavBarModeOverride_noPackageDoesNotEnable() throws Exception {
+ public void testSetNavBarMode_noPackageDoesNotEnable() throws Exception {
mContext.setMockPackageManager(mPackageManager);
when(mPackageManager.getPackageInfo(anyString(),
any(PackageManager.PackageInfoFlags.class))).thenReturn(null);
- int navBarModeOverrideKids = StatusBarManager.NAV_BAR_MODE_OVERRIDE_KIDS;
+ int navBarModeKids = StatusBarManager.NAV_BAR_MODE_KIDS;
- mStatusBarManagerService.setNavBarModeOverride(navBarModeOverrideKids);
+ mStatusBarManagerService.setNavBarMode(navBarModeKids);
- assertEquals(navBarModeOverrideKids, mStatusBarManagerService.getNavBarModeOverride());
+ assertEquals(navBarModeKids, mStatusBarManagerService.getNavBarMode());
verify(mOverlayManager, never()).setEnabledExclusiveInCategory(anyString(), anyInt());
}
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
index e1a4989..3d24a81 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
@@ -61,8 +61,6 @@
import androidx.test.InstrumentationRegistry;
-import com.android.internal.app.IBatteryStats;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
@@ -106,8 +104,6 @@
@Mock
private IBinder mVibrationToken;
@Mock
- private IBatteryStats mIBatteryStatsMock;
- @Mock
private VibrationConfig mVibrationConfigMock;
private final Map<Integer, FakeVibratorControllerProvider> mVibratorProviders = new HashMap<>();
@@ -117,6 +113,9 @@
private TestLooper mTestLooper;
private TestLooperAutoDispatcher mCustomTestLooperDispatcher;
+ // Setup from the providers when VibrationThread is initialized.
+ private SparseArray<VibratorController> mControllers;
+
@Before
public void setUp() throws Exception {
mTestLooper = new TestLooper();
@@ -178,11 +177,11 @@
VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
waitForCompletion(thread);
- verify(mIBatteryStatsMock).noteVibratorOn(eq(UID), eq(10L));
- verify(mIBatteryStatsMock).noteVibratorOff(eq(UID));
+ verify(mManagerHooks).noteVibratorOn(eq(UID), eq(10L));
+ verify(mManagerHooks).noteVibratorOff(eq(UID));
verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
- assertFalse(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
+ assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
assertEquals(Arrays.asList(expectedOneShot(10)),
mVibratorProviders.get(VIBRATOR_ID).getEffectSegments());
@@ -197,11 +196,11 @@
VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
waitForCompletion(thread);
- verify(mIBatteryStatsMock).noteVibratorOn(eq(UID), eq(10L));
- verify(mIBatteryStatsMock).noteVibratorOff(eq(UID));
+ verify(mManagerHooks).noteVibratorOn(eq(UID), eq(10L));
+ verify(mManagerHooks).noteVibratorOff(eq(UID));
verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
- assertFalse(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
+ assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
assertEquals(Arrays.asList(expectedOneShot(10)),
mVibratorProviders.get(VIBRATOR_ID).getEffectSegments());
@@ -219,11 +218,11 @@
VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
waitForCompletion(thread);
- verify(mIBatteryStatsMock).noteVibratorOn(eq(UID), eq(15L));
- verify(mIBatteryStatsMock).noteVibratorOff(eq(UID));
+ verify(mManagerHooks).noteVibratorOn(eq(UID), eq(15L));
+ verify(mManagerHooks).noteVibratorOff(eq(UID));
verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
- assertFalse(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
+ assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
assertEquals(Arrays.asList(expectedOneShot(15)),
mVibratorProviders.get(VIBRATOR_ID).getEffectSegments());
@@ -247,15 +246,15 @@
thread, TEST_TIMEOUT_MILLIS));
// Vibration still running after 2 cycles.
assertTrue(thread.isAlive());
- assertTrue(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
+ assertTrue(mControllers.get(VIBRATOR_ID).isVibrating());
thread.cancel();
waitForCompletion(thread);
- verify(mIBatteryStatsMock).noteVibratorOn(eq(UID), anyLong());
- verify(mIBatteryStatsMock).noteVibratorOff(eq(UID));
+ verify(mManagerHooks).noteVibratorOn(eq(UID), anyLong());
+ verify(mManagerHooks).noteVibratorOff(eq(UID));
verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED);
- assertFalse(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
+ assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
List<Float> playedAmplitudes = fakeVibrator.getAmplitudes();
assertFalse(fakeVibrator.getEffectSegments().isEmpty());
@@ -284,7 +283,7 @@
waitForCompletion(thread);
verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED);
- assertFalse(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
+ assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
assertEquals(Arrays.asList(expectedOneShot(1000)), fakeVibrator.getEffectSegments());
}
@@ -306,7 +305,7 @@
waitForCompletion(thread);
verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED);
- assertFalse(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
+ assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
assertEquals(Arrays.asList(expectedOneShot(5550)), fakeVibrator.getEffectSegments());
}
@@ -329,7 +328,7 @@
waitForCompletion(thread);
verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED);
- assertFalse(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
+ assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
assertEquals(2, fakeVibrator.getEffectSegments().size());
// First time turn vibrator ON for minimum of 1s.
assertEquals(1000L, fakeVibrator.getEffectSegments().get(0).getDuration());
@@ -354,7 +353,7 @@
.compose();
VibrationThread vibrationThread = startThreadAndDispatcher(vibrationId, effect);
- assertTrue(waitUntil(t -> t.getVibrators().get(VIBRATOR_ID).isVibrating(), vibrationThread,
+ assertTrue(waitUntil(t -> mControllers.get(VIBRATOR_ID).isVibrating(), vibrationThread,
TEST_TIMEOUT_MILLIS));
assertTrue(vibrationThread.isAlive());
@@ -367,7 +366,7 @@
waitForCompletion(cancellingThread);
verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED);
- assertFalse(vibrationThread.getVibrators().get(VIBRATOR_ID).isVibrating());
+ assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
}
@Test
@@ -379,7 +378,7 @@
VibrationEffect effect = VibrationEffect.createWaveform(new long[]{100}, new int[]{100}, 0);
VibrationThread vibrationThread = startThreadAndDispatcher(vibrationId, effect);
- assertTrue(waitUntil(t -> t.getVibrators().get(VIBRATOR_ID).isVibrating(), vibrationThread,
+ assertTrue(waitUntil(t -> mControllers.get(VIBRATOR_ID).isVibrating(), vibrationThread,
TEST_TIMEOUT_MILLIS));
assertTrue(vibrationThread.isAlive());
@@ -392,7 +391,7 @@
waitForCompletion(cancellingThread);
verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED);
- assertFalse(vibrationThread.getVibrators().get(VIBRATOR_ID).isVibrating());
+ assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
}
@Test
@@ -404,11 +403,11 @@
VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
waitForCompletion(thread);
- verify(mIBatteryStatsMock).noteVibratorOn(eq(UID), eq(20L));
- verify(mIBatteryStatsMock).noteVibratorOff(eq(UID));
+ verify(mManagerHooks).noteVibratorOn(eq(UID), eq(20L));
+ verify(mManagerHooks).noteVibratorOff(eq(UID));
verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
- assertFalse(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
+ assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
assertEquals(Arrays.asList(expectedPrebaked(VibrationEffect.EFFECT_THUD)),
mVibratorProviders.get(VIBRATOR_ID).getEffectSegments());
@@ -427,11 +426,11 @@
VibrationThread thread = startThreadAndDispatcher(vibration);
waitForCompletion(thread);
- verify(mIBatteryStatsMock).noteVibratorOn(eq(UID), eq(10L));
- verify(mIBatteryStatsMock).noteVibratorOff(eq(UID));
+ verify(mManagerHooks).noteVibratorOn(eq(UID), eq(10L));
+ verify(mManagerHooks).noteVibratorOff(eq(UID));
verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
- assertFalse(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
+ assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
assertEquals(Arrays.asList(expectedOneShot(10)),
mVibratorProviders.get(VIBRATOR_ID).getEffectSegments());
@@ -446,8 +445,8 @@
VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
waitForCompletion(thread);
- verify(mIBatteryStatsMock, never()).noteVibratorOn(eq(UID), anyLong());
- verify(mIBatteryStatsMock, never()).noteVibratorOff(eq(UID));
+ verify(mManagerHooks, never()).noteVibratorOn(eq(UID), anyLong());
+ verify(mManagerHooks, never()).noteVibratorOff(eq(UID));
verify(mControllerCallbacks, never()).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
verifyCallbacksTriggered(vibrationId, Vibration.Status.IGNORED_UNSUPPORTED);
assertTrue(mVibratorProviders.get(VIBRATOR_ID).getEffectSegments().isEmpty());
@@ -466,11 +465,11 @@
VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
waitForCompletion(thread);
- verify(mIBatteryStatsMock).noteVibratorOn(eq(UID), eq(40L));
- verify(mIBatteryStatsMock).noteVibratorOff(eq(UID));
+ verify(mManagerHooks).noteVibratorOn(eq(UID), eq(40L));
+ verify(mManagerHooks).noteVibratorOff(eq(UID));
verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
- assertFalse(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
+ assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
assertEquals(Arrays.asList(
expectedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1, 0),
expectedPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, 0.5f, 0)),
@@ -486,8 +485,8 @@
VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
waitForCompletion(thread);
- verify(mIBatteryStatsMock, never()).noteVibratorOn(eq(UID), anyLong());
- verify(mIBatteryStatsMock, never()).noteVibratorOff(eq(UID));
+ verify(mManagerHooks, never()).noteVibratorOn(eq(UID), anyLong());
+ verify(mManagerHooks, never()).noteVibratorOff(eq(UID));
verify(mControllerCallbacks, never()).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
verifyCallbacksTriggered(vibrationId, Vibration.Status.IGNORED_UNSUPPORTED);
assertTrue(mVibratorProviders.get(VIBRATOR_ID).getEffectSegments().isEmpty());
@@ -536,11 +535,11 @@
waitForCompletion(thread);
// Use first duration the vibrator is turned on since we cannot estimate the clicks.
- verify(mIBatteryStatsMock).noteVibratorOn(eq(UID), eq(10L));
- verify(mIBatteryStatsMock).noteVibratorOff(eq(UID));
+ verify(mManagerHooks).noteVibratorOn(eq(UID), eq(10L));
+ verify(mManagerHooks).noteVibratorOff(eq(UID));
verify(mControllerCallbacks, times(4)).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
- assertFalse(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
+ assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
assertEquals(Arrays.asList(
expectedOneShot(10),
expectedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1, 0),
@@ -573,11 +572,11 @@
VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
waitForCompletion(thread);
- verify(mIBatteryStatsMock).noteVibratorOn(eq(UID), eq(100L));
- verify(mIBatteryStatsMock).noteVibratorOff(eq(UID));
+ verify(mManagerHooks).noteVibratorOn(eq(UID), eq(100L));
+ verify(mManagerHooks).noteVibratorOff(eq(UID));
verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
- assertFalse(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
+ assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
assertEquals(Arrays.asList(
expectedRamp(/* amplitude= */ 1, /* frequencyHz= */ 150, /* duration= */ 10),
expectedRamp(/* startAmplitude= */ 1, /* endAmplitude= */ 0,
@@ -630,11 +629,11 @@
TEST_TIMEOUT_MILLIS));
// Vibration still running after 2 cycles.
assertTrue(thread.isAlive());
- assertTrue(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
+ assertTrue(mControllers.get(VIBRATOR_ID).isVibrating());
thread.binderDied();
waitForCompletion(thread);
- assertFalse(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
+ assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED);
}
@@ -666,12 +665,12 @@
VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
waitForCompletion(thread);
- verify(mIBatteryStatsMock).noteVibratorOn(eq(UID), eq(20L));
- verify(mIBatteryStatsMock).noteVibratorOff(eq(UID));
+ verify(mManagerHooks).noteVibratorOn(eq(UID), eq(20L));
+ verify(mManagerHooks).noteVibratorOff(eq(UID));
verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
verify(mControllerCallbacks, never()).onComplete(eq(2), eq(vibrationId));
verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
- assertFalse(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
+ assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
assertEquals(Arrays.asList(expectedPrebaked(VibrationEffect.EFFECT_TICK)),
mVibratorProviders.get(VIBRATOR_ID).getEffectSegments());
@@ -690,15 +689,15 @@
VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
waitForCompletion(thread);
- verify(mIBatteryStatsMock).noteVibratorOn(eq(UID), eq(20L));
- verify(mIBatteryStatsMock).noteVibratorOff(eq(UID));
+ verify(mManagerHooks).noteVibratorOn(eq(UID), eq(20L));
+ verify(mManagerHooks).noteVibratorOff(eq(UID));
verify(mControllerCallbacks).onComplete(eq(1), eq(vibrationId));
verify(mControllerCallbacks).onComplete(eq(2), eq(vibrationId));
verify(mControllerCallbacks).onComplete(eq(3), eq(vibrationId));
verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
- assertFalse(thread.getVibrators().get(1).isVibrating());
- assertFalse(thread.getVibrators().get(2).isVibrating());
- assertFalse(thread.getVibrators().get(3).isVibrating());
+ assertFalse(mControllers.get(1).isVibrating());
+ assertFalse(mControllers.get(2).isVibrating());
+ assertFalse(mControllers.get(3).isVibrating());
VibrationEffectSegment expected = expectedPrebaked(VibrationEffect.EFFECT_CLICK);
assertEquals(Arrays.asList(expected), mVibratorProviders.get(1).getEffectSegments());
@@ -728,17 +727,17 @@
VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
waitForCompletion(thread);
- verify(mIBatteryStatsMock).noteVibratorOn(eq(UID), eq(20L));
- verify(mIBatteryStatsMock).noteVibratorOff(eq(UID));
+ verify(mManagerHooks).noteVibratorOn(eq(UID), eq(20L));
+ verify(mManagerHooks).noteVibratorOff(eq(UID));
verify(mControllerCallbacks).onComplete(eq(1), eq(vibrationId));
verify(mControllerCallbacks).onComplete(eq(2), eq(vibrationId));
verify(mControllerCallbacks).onComplete(eq(3), eq(vibrationId));
verify(mControllerCallbacks).onComplete(eq(4), eq(vibrationId));
verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
- assertFalse(thread.getVibrators().get(1).isVibrating());
- assertFalse(thread.getVibrators().get(2).isVibrating());
- assertFalse(thread.getVibrators().get(3).isVibrating());
- assertFalse(thread.getVibrators().get(4).isVibrating());
+ assertFalse(mControllers.get(1).isVibrating());
+ assertFalse(mControllers.get(2).isVibrating());
+ assertFalse(mControllers.get(3).isVibrating());
+ assertFalse(mControllers.get(4).isVibrating());
assertEquals(Arrays.asList(expectedPrebaked(VibrationEffect.EFFECT_CLICK)),
mVibratorProviders.get(1).getEffectSegments());
@@ -777,18 +776,18 @@
controllerVerifier.verify(mControllerCallbacks).onComplete(eq(1), eq(vibrationId));
controllerVerifier.verify(mControllerCallbacks).onComplete(eq(2), eq(vibrationId));
- InOrder batterVerifier = inOrder(mIBatteryStatsMock);
- batterVerifier.verify(mIBatteryStatsMock).noteVibratorOn(eq(UID), eq(20L));
- batterVerifier.verify(mIBatteryStatsMock).noteVibratorOff(eq(UID));
- batterVerifier.verify(mIBatteryStatsMock).noteVibratorOn(eq(UID), eq(10L));
- batterVerifier.verify(mIBatteryStatsMock).noteVibratorOff(eq(UID));
- batterVerifier.verify(mIBatteryStatsMock).noteVibratorOn(eq(UID), eq(20L));
- batterVerifier.verify(mIBatteryStatsMock).noteVibratorOff(eq(UID));
+ InOrder batteryVerifier = inOrder(mManagerHooks);
+ batteryVerifier.verify(mManagerHooks).noteVibratorOn(eq(UID), eq(20L));
+ batteryVerifier.verify(mManagerHooks).noteVibratorOff(eq(UID));
+ batteryVerifier.verify(mManagerHooks).noteVibratorOn(eq(UID), eq(10L));
+ batteryVerifier.verify(mManagerHooks).noteVibratorOff(eq(UID));
+ batteryVerifier.verify(mManagerHooks).noteVibratorOn(eq(UID), eq(20L));
+ batteryVerifier.verify(mManagerHooks).noteVibratorOff(eq(UID));
verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
- assertFalse(thread.getVibrators().get(1).isVibrating());
- assertFalse(thread.getVibrators().get(2).isVibrating());
- assertFalse(thread.getVibrators().get(3).isVibrating());
+ assertFalse(mControllers.get(1).isVibrating());
+ assertFalse(mControllers.get(2).isVibrating());
+ assertFalse(mControllers.get(3).isVibrating());
assertEquals(Arrays.asList(expectedOneShot(10)),
mVibratorProviders.get(1).getEffectSegments());
@@ -945,22 +944,22 @@
// All vibrators are turned on in parallel.
assertTrue(waitUntil(
- t -> t.getVibrators().get(1).isVibrating()
- && t.getVibrators().get(2).isVibrating()
- && t.getVibrators().get(3).isVibrating(),
+ t -> mControllers.get(1).isVibrating()
+ && mControllers.get(2).isVibrating()
+ && mControllers.get(3).isVibrating(),
thread, TEST_TIMEOUT_MILLIS));
waitForCompletion(thread);
- verify(mIBatteryStatsMock).noteVibratorOn(eq(UID), eq(80L));
- verify(mIBatteryStatsMock).noteVibratorOff(eq(UID));
+ verify(mManagerHooks).noteVibratorOn(eq(UID), eq(80L));
+ verify(mManagerHooks).noteVibratorOff(eq(UID));
verify(mControllerCallbacks).onComplete(eq(1), eq(vibrationId));
verify(mControllerCallbacks).onComplete(eq(2), eq(vibrationId));
verify(mControllerCallbacks).onComplete(eq(3), eq(vibrationId));
verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
- assertFalse(thread.getVibrators().get(1).isVibrating());
- assertFalse(thread.getVibrators().get(2).isVibrating());
- assertFalse(thread.getVibrators().get(3).isVibrating());
+ assertFalse(mControllers.get(1).isVibrating());
+ assertFalse(mControllers.get(2).isVibrating());
+ assertFalse(mControllers.get(3).isVibrating());
assertEquals(Arrays.asList(expectedOneShot(25)),
mVibratorProviders.get(1).getEffectSegments());
@@ -1035,7 +1034,7 @@
// After the vibrator call ends the vibration is cancelled and the vibrator is turned off.
waitForCompletion(vibrationThread, /* timeout= */ latency + TEST_TIMEOUT_MILLIS);
verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED);
- assertFalse(vibrationThread.getVibrators().get(VIBRATOR_ID).isVibrating());
+ assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
}
@Test
@@ -1055,7 +1054,7 @@
.combine();
VibrationThread vibrationThread = startThreadAndDispatcher(vibrationId, effect);
- assertTrue(waitUntil(t -> t.getVibrators().get(2).isVibrating(), vibrationThread,
+ assertTrue(waitUntil(t -> mControllers.get(2).isVibrating(), vibrationThread,
TEST_TIMEOUT_MILLIS));
assertTrue(vibrationThread.isAlive());
@@ -1068,8 +1067,8 @@
waitForCompletion(cancellingThread);
verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED);
- assertFalse(vibrationThread.getVibrators().get(1).isVibrating());
- assertFalse(vibrationThread.getVibrators().get(2).isVibrating());
+ assertFalse(mControllers.get(1).isVibrating());
+ assertFalse(mControllers.get(2).isVibrating());
}
@Test
@@ -1086,8 +1085,8 @@
.combine();
VibrationThread vibrationThread = startThreadAndDispatcher(vibrationId, effect);
- assertTrue(waitUntil(t -> t.getVibrators().get(1).isVibrating()
- && t.getVibrators().get(2).isVibrating(),
+ assertTrue(waitUntil(t -> mControllers.get(1).isVibrating()
+ && mControllers.get(2).isVibrating(),
vibrationThread, TEST_TIMEOUT_MILLIS));
assertTrue(vibrationThread.isAlive());
@@ -1100,8 +1099,8 @@
waitForCompletion(cancellingThread);
verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED);
- assertFalse(vibrationThread.getVibrators().get(1).isVibrating());
- assertFalse(vibrationThread.getVibrators().get(2).isVibrating());
+ assertFalse(mControllers.get(1).isVibrating());
+ assertFalse(mControllers.get(2).isVibrating());
}
@Test
@@ -1110,7 +1109,7 @@
VibrationEffect effect = VibrationEffect.createWaveform(new long[]{5}, new int[]{100}, 0);
VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
- assertTrue(waitUntil(t -> t.getVibrators().get(VIBRATOR_ID).isVibrating(), thread,
+ assertTrue(waitUntil(t -> mControllers.get(VIBRATOR_ID).isVibrating(), thread,
TEST_TIMEOUT_MILLIS));
assertTrue(thread.isAlive());
@@ -1121,7 +1120,7 @@
verify(mVibrationToken).unlinkToDeath(same(thread), eq(0));
verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED);
assertFalse(mVibratorProviders.get(VIBRATOR_ID).getEffectSegments().isEmpty());
- assertFalse(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
+ assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
}
@Test
@@ -1192,7 +1191,7 @@
long vibrationId = 1;
VibrationEffect effect = VibrationEffect.createOneShot(10_000, 240);
VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
- assertTrue(waitUntil(t -> t.getVibrators().get(VIBRATOR_ID).isVibrating(), thread,
+ assertTrue(waitUntil(t -> mControllers.get(VIBRATOR_ID).isVibrating(), thread,
TEST_TIMEOUT_MILLIS));
thread.cancel();
waitForCompletion(thread);
@@ -1299,8 +1298,9 @@
}
private VibrationThread startThreadAndDispatcher(Vibration vib) {
+ mControllers = createVibratorControllers();
VibrationThread thread = new VibrationThread(vib, mVibrationSettings, mEffectAdapter,
- createVibratorControllers(), mWakeLock, mIBatteryStatsMock, mManagerHooks);
+ mControllers, mWakeLock, mManagerHooks);
doAnswer(answer -> {
thread.vibratorComplete(answer.getArgument(0));
return null;
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
index ccdb105..19111e5 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
@@ -71,6 +71,7 @@
import android.os.test.TestLooper;
import android.os.vibrator.PrebakedSegment;
import android.os.vibrator.PrimitiveSegment;
+import android.os.vibrator.VibrationConfig;
import android.os.vibrator.VibrationEffectSegment;
import android.platform.test.annotations.Presubmit;
import android.provider.Settings;
@@ -78,6 +79,7 @@
import androidx.test.InstrumentationRegistry;
+import com.android.internal.app.IBatteryStats;
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.internal.util.test.FakeSettingsProviderRule;
import com.android.server.LocalServices;
@@ -144,6 +146,8 @@
private AppOpsManager mAppOpsManagerMock;
@Mock
private IInputManager mIInputManagerMock;
+ @Mock
+ private IBatteryStats mBatteryStatsMock;
private final Map<Integer, FakeVibratorControllerProvider> mVibratorProviders = new HashMap<>();
@@ -152,12 +156,14 @@
private FakeVibrator mVibrator;
private PowerManagerInternal.LowPowerModeListener mRegisteredPowerModeListener;
private VibratorManagerService.ExternalVibratorService mExternalVibratorService;
+ private VibrationConfig mVibrationConfig;
@Before
public void setUp() throws Exception {
mTestLooper = new TestLooper();
mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext()));
InputManager inputManager = InputManager.resetInstance(mIInputManagerMock);
+ mVibrationConfig = new VibrationConfig(mContextSpy.getResources());
ContentResolver contentResolver = mSettingsProviderRule.mockContentResolver(mContextSpy);
when(mContextSpy.getContentResolver()).thenReturn(contentResolver);
@@ -222,6 +228,11 @@
}
@Override
+ IBatteryStats getBatteryStatsService() {
+ return mBatteryStatsMock;
+ }
+
+ @Override
VibratorController createVibratorController(int vibratorId,
VibratorController.OnVibrationCompleteListener listener) {
return mVibratorProviders.get(vibratorId)
@@ -382,6 +393,11 @@
inOrderVerifier.verify(listenerMock).onVibrating(eq(true));
inOrderVerifier.verify(listenerMock).onVibrating(eq(false));
inOrderVerifier.verifyNoMoreInteractions();
+
+ InOrder batteryVerifier = inOrder(mBatteryStatsMock);
+ batteryVerifier.verify(mBatteryStatsMock)
+ .noteVibratorOn(UID, 40 + mVibrationConfig.getRampDownDurationMs());
+ batteryVerifier.verify(mBatteryStatsMock).noteVibratorOff(UID);
}
@Test
@@ -731,6 +747,12 @@
// Wait before checking it never played a second effect.
assertFalse(waitUntil(s -> mVibratorProviders.get(1).getEffectSegments().size() > 1,
service, /* timeout= */ 50));
+
+ // The time estimate is recorded when the vibration starts, repeating vibrations
+ // are capped at BATTERY_STATS_REPEATING_VIBRATION_DURATION (=5000).
+ verify(mBatteryStatsMock).noteVibratorOn(UID, 5000);
+ // The second vibration shouldn't have recorded that the vibrators were turned on.
+ verify(mBatteryStatsMock, times(1)).noteVibratorOn(anyInt(), anyLong());
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowOrientationListenerTest.java b/services/tests/servicestests/src/com/android/server/wm/WindowOrientationListenerTest.java
index 2794d48..c64ff9e 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowOrientationListenerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowOrientationListenerTest.java
@@ -114,7 +114,7 @@
}
@Test
- public void testSensorChanged_normalCase2() {
+ public void testOnSensorChanged_normalCase2() {
mWindowOrientationListener.mOrientationJudge.onSensorChanged(mFakeSensorEvent);
mFakeRotationResolverInternal.callbackWithFailureResult(
@@ -123,6 +123,15 @@
assertThat(mFinalizedRotation).isEqualTo(DEFAULT_SENSOR_ROTATION);
}
+ @Test
+ public void testOnSensorChanged_rotationResolverServiceIsNull_useSensorResult() {
+ mWindowOrientationListener.mRotationResolverService = null;
+
+ mWindowOrientationListener.mOrientationJudge.onSensorChanged(mFakeSensorEvent);
+
+ assertThat(mFinalizedRotation).isEqualTo(DEFAULT_SENSOR_ROTATION);
+ }
+
static final class TestableRotationResolver extends RotationResolverInternal {
@Surface.Rotation
RotationResolverCallbackInternal mCallback;
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 87abc53..16c5bfe 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -925,14 +925,10 @@
any(), anyBoolean(), anyBoolean(), eq(false));
}
- private ActivityRecord createSingleTaskActivityOn(Task stack) {
+ private ActivityRecord createSingleTaskActivityOn(Task task) {
final ComponentName componentName = ComponentName.createRelative(
DEFAULT_COMPONENT_PACKAGE_NAME,
DEFAULT_COMPONENT_PACKAGE_NAME + ".SingleTaskActivity");
- final Task task = new TaskBuilder(mSupervisor)
- .setComponent(componentName)
- .setParentTaskFragment(stack)
- .build();
return new ActivityBuilder(mAtm)
.setComponent(componentName)
.setLaunchMode(LAUNCH_SINGLE_TASK)
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
index 0d67946..72521fd 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -120,7 +120,7 @@
behind.setState(ActivityRecord.State.STARTED, "test");
behind.mVisibleRequested = true;
- task.performClearTask("test");
+ task.removeActivities("test", false /* excludingTaskOverlay */);
assertFalse(mDisplayContent.mAppTransition.isReady());
}
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 9f7130e..c083870 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.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 @@
app.removeImmediately();
- assertNull(dc.getImeTarget(IME_TARGET_INPUT));
+ assertNull(dc.getImeInputTarget());
assertNull(dc.computeImeControlTarget());
}
@@ -1126,19 +1125,19 @@
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 @@
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 @@
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 e387615..90a6918 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 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 @@
// 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/LockTaskControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
index cc1869e..9fc9489 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
@@ -557,7 +557,7 @@
mLockTaskController.updateLockTaskPackages(TEST_USER_ID, allowlist);
// THEN the task running that package should be stopped
- verify(tr2).performClearTaskLocked();
+ verify(tr2).performClearTaskForReuse(false /* excludingTaskOverlay*/);
assertFalse(mLockTaskController.isTaskLocked(tr2));
// THEN the other task should remain locked
assertEquals(LOCK_TASK_MODE_LOCKED, mLockTaskController.getLockTaskModeState());
@@ -569,7 +569,7 @@
mLockTaskController.updateLockTaskPackages(TEST_USER_ID, allowlist);
// THEN the last task should be cleared, and the system should quit LockTask mode
- verify(tr1).performClearTaskLocked();
+ verify(tr1).performClearTaskForReuse(false /* excludingTaskOverlay*/);
assertFalse(mLockTaskController.isTaskLocked(tr1));
assertEquals(LOCK_TASK_MODE_NONE, mLockTaskController.getLockTaskModeState());
verifyLockTaskStopped(times(1));
diff --git a/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java b/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java
index f007149..972567b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java
@@ -21,6 +21,7 @@
import static org.junit.Assert.assertNull;
import android.app.ActivityOptions;
+import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
import android.view.RemoteAnimationAdapter;
@@ -45,6 +46,7 @@
public class PendingRemoteAnimationRegistryTest {
@Mock RemoteAnimationAdapter mAdapter;
+ @Mock IBinder mLaunchCookie;
private PendingRemoteAnimationRegistry mRegistry;
private final OffsettableClock mClock = new OffsettableClock.Stopped();
private TestHandler mHandler;
@@ -65,7 +67,7 @@
@Test
public void testOverrideActivityOptions() {
- mRegistry.addPendingAnimation("com.android.test", mAdapter);
+ mRegistry.addPendingAnimation("com.android.test", mAdapter, null /* launchCookie */);
ActivityOptions opts = ActivityOptions.makeBasic();
opts = mRegistry.overrideOptionsIfNeeded("com.android.test", opts);
assertEquals(mAdapter, opts.getRemoteAnimationAdapter());
@@ -73,15 +75,24 @@
@Test
public void testOverrideActivityOptions_null() {
- mRegistry.addPendingAnimation("com.android.test", mAdapter);
+ mRegistry.addPendingAnimation("com.android.test", mAdapter, null /* launchCookie */);
final ActivityOptions opts = mRegistry.overrideOptionsIfNeeded("com.android.test", null);
assertNotNull(opts);
assertEquals(mAdapter, opts.getRemoteAnimationAdapter());
}
@Test
+ public void testOverrideLaunchCookie() {
+ mRegistry.addPendingAnimation("com.android.test", mAdapter, mLaunchCookie);
+ ActivityOptions opts = ActivityOptions.makeBasic();
+ opts = mRegistry.overrideOptionsIfNeeded("com.android.test", opts);
+ assertNotNull(opts);
+ assertEquals(mLaunchCookie, opts.getLaunchCookie());
+ }
+
+ @Test
public void testTimeout() {
- mRegistry.addPendingAnimation("com.android.test", mAdapter);
+ mRegistry.addPendingAnimation("com.android.test", mAdapter, null /* launchCookie */);
mClock.fastForward(5000);
mHandler.timeAdvance();
assertNull(mRegistry.overrideOptionsIfNeeded("com.android.test", null));
@@ -89,10 +100,10 @@
@Test
public void testTimeout_overridenEntry() {
- mRegistry.addPendingAnimation("com.android.test", mAdapter);
+ mRegistry.addPendingAnimation("com.android.test", mAdapter, null /* launchCookie */);
mClock.fastForward(2500);
mHandler.timeAdvance();
- mRegistry.addPendingAnimation("com.android.test", mAdapter);
+ mRegistry.addPendingAnimation("com.android.test", mAdapter, null /* launchCookie */);
mClock.fastForward(1000);
mHandler.timeAdvance();
final ActivityOptions opts = mRegistry.overrideOptionsIfNeeded("com.android.test", null);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index ba65104..acceadf 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -938,7 +938,33 @@
}
@Test
- public void testGetValidLaunchRootTaskOnDisplayWithCandidateRootTask() {
+ public void testGetLaunchRootTaskOnSecondaryTaskDisplayArea() {
+ // Adding another TaskDisplayArea to the default display.
+ final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
+ final TaskDisplayArea taskDisplayArea = new TaskDisplayArea(display,
+ mWm, "TDA", FEATURE_VENDOR_FIRST);
+ display.addChild(taskDisplayArea, POSITION_BOTTOM);
+
+ // Making sure getting the root task from the preferred TDA
+ LaunchParamsController.LaunchParams launchParams =
+ new LaunchParamsController.LaunchParams();
+ launchParams.mPreferredTaskDisplayArea = taskDisplayArea;
+ Task root = mRootWindowContainer.getLaunchRootTask(null /* r */, null /* options */,
+ null /* candidateTask */, null /* sourceTask */, true /* onTop */, launchParams,
+ 0 /* launchParams */);
+ assertEquals(taskDisplayArea, root.getTaskDisplayArea());
+
+ // Making sure still getting the root task from the preferred TDA when passing in a
+ // launching activity.
+ ActivityRecord r = new ActivityBuilder(mAtm).build();
+ root = mRootWindowContainer.getLaunchRootTask(r, null /* options */,
+ null /* candidateTask */, null /* sourceTask */, true /* onTop */, launchParams,
+ 0 /* launchParams */);
+ assertEquals(taskDisplayArea, root.getTaskDisplayArea());
+ }
+
+ @Test
+ public void testGetOrCreateRootTaskOnDisplayWithCandidateRootTask() {
// Create a root task with an activity on secondary display.
final TestDisplayContent secondaryDisplay = new TestDisplayContent.Builder(mAtm, 300,
600).build();
@@ -947,9 +973,9 @@
final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task).build();
// Make sure the root task is valid and can be reused on default display.
- final Task rootTask = mRootWindowContainer.getValidLaunchRootTaskInTaskDisplayArea(
- mRootWindowContainer.getDefaultTaskDisplayArea(), activity, task,
- null /* options */, null /* launchParams */);
+ final Task rootTask = mRootWindowContainer.getDefaultTaskDisplayArea().getOrCreateRootTask(
+ activity, null /* options */, task, null /* sourceTask */, null /* launchParams */,
+ 0 /* launchFlags */, ACTIVITY_TYPE_STANDARD, true /* onTop */);
assertEquals(task, rootTask);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
index 168c250..c0759c1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
@@ -575,7 +575,7 @@
final TestDisplayContent fullscreenDisplay = createNewDisplayContent(
WINDOWING_MODE_FULLSCREEN);
final ActivityRecord source = createSourceActivity(fullscreenDisplay);
- source.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ source.getTask().setWindowingMode(WINDOWING_MODE_FREEFORM);
assertEquals(RESULT_CONTINUE,
new CalculateRequestBuilder().setSource(source).calculate());
@@ -951,7 +951,7 @@
final TestDisplayContent fullscreenDisplay = createNewDisplayContent(
WINDOWING_MODE_FULLSCREEN);
final ActivityRecord source = createSourceActivity(fullscreenDisplay);
- source.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ source.getTask().setWindowingMode(WINDOWING_MODE_FREEFORM);
final ActivityOptions options = ActivityOptions.makeBasic();
final Rect expected = new Rect(0, 0, 150, 150);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index d74e1be..29289a4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -713,7 +713,7 @@
closeTransition.collectExistenceChange(activity1);
closeTransition.collectExistenceChange(task2);
closeTransition.collectExistenceChange(activity2);
- closeTransition.setTransientLaunch(activity2);
+ closeTransition.setTransientLaunch(activity2, null /* restoreBelow */);
activity1.mVisibleRequested = false;
activity2.mVisibleRequested = true;
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index a442de5..5743922 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -1340,6 +1340,41 @@
}
@Test
+ public void testAddLocalInsetsSourceProvider_sameType_replacesInsets() {
+ /*
+ ___ rootTask ________________________________________
+ | | |
+ activity0 navigationBarInsetsProvider1 navigationBarInsetsProvider2
+ */
+ final Task rootTask = createTask(mDisplayContent);
+
+ final ActivityRecord activity0 = createActivityRecord(mDisplayContent,
+ createTaskInRootTask(rootTask, 0 /* userId */));
+ final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(
+ TYPE_BASE_APPLICATION);
+ attrs.setTitle("AppWindow0");
+ activity0.addWindow(createWindowState(attrs, activity0));
+
+ Rect navigationBarInsetsRect1 = new Rect(0, 200, 1080, 700);
+ Rect navigationBarInsetsRect2 = new Rect(0, 0, 1080, 200);
+
+ rootTask.addLocalRectInsetsSourceProvider(navigationBarInsetsRect1,
+ new int[]{ITYPE_LOCAL_NAVIGATION_BAR_1});
+ activity0.forAllWindows(window -> {
+ assertEquals(navigationBarInsetsRect1,
+ window.getInsetsState().peekSource(ITYPE_LOCAL_NAVIGATION_BAR_1).getFrame());
+ }, true);
+
+ rootTask.addLocalRectInsetsSourceProvider(navigationBarInsetsRect2,
+ new int[]{ITYPE_LOCAL_NAVIGATION_BAR_1});
+
+ activity0.forAllWindows(window -> {
+ assertEquals(navigationBarInsetsRect2,
+ window.getInsetsState().peekSource(ITYPE_LOCAL_NAVIGATION_BAR_1).getFrame());
+ }, true);
+ }
+
+ @Test
public void testRemoveLocalInsetsSourceProvider() {
/*
___ rootTask _______________________________________________
diff --git a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
index 0f223ca..eea3f84 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
@@ -293,7 +293,8 @@
public void testAssignWindowLayers_ForImeWithAppTargetAndAppAbove() {
final WindowState appBelowImeTarget = createWindow("appBelowImeTarget");
final WindowState imeAppTarget = createWindow("imeAppTarget");
- final WindowState appAboveImeTarget = createWindow("appAboveImeTarget");
+ final WindowState appAboveImeTarget = createWindow(imeAppTarget, TYPE_APPLICATION,
+ "appAboveImeTarget");
mDisplayContent.setImeLayeringTarget(imeAppTarget);
mDisplayContent.setImeControlTarget(imeAppTarget);
diff --git a/telephony/java/android/service/euicc/EuiccService.java b/telephony/java/android/service/euicc/EuiccService.java
index 8d92520..7129a27 100644
--- a/telephony/java/android/service/euicc/EuiccService.java
+++ b/telephony/java/android/service/euicc/EuiccService.java
@@ -29,7 +29,6 @@
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 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/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index f57c32c..1eb391d 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -48,6 +48,7 @@
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
+import android.content.ContextParams;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
@@ -143,6 +144,7 @@
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
+import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Executor;
import java.util.concurrent.RejectedExecutionException;
@@ -388,16 +390,8 @@
@UnsupportedAppUsage
public TelephonyManager(Context context, int subId) {
mSubId = subId;
- Context appContext = context.getApplicationContext();
- if (appContext != null) {
- if (Objects.equals(context.getAttributionTag(), appContext.getAttributionTag())) {
- mContext = appContext;
- } else {
- mContext = appContext.createAttributionContext(context.getAttributionTag());
- }
- } else {
- mContext = context;
- }
+ mContext = mergeAttributionAndRenouncedPermissions(context.getApplicationContext(),
+ context);
mSubscriptionManager = SubscriptionManager.from(mContext);
}
@@ -418,6 +412,34 @@
return sInstance;
}
+ // This method takes the Application context and adds the attributionTag
+ // and renouncedPermissions from the given context.
+ private Context mergeAttributionAndRenouncedPermissions(Context to, Context from) {
+ Context contextToReturn = from;
+ if (to != null) {
+ if (!Objects.equals(from.getAttributionTag(), to.getAttributionTag())) {
+ contextToReturn = to.createAttributionContext(from.getAttributionTag());
+ } else {
+ contextToReturn = to;
+ }
+
+ Set<String> renouncedPermissions =
+ from.getAttributionSource().getRenouncedPermissions();
+ if (!renouncedPermissions.isEmpty()) {
+ if (to.getParams() != null) {
+ contextToReturn = contextToReturn.createContext(
+ new ContextParams.Builder(to.getParams())
+ .setRenouncedPermissions(renouncedPermissions).build());
+ } else {
+ contextToReturn = contextToReturn.createContext(
+ new ContextParams.Builder()
+ .setRenouncedPermissions(renouncedPermissions).build());
+ }
+ }
+ }
+ return contextToReturn;
+ }
+
private String getOpPackageName() {
// For legacy reasons the TelephonyManager has API for getting
// a static instance with no context set preventing us from
@@ -448,6 +470,16 @@
return null;
}
+ private Set<String> getRenouncedPermissions() {
+ // For legacy reasons the TelephonyManager has API for getting
+ // a static instance with no context set preventing us from
+ // getting the attribution source.
+ if (mContext != null) {
+ return mContext.getAttributionSource().getRenouncedPermissions();
+ }
+ return Collections.emptySet();
+ }
+
/**
* Post a runnable to the BackgroundThread.
*
@@ -4189,7 +4221,8 @@
* {@link UiccSlotMapping} which consist of both physical slot index and port index.
* Logical slot is the slot that is seen by modem. Physical slot is the actual physical slot.
* Port index is the index (enumerated value) for the associated port available on the SIM.
- * Each physical slot can have multiple ports if multi-enabled profile(MEP) is supported.
+ * Each physical slot can have multiple ports if
+ * {@link PackageManager#FEATURE_TELEPHONY_EUICC_MEP} is supported.
*
* Example: no. of logical slots 1 and physical slots 2 do not support MEP, each physical slot
* has one port:
@@ -4285,11 +4318,11 @@
/**
* Get the mapping from logical slots to physical sim slots and port indexes. Initially the
* logical slot index was mapped to physical slot index, but with support for multi-enabled
- * profile(MEP) logical slot is now mapped to port index.
+ * profile(MEP){@link PackageManager#FEATURE_TELEPHONY_EUICC_MEP},logical slot is now mapped to
+ * port index.
*
* @return a collection of {@link UiccSlotMapping} which indicates the mapping from logical
* slots to ports and physical slots.
- *
* @hide
*/
@SystemApi
@@ -6307,8 +6340,14 @@
(TelephonyRegistryManager)
mContext.getSystemService(Context.TELEPHONY_REGISTRY_SERVICE);
if (telephonyRegistry != null) {
- telephonyRegistry.listenFromListener(mSubId, getOpPackageName(),
- getAttributionTag(), listener, events, notifyNow);
+ Set<String> renouncedPermissions = getRenouncedPermissions();
+ boolean renounceFineLocationAccess = renouncedPermissions
+ .contains(Manifest.permission.ACCESS_FINE_LOCATION);
+ boolean renounceCoarseLocationAccess = renouncedPermissions
+ .contains(Manifest.permission.ACCESS_COARSE_LOCATION);
+ telephonyRegistry.listenFromListener(mSubId, renounceFineLocationAccess,
+ renounceCoarseLocationAccess, getOpPackageName(), getAttributionTag(),
+ listener, events, notifyNow);
} else {
Rlog.w(TAG, "telephony registry not ready.");
}
@@ -12131,7 +12170,10 @@
})
@RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
public @Nullable ServiceState getServiceState() {
- return getServiceState(false, false);
+ return getServiceState(getRenouncedPermissions()
+ .contains(Manifest.permission.ACCESS_FINE_LOCATION),
+ getRenouncedPermissions()
+ .contains(Manifest.permission.ACCESS_COARSE_LOCATION));
}
/**
@@ -12143,6 +12185,11 @@
* If you want continuous updates of service state info, register a {@link PhoneStateListener}
* via {@link #listen} with the {@link PhoneStateListener#LISTEN_SERVICE_STATE} event.
*
+ * There's another way to renounce permissions with a custom context
+ * {@code AttributionSource.Builder#setRenouncedPermissions(Set<String>)} but only for system
+ * apps. To avoid confusion, calling this method supersede renouncing permissions with a
+ * custom context.
+ *
* <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
* or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges})
* and {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}.
@@ -12186,8 +12233,7 @@
ITelephony service = getITelephony();
if (service != null) {
return service.getServiceStateForSubscriber(subId, renounceFineLocationAccess,
- renounceCoarseLocationAccess,
- getOpPackageName(), getAttributionTag());
+ renounceCoarseLocationAccess, getOpPackageName(), getAttributionTag());
}
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelephony#getServiceStateForSubscriber", e);
@@ -16122,7 +16168,10 @@
*/
public void registerTelephonyCallback(@NonNull @CallbackExecutor Executor executor,
@NonNull TelephonyCallback callback) {
- registerTelephonyCallback(false, false, executor, callback);
+ registerTelephonyCallback(
+ getRenouncedPermissions().contains(Manifest.permission.ACCESS_FINE_LOCATION),
+ getRenouncedPermissions().contains(Manifest.permission.ACCESS_COARSE_LOCATION),
+ executor, callback);
}
/**
@@ -16152,6 +16201,12 @@
* instability. If a process has registered too many callbacks without unregistering them, it
* may encounter an {@link IllegalStateException} when trying to register more callbacks.
*
+ * <p>
+ * There's another way to renounce permissions with a custom context
+ * {@code AttributionSource.Builder#setRenouncedPermissions(Set<String>)} but only for system
+ * apps. To avoid confusion, calling this method supersede renouncing permissions with a
+ * custom context.
+ *
* @param renounceFineLocationAccess Set this to true if the caller would not like to receive
* location related information which will be sent if the caller already possess
* {@link android.Manifest.permission#ACCESS_FINE_LOCATION} and do not renounce the permissions.
diff --git a/telephony/java/android/telephony/UiccCardInfo.java b/telephony/java/android/telephony/UiccCardInfo.java
index 30ca162..3843a62 100644
--- a/telephony/java/android/telephony/UiccCardInfo.java
+++ b/telephony/java/android/telephony/UiccCardInfo.java
@@ -17,6 +17,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.pm.PackageManager;
import android.os.Parcel;
import android.os.Parcelable;
@@ -147,9 +148,10 @@
* Note that this field may be omitted if the caller does not have the correct permissions
* (see {@link TelephonyManager#getUiccCardsInfo()}).
*
- * @deprecated with support for MEP(multiple enabled profile), a SIM card can have more than one
- * ICCID active at the same time.Instead use {@link UiccPortInfo#getIccId()} to retrieve ICCID.
- * To find {@link UiccPortInfo} use {@link UiccCardInfo#getPorts()}
+ * @deprecated with support for MEP(multiple enabled profile)
+ * {@link PackageManager#FEATURE_TELEPHONY_EUICC_MEP}, a SIM card can have more than one
+ * ICCID active at the same time. Instead use {@link UiccPortInfo#getIccId()} to retrieve ICCID.
+ * To find {@link UiccPortInfo} use {@link UiccCardInfo#getPorts()}.
*
* @throws UnsupportedOperationException if the calling app's target SDK is T and beyond.
*/
@@ -192,11 +194,11 @@
}
/*
- * Whether the UICC card supports multiple enable profile(MEP)
+ * Whether the UICC card supports multiple enabled profile(MEP)
* UICCs are generally MEP disabled, there can be only one active profile on the physical
* sim card.
*
- * @return {@code true} if the eUICC is supporting multiple enabled profile(MEP).
+ * @return {@code true} if the UICC is supporting multiple enabled profile(MEP).
*/
public boolean isMultipleEnabledProfilesSupported() {
return mIsMultipleEnabledProfilesSupported;
@@ -205,6 +207,9 @@
/**
* Get information regarding port, ICCID and its active status.
*
+ * For device which support {@link PackageManager#FEATURE_TELEPHONY_EUICC_MEP}, it should return
+ * more than one {@link UiccPortInfo} object if the card is eUICC.
+ *
* @return Collection of {@link UiccPortInfo}
*/
public @NonNull Collection<UiccPortInfo> getPorts() {
diff --git a/telephony/java/android/telephony/UiccPortInfo.java b/telephony/java/android/telephony/UiccPortInfo.java
index d1838c0..6fb0470 100644
--- a/telephony/java/android/telephony/UiccPortInfo.java
+++ b/telephony/java/android/telephony/UiccPortInfo.java
@@ -29,7 +29,9 @@
* Per GSMA SGP.22 V3.0, a port is a logical entity to which an active UICC profile can be bound on
* a UICC card. If UICC supports 2 ports, then the port index is numbered 0,1.
* Each port index is unique within an UICC, but not necessarily unique across UICC’s.
- * For UICC's does not support MEP(Multi-enabled profile), just return the default port index 0.
+ * For UICC's does not support MEP(Multi-enabled profile)
+ * {@link android.content.pm.PackageManager#FEATURE_TELEPHONY_EUICC_MEP}, just return the default
+ * port index 0.
*/
public final class UiccPortInfo implements Parcelable{
private final String mIccId;
diff --git a/telephony/java/android/telephony/UiccSlotInfo.java b/telephony/java/android/telephony/UiccSlotInfo.java
index 17f34db..17ce450 100644
--- a/telephony/java/android/telephony/UiccSlotInfo.java
+++ b/telephony/java/android/telephony/UiccSlotInfo.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.content.pm.PackageManager;
import android.os.Parcel;
import android.os.Parcelable;
@@ -225,6 +226,9 @@
/**
* Get Information regarding port, iccid and its active status.
*
+ * For device which support {@link PackageManager#FEATURE_TELEPHONY_EUICC_MEP}, it should return
+ * more than one {@link UiccPortInfo} object if the card is eUICC.
+ *
* @return Collection of {@link UiccPortInfo}
*/
public @NonNull Collection<UiccPortInfo> getPorts() {
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index b6ae530..4820d33 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -37,6 +37,7 @@
import android.telephony.SubscriptionInfo;
import android.telephony.TelephonyFrameworkInitializer;
import android.telephony.TelephonyManager;
+import android.telephony.UiccCardInfo;
import android.telephony.euicc.EuiccCardManager.ResetOption;
import android.util.Log;
@@ -931,6 +932,21 @@
* intent to prompt the user to accept the download. The caller should also be authorized to
* manage the subscription to be downloaded.
*
+ * <p>If device support {@link PackageManager#FEATURE_TELEPHONY_EUICC_MEP} and
+ * switchAfterDownload is {@code true}, the subscription will be enabled on an esim port based
+ * on the following selection rules:
+ * <ul>
+ * <li>In SS(Single SIM) mode, if the embedded slot already has an active port, then download
+ * and enable the subscription on this port.
+ * <li>In SS mode, if the embedded slot is not active, then try to download and enable the
+ * subscription on the default port 0 of eUICC.
+ * <li>In DSDS mode, find first available port to download and enable the subscription.
+ * (see {@link #isSimPortAvailable(int)})
+ *</ul>
+ * If there is no available port, an {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR}
+ * will be returned in the callback intent to prompt the user to disable an already-active
+ * subscription.
+ *
* @param subscription the subscription to download.
* @param switchAfterDownload if true, the profile will be activated upon successful download.
* @param callbackIntent a PendingIntent to launch when the operation completes.
@@ -1141,14 +1157,25 @@
* intent to prompt the user to accept the download. The caller should also be authorized to
* manage the subscription to be enabled.
*
- * <p> From Android T, devices might support MEP(Multiple Enabled Profiles), the subscription
- * can be installed on different port from the eUICC. Calling apps with carrier privilege
- * (see {@link TelephonyManager#hasCarrierPrivileges}) over the currently active subscriptions
- * can use {@link #switchToSubscription(int, int, PendingIntent)} to specify which port to
- * enable the subscription. Otherwise, use this API to enable the subscription on the eUICC
- * and the platform will internally resolve a port. If there is no available port,
- * an {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} might be returned in the callback
- * intent to prompt the user to disable an already-active subscription.
+ * <p> From Android T, devices might support {@link PackageManager#FEATURE_TELEPHONY_EUICC_MEP},
+ * the subscription can be installed on different port from the eUICC. Calling apps with
+ * carrier privilege (see {@link TelephonyManager#hasCarrierPrivileges}) over the currently
+ * active subscriptions can use {@link #switchToSubscription(int, int, PendingIntent)} to
+ * specify which port to enable the subscription. Otherwise, use this API to enable the
+ * subscription on the eUICC and the platform will internally resolve a port based on following
+ * rules:
+ * <ul>
+ * <li>always use the default port 0 is eUICC does not support MEP.
+ * <li>In SS(Single SIM) mode, if the embedded slot already has an active port, then enable
+ * the subscription on this port.
+ * <li>In SS mode, if the embedded slot is not active, then try to enable the subscription on
+ * the default port 0 of eUICC.
+ * <li>In DSDS mode, find first available port to enable the subscription.
+ * (see {@link #isSimPortAvailable(int)})
+ *</ul>
+ * If there is no available port, an {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR}
+ * will be returned in the callback intent to prompt the user to disable an already-active
+ * subscription.
*
* @param subscriptionId the ID of the subscription to enable. May be
* {@link android.telephony.SubscriptionManager#INVALID_SUBSCRIPTION_ID} to deactivate the
@@ -1197,7 +1224,15 @@
*
* <p> If the caller is passing invalid port index,
* an {@link #EMBEDDED_SUBSCRIPTION_RESULT_ERROR} with detailed error code
- * {@link #ERROR_INVALID_PORT} will be returned.
+ * {@link #ERROR_INVALID_PORT} will be returned. The port index is invalid if one of the
+ * following requirements is met:
+ * <ul>
+ * <li>index is beyond the range of {@link UiccCardInfo#getPorts()}.
+ * <li>In SS(Single SIM) mode, the embedded slot already has an active port with different
+ * port index.
+ * <li>In DSDS mode, if the psim slot is active and the embedded slot already has an active
+ * empty port with different port index.
+ * </ul>
*
* <p> Depending on the target port and permission check,
* an {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} might be returned to the callback
@@ -1522,8 +1557,8 @@
/**
* Returns whether the passing portIndex is available.
- * A port is available if it has no profiles enabled on it or calling app has carrier privilege
- * over the profile installed on the selected port.
+ * A port is available if it is active without enabled profile on it or
+ * calling app has carrier privilege over the profile installed on the selected port.
* Always returns false if the cardId is a physical card.
*
* @param portIndex is an enumeration of the ports available on the UICC.
diff --git a/tests/AttestationVerificationTest/Android.bp b/tests/AttestationVerificationTest/Android.bp
index a4741eed..b98f8cb 100644
--- a/tests/AttestationVerificationTest/Android.bp
+++ b/tests/AttestationVerificationTest/Android.bp
@@ -40,5 +40,6 @@
"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 c42bde9..37321ad8 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 0000000..e29ff48
--- /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 0000000..3d6410a
--- /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 0000000..6d261fa
--- /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 0000000..c51851fe
--- /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 0000000..2827710
--- /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 0000000..32c2230
--- /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 6290292..169effa 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.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 @@
@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 @@
@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 @@
@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 0000000..0d15fe7
--- /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 0000000..45f2e5c
--- /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/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
index 8d60466..4cddd85 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
@@ -60,7 +60,7 @@
}
teardown {
test {
- testApp.exit()
+ testApp.exit(wmHelper)
}
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
index 7ee6451..5bd365c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
@@ -64,7 +64,6 @@
device.waitForIdle()
} else {
wmHelper.waitImeShown()
- wmHelper.waitForAppTransitionIdle()
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt
index b66c45c7..a135e0a 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt
@@ -53,8 +53,8 @@
button.click()
device.wait(Until.gone(launchActivityButton), FIND_TIMEOUT)
- wmHelper.waitForFullScreenApp(secondActivityComponent)
wmHelper.waitFor(
+ WindowManagerStateHelper.isAppFullScreen(secondActivityComponent),
WindowManagerConditionsFactory.isAppTransitionIdle(Display.DEFAULT_DISPLAY),
WindowManagerConditionsFactory.hasLayersAnimating().negate()
)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
index ba5698c..a9564fd 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
@@ -88,7 +88,7 @@
}
transitions {
device.reopenAppFromOverview(wmHelper)
- require(wmHelper.waitImeShown()) { "IME didn't show in time" }
+ wmHelper.waitImeShown()
}
teardown {
test {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt
index 19e2c92..7e3ed82 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt
@@ -18,6 +18,7 @@
import android.app.Instrumentation
import android.platform.test.annotations.Presubmit
+import android.view.Display
import android.view.Surface
import android.view.WindowManagerPolicyConstants
import androidx.test.filters.RequiresDevice
@@ -35,6 +36,8 @@
import com.android.server.wm.flicker.navBarWindowIsVisible
import com.android.server.wm.flicker.statusBarWindowIsVisible
import com.android.server.wm.traces.common.FlickerComponentName
+import com.android.server.wm.traces.common.WindowManagerConditionsFactory
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
import org.junit.FixMethodOrder
import org.junit.Test
@@ -64,12 +67,22 @@
eachRun {
this.setRotation(testSpec.startRotation)
testApp.launchViaIntent(wmHelper)
- wmHelper.waitForFullScreenApp(testApp.component)
- wmHelper.waitForAppTransitionIdle()
+ val testAppVisible = wmHelper.waitFor(
+ WindowManagerStateHelper.isAppFullScreen(testApp.component),
+ WindowManagerConditionsFactory.isAppTransitionIdle(
+ Display.DEFAULT_DISPLAY))
+ require(testAppVisible) {
+ "Expected ${testApp.component.toWindowName()} to be visible"
+ }
imeTestApp.launchViaIntent(wmHelper)
- wmHelper.waitForFullScreenApp(testApp.component)
- wmHelper.waitForAppTransitionIdle()
+ val imeAppVisible = wmHelper.waitFor(
+ WindowManagerStateHelper.isAppFullScreen(imeTestApp.component),
+ WindowManagerConditionsFactory.isAppTransitionIdle(
+ Display.DEFAULT_DISPLAY))
+ require(imeAppVisible) {
+ "Expected ${imeTestApp.component.toWindowName()} to be visible"
+ }
imeTestApp.openIME(device, wmHelper)
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt
index b5e13be..cc808a0 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt
@@ -18,6 +18,7 @@
import android.app.Instrumentation
import android.platform.test.annotations.Presubmit
+import android.view.Display
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.entireScreenCovered
@@ -30,7 +31,9 @@
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.TwoActivitiesAppHelper
import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.server.wm.traces.common.WindowManagerConditionsFactory
import com.android.server.wm.traces.parser.toFlickerComponent
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -77,14 +80,16 @@
}
teardown {
test {
- testApp.exit()
+ testApp.exit(wmHelper)
}
}
transitions {
testApp.openSecondActivity(device, wmHelper)
device.pressBack()
- wmHelper.waitForAppTransitionIdle()
- wmHelper.waitForFullScreenApp(testApp.component)
+ val firstActivityVisible = wmHelper.waitFor(
+ WindowManagerConditionsFactory.isAppTransitionIdle(Display.DEFAULT_DISPLAY),
+ WindowManagerStateHelper.isAppFullScreen(testApp.component))
+ require(firstActivityVisible) { "Expected ${testApp.component} to be visible" }
}
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
index 53560cc..4313b8d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
@@ -56,7 +56,7 @@
}
teardown {
test {
- testApp.exit()
+ testApp.exit(wmHelper)
}
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
index f21b1d6..c89e6a4 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
@@ -17,12 +17,12 @@
package com.android.server.wm.flicker.quickswitch
import android.app.Instrumentation
-import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.platform.test.annotations.RequiresDevice
import android.view.Surface
import android.view.WindowManagerPolicyConstants
import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.tapl.LauncherInstrumentation
import com.android.server.wm.flicker.FlickerBuilderProvider
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
@@ -66,6 +66,7 @@
@Group1
open class QuickSwitchBetweenTwoAppsBackTest(private val testSpec: FlickerTestParameter) {
private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val taplInstrumentation = LauncherInstrumentation()
private val testApp1 = SimpleAppHelper(instrumentation)
private val testApp2 = NonResizeableAppHelper(instrumentation)
@@ -81,6 +82,10 @@
fun buildFlicker(): FlickerBuilder {
return FlickerBuilder(instrumentation).apply {
setup {
+ test {
+ taplInstrumentation.setExpectedRotation(testSpec.startRotation)
+ }
+
eachRun {
testApp1.launchViaIntent(wmHelper)
wmHelper.waitForFullScreenApp(testApp1.component)
@@ -90,20 +95,10 @@
}
}
transitions {
- // Swipe right from bottom to quick switch back
- // NOTE: We don't perform an edge-to-edge swipe but instead only swipe in the middle
- // as to not accidentally trigger a swipe back or forward action which would result
- // in the same behavior but not testing quick swap.
- device.swipe(
- startDisplayBounds.bounds.right / 3,
- startDisplayBounds.bounds.bottom,
- 2 * startDisplayBounds.bounds.right / 3,
- startDisplayBounds.bounds.bottom,
- if (testSpec.isLandscapeOrSeascapeAtStart) 75 else 30
- )
-
+ taplInstrumentation.launchedAppState.quickSwitchToPreviousApp()
wmHelper.waitForFullScreenApp(testApp1.component)
wmHelper.waitForAppTransitionIdle()
+ wmHelper.waitForNavBarStatusBarVisible()
}
teardown {
@@ -119,7 +114,7 @@
* Checks that the transition starts with [testApp2]'s windows filling/covering exactly the
* entirety of the display.
*/
- @Postsubmit
+ @Presubmit
@Test
fun startsWithApp2WindowsCoverFullScreen() {
testSpec.assertWmStart {
@@ -131,7 +126,7 @@
* Checks that the transition starts with [testApp2]'s layers filling/covering exactly the
* entirety of the display.
*/
- @Postsubmit
+ @Presubmit
@Test
fun startsWithApp2LayersCoverFullScreen() {
testSpec.assertLayersStart {
@@ -154,7 +149,7 @@
* Checks that [testApp1] windows fill the entire screen (i.e. is "fullscreen") at the end of the
* transition once we have fully quick switched from [testApp2] back to the [testApp1].
*/
- @Postsubmit
+ @Presubmit
@Test
fun endsWithApp1WindowsCoveringFullScreen() {
testSpec.assertWmEnd {
@@ -166,7 +161,7 @@
* Checks that [testApp1] layers fill the entire screen (i.e. is "fullscreen") at the end of the
* transition once we have fully quick switched from [testApp2] back to the [testApp1].
*/
- @Postsubmit
+ @Presubmit
@Test
fun endsWithApp1LayersCoveringFullScreen() {
testSpec.assertLayersEnd {
@@ -178,7 +173,7 @@
* Checks that [testApp1] is the top window at the end of the transition once we have fully quick
* switched from [testApp2] back to the [testApp1].
*/
- @Postsubmit
+ @Presubmit
@Test
fun endsWithApp1BeingOnTop() {
testSpec.assertWmEnd {
@@ -190,7 +185,7 @@
* Checks that [testApp1]'s window starts off invisible and becomes visible at some point before
* the end of the transition and then stays visible until the end of the transition.
*/
- @Postsubmit
+ @Presubmit
@Test
fun app1WindowBecomesAndStaysVisible() {
testSpec.assertWm {
@@ -206,7 +201,7 @@
* Checks that [testApp1]'s layer starts off invisible and becomes visible at some point before
* the end of the transition and then stays visible until the end of the transition.
*/
- @Postsubmit
+ @Presubmit
@Test
fun app1LayerBecomesAndStaysVisible() {
testSpec.assertLayers {
@@ -220,7 +215,7 @@
* Checks that [testApp2]'s window starts off visible and becomes invisible at some point before
* the end of the transition and then stays invisible until the end of the transition.
*/
- @Postsubmit
+ @Presubmit
@Test
fun app2WindowBecomesAndStaysInvisible() {
testSpec.assertWm {
@@ -234,7 +229,7 @@
* Checks that [testApp2]'s layer starts off visible and becomes invisible at some point before
* the end of the transition and then stays invisible until the end of the transition.
*/
- @Postsubmit
+ @Presubmit
@Test
fun app2LayerBecomesAndStaysInvisible() {
testSpec.assertLayers {
@@ -249,7 +244,7 @@
* Ensures that at any point, either [testApp1] or [testApp2]'s windows are at least partially
* visible.
*/
- @Postsubmit
+ @Presubmit
@Test
fun app1WindowIsVisibleOnceApp2WindowIsInvisible() {
testSpec.assertWm {
@@ -269,7 +264,7 @@
* Ensures that at any point, either [testApp1] or [testApp2]'s windows are at least partially
* visible.
*/
- @Postsubmit
+ @Presubmit
@Test
fun app1LayerIsVisibleOnceApp2LayerIsInvisible() {
testSpec.assertLayers {
@@ -286,7 +281,7 @@
/**
* Checks that the navbar window is visible throughout the entire transition.
*/
- @Postsubmit
+ @Presubmit
@Test
fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsVisible()
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
index ce6a383..5d172e2 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
@@ -22,6 +22,7 @@
import android.view.Surface
import android.view.WindowManagerPolicyConstants
import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.tapl.LauncherInstrumentation
import com.android.server.wm.flicker.FlickerBuilderProvider
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
@@ -65,6 +66,7 @@
@Group1
open class QuickSwitchBetweenTwoAppsForwardTest(private val testSpec: FlickerTestParameter) {
private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val taplInstrumentation = LauncherInstrumentation()
private val testApp1 = SimpleAppHelper(instrumentation)
private val testApp2 = NonResizeableAppHelper(instrumentation)
@@ -73,6 +75,10 @@
fun buildFlicker(): FlickerBuilder {
return FlickerBuilder(instrumentation).apply {
setup {
+ test {
+ taplInstrumentation.setExpectedRotation(testSpec.startRotation)
+ }
+
eachRun {
testApp1.launchViaIntent(wmHelper)
wmHelper.waitForFullScreenApp(testApp1.component)
@@ -85,43 +91,24 @@
?.layerStackSpace
?: error("Display not found")
- // Swipe right from bottom to quick switch back
- // NOTE: We don't perform an edge-to-edge swipe but instead only swipe in the
- // middle as to not accidentally trigger a swipe back or forward action which
- // would result in the same behavior but not testing quick swap.
- device.swipe(
- startDisplayBounds.right / 3,
- startDisplayBounds.bottom,
- 2 * startDisplayBounds.right / 3,
- startDisplayBounds.bottom,
- if (testSpec.isLandscapeOrSeascapeAtStart) 75 else 30
- )
+ taplInstrumentation.launchedAppState.quickSwitchToPreviousApp()
wmHelper.waitForFullScreenApp(testApp1.component)
wmHelper.waitForAppTransitionIdle()
}
}
transitions {
- // Swipe left from bottom to quick switch forward
- // NOTE: We don't perform an edge-to-edge swipe but instead only swipe in the middle
- // as to not accidentally trigger a swipe back or forward action which would result
- // in the same behavior but not testing quick swap.
- device.swipe(
- 2 * startDisplayBounds.right / 3,
- startDisplayBounds.bottom,
- startDisplayBounds.right / 3,
- startDisplayBounds.bottom,
- if (testSpec.isLandscapeOrSeascapeAtStart) 75 else 30
- )
+ taplInstrumentation.launchedAppState.quickSwitchToPreviousAppSwipeLeft()
wmHelper.waitForFullScreenApp(testApp2.component)
wmHelper.waitForAppTransitionIdle()
+ wmHelper.waitForNavBarStatusBarVisible()
}
teardown {
test {
- testApp1.exit()
- testApp2.exit()
+ testApp1.exit(wmHelper)
+ testApp2.exit(wmHelper)
}
}
}
@@ -365,4 +352,4 @@
)
}
}
-}
\ No newline at end of file
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
index 1a762bf..e5e2404 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
@@ -22,6 +22,7 @@
import android.view.Surface
import android.view.WindowManagerPolicyConstants
import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.tapl.LauncherInstrumentation
import com.android.server.wm.flicker.FlickerBuilderProvider
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
@@ -62,13 +63,20 @@
@Group4
class QuickSwitchFromLauncherTest(private val testSpec: FlickerTestParameter) {
private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val taplInstrumentation = LauncherInstrumentation()
+
private val testApp = SimpleAppHelper(instrumentation)
+
private val startDisplayBounds = WindowUtils.getDisplayBounds(testSpec.startRotation)
@FlickerBuilderProvider
fun buildFlicker(): FlickerBuilder {
return FlickerBuilder(instrumentation).apply {
setup {
+ test {
+ taplInstrumentation.setExpectedRotation(testSpec.startRotation)
+ }
+
eachRun {
testApp.launchViaIntent(wmHelper)
device.pressHome()
@@ -77,20 +85,10 @@
}
}
transitions {
- // Swipe right from bottom to quick switch back
- // NOTE: We don't perform an edge-to-edge swipe but instead only swipe in the middle
- // as to not accidentally trigger a swipe back or forward action which would result
- // in the same behavior but not testing quick swap.
- device.swipe(
- startDisplayBounds.bounds.right / 3,
- startDisplayBounds.bounds.bottom,
- 2 * startDisplayBounds.bounds.right / 3,
- startDisplayBounds.bounds.bottom,
- 50
- )
-
+ taplInstrumentation.workspace.quickSwitchToPreviousApp()
wmHelper.waitForFullScreenApp(testApp.component)
wmHelper.waitForAppTransitionIdle()
+ wmHelper.waitForNavBarStatusBarVisible()
}
teardown {
diff --git a/tests/InputMethodStressTest/AndroidTest.xml b/tests/InputMethodStressTest/AndroidTest.xml
index b194010..fc54ca6 100644
--- a/tests/InputMethodStressTest/AndroidTest.xml
+++ b/tests/InputMethodStressTest/AndroidTest.xml
@@ -18,6 +18,11 @@
<target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="adb shell settings put secure show_ime_with_hard_keyboard 1" />
+ <option name="teardown-command" value="adb shell settings delete secure show_ime_with_hard_keyboard" />
+ </target_preparer>
+
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="InputMethodStressTest.apk" />
diff --git a/tools/bit/command.cpp b/tools/bit/command.cpp
index f95ea11..6c68e0b 100644
--- a/tools/bit/command.cpp
+++ b/tools/bit/command.cpp
@@ -192,10 +192,11 @@
if (strchr(prog, '/') != NULL) {
return execve(prog, (char*const*)argv, (char*const*)envp);
} else {
- char* pathEnv = strdup(getenv("PATH"));
- if (pathEnv == NULL) {
+ const char* pathEnvRaw = getenv("PATH");
+ if (pathEnvRaw == NULL) {
return 1;
}
+ char* pathEnv = strdup(pathEnvRaw);
char* dir = pathEnv;
while (dir) {
char* next = strchr(dir, ':');