summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb4
-rw-r--r--.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb4
-rw-r--r--.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb4
-rw-r--r--.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb4
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java6
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java96
-rw-r--r--apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java33
-rw-r--r--core/java/android/app/ActivityManager.java11
-rw-r--r--core/java/android/app/TaskInfo.java15
-rw-r--r--core/java/android/content/AttributionSource.java3
-rw-r--r--core/java/android/hardware/location/ContextHubClientCallback.java7
-rw-r--r--core/java/android/hardware/location/ContextHubManager.java3
-rw-r--r--core/java/android/os/Debug.java4
-rw-r--r--core/java/android/speech/RecognitionService.java15
-rw-r--r--core/jni/Android.bp1
-rw-r--r--core/jni/android_os_Debug.cpp33
-rw-r--r--core/res/res/values-is/strings.xml4
-rw-r--r--core/res/res/values-zh-rCN/strings.xml6
-rw-r--r--libs/hwui/Readback.cpp6
-rw-r--r--libs/hwui/pipeline/skia/SkiaPipeline.cpp8
-rw-r--r--libs/hwui/renderthread/DrawFrameTask.cpp6
-rw-r--r--media/java/android/media/tv/tuner/Lnb.java21
-rw-r--r--media/java/android/media/tv/tuner/Tuner.java223
-rw-r--r--media/java/android/media/tv/tuner/dvr/DvrPlayback.java13
-rw-r--r--media/java/android/media/tv/tuner/dvr/DvrRecorder.java13
-rw-r--r--media/java/android/media/tv/tuner/filter/Filter.java23
-rw-r--r--packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml2
-rw-r--r--packages/CtsShim/apk/arm/CtsShim.apkbin5490 -> 5488 bytes
-rw-r--r--packages/CtsShim/apk/arm/CtsShimPriv.apkbin31631 -> 31623 bytes
-rw-r--r--packages/CtsShim/apk/x86/CtsShim.apkbin5490 -> 5488 bytes
-rw-r--r--packages/CtsShim/apk/x86/CtsShimPriv.apkbin24252 -> 24264 bytes
-rw-r--r--packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp1
-rw-r--r--packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java26
-rw-r--r--packages/SystemUI/animation/Android.bp1
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt26
-rw-r--r--packages/SystemUI/res/drawable/fingerprint_bg.xml3
-rw-r--r--packages/SystemUI/res/layout/status_bar_expanded.xml20
-rw-r--r--packages/SystemUI/res/values-mr/strings.xml2
-rw-r--r--packages/SystemUI/res/values-te/strings.xml3
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskInfoCompat.java67
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java10
-rw-r--r--packages/SystemUI/src/com/android/keyguard/LockIconView.java96
-rw-r--r--packages/SystemUI/src/com/android/keyguard/LockIconViewController.java12
-rw-r--r--packages/SystemUI/src/com/android/keyguard/NumPadButton.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java104
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt22
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java81
-rw-r--r--services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java33
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java17
-rw-r--r--services/core/java/com/android/server/am/AppProfiler.java6
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java14
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java23
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java22
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java23
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java9
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java34
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java104
-rw-r--r--services/core/java/com/android/server/stats/pull/SystemMemoryUtil.java6
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java5
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java4
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java1
-rw-r--r--services/core/java/com/android/server/wm/Task.java15
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java5
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java157
-rw-r--r--services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java444
70 files changed, 1440 insertions, 565 deletions
diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb
index 3258514cb6d7..0ccd9511d945 100644
--- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb
+++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb
@@ -1,6 +1,6 @@
drops {
android_build_drop {
- build_id: "7533747"
+ build_id: "7552332"
target: "CtsShim"
source_file: "aosp_arm64/CtsShimPriv.apk"
}
@@ -10,4 +10,6 @@ drops {
git_project: "platform/frameworks/base"
git_branch: "sc-dev"
transform: TRANSFORM_NONE
+ transform_options {
+ }
}
diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb
index 4fb50e22989c..7e85c8f6697d 100644
--- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb
+++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb
@@ -1,6 +1,6 @@
drops {
android_build_drop {
- build_id: "7533747"
+ build_id: "7552332"
target: "CtsShim"
source_file: "aosp_arm64/CtsShim.apk"
}
@@ -10,4 +10,6 @@ drops {
git_project: "platform/frameworks/base"
git_branch: "sc-dev"
transform: TRANSFORM_NONE
+ transform_options {
+ }
}
diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb
index 1a0e3185665a..20c27858e9ab 100644
--- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb
+++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb
@@ -1,6 +1,6 @@
drops {
android_build_drop {
- build_id: "7533747"
+ build_id: "7552332"
target: "CtsShim"
source_file: "aosp_x86_64/CtsShimPriv.apk"
}
@@ -10,4 +10,6 @@ drops {
git_project: "platform/frameworks/base"
git_branch: "sc-dev"
transform: TRANSFORM_NONE
+ transform_options {
+ }
}
diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb
index d72f62e52148..13e3ae5b121b 100644
--- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb
+++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb
@@ -1,6 +1,6 @@
drops {
android_build_drop {
- build_id: "7533747"
+ build_id: "7552332"
target: "CtsShim"
source_file: "aosp_x86_64/CtsShim.apk"
}
@@ -10,4 +10,6 @@ drops {
git_project: "platform/frameworks/base"
git_branch: "sc-dev"
transform: TRANSFORM_NONE
+ transform_options {
+ }
}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
index b52a503a2166..666d49770a70 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
@@ -795,7 +795,7 @@ public class AppSearchManagerService extends SystemService {
AppSearchUserInstance instance =
mAppSearchUserInstanceManager.getUserInstance(callingUser);
SearchResultPage searchResultPage =
- instance.getAppSearchImpl().getNextPage(nextPageToken);
+ instance.getAppSearchImpl().getNextPage(packageName, nextPageToken);
invokeCallbackOnResult(
callback,
AppSearchResult.newSuccessfulResult(searchResultPage.getBundle()));
@@ -821,7 +821,7 @@ public class AppSearchManagerService extends SystemService {
verifyNotInstantApp(userContext, packageName);
AppSearchUserInstance instance =
mAppSearchUserInstanceManager.getUserInstance(callingUser);
- instance.getAppSearchImpl().invalidateNextPageToken(nextPageToken);
+ instance.getAppSearchImpl().invalidateNextPageToken(packageName, nextPageToken);
} catch (Throwable t) {
Log.e(TAG, "Unable to invalidate the query page token", t);
}
@@ -871,7 +871,7 @@ public class AppSearchManagerService extends SystemService {
.getGenericDocument().getBundle());
}
searchResultPage = instance.getAppSearchImpl().getNextPage(
- searchResultPage.getNextPageToken());
+ packageName, searchResultPage.getNextPageToken());
}
}
invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null));
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
index a1b93ce12975..830e76c62279 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
@@ -173,6 +173,21 @@ public final class AppSearchImpl implements Closeable {
@GuardedBy("mReadWriteLock")
private final Map<String, Integer> mDocumentCountMapLocked = new ArrayMap<>();
+ // Maps packages to the set of valid nextPageTokens that the package can manipulate. A token
+ // is unique and constant per query (i.e. the same token '123' is used to iterate through
+ // pages of search results). The tokens themselves are generated and tracked by
+ // IcingSearchEngine. IcingSearchEngine considers a token valid and won't be reused
+ // until we call invalidateNextPageToken on the token.
+ //
+ // Note that we synchronize on itself because the nextPageToken cache is checked at
+ // query-time, and queries are done in parallel with a read lock. Ideally, this would be
+ // guarded by the normal mReadWriteLock.writeLock, but ReentrantReadWriteLocks can't upgrade
+ // read to write locks. This lock should be acquired at the smallest scope possible.
+ // mReadWriteLock is a higher-level lock, so calls shouldn't be made out
+ // to any functions that grab the lock.
+ @GuardedBy("mNextPageTokensLocked")
+ private final Map<String, Set<Long>> mNextPageTokensLocked = new ArrayMap<>();
+
/**
* The counter to check when to call {@link #checkForOptimize}. The interval is {@link
* #CHECK_OPTIMIZE_INTERVAL}.
@@ -837,12 +852,15 @@ public final class AppSearchImpl implements Closeable {
String prefix = createPrefix(packageName, databaseName);
Set<String> allowedPrefixedSchemas = getAllowedPrefixSchemasLocked(prefix, searchSpec);
- return doQueryLocked(
- Collections.singleton(createPrefix(packageName, databaseName)),
- allowedPrefixedSchemas,
- queryExpression,
- searchSpec,
- sStatsBuilder);
+ SearchResultPage searchResultPage =
+ doQueryLocked(
+ Collections.singleton(createPrefix(packageName, databaseName)),
+ allowedPrefixedSchemas,
+ queryExpression,
+ searchSpec,
+ sStatsBuilder);
+ addNextPageToken(packageName, searchResultPage.getNextPageToken());
+ return searchResultPage;
} finally {
mReadWriteLock.readLock().unlock();
if (logger != null) {
@@ -956,12 +974,15 @@ public final class AppSearchImpl implements Closeable {
}
}
- return doQueryLocked(
- prefixFilters,
- prefixedSchemaFilters,
- queryExpression,
- searchSpec,
- sStatsBuilder);
+ SearchResultPage searchResultPage =
+ doQueryLocked(
+ prefixFilters,
+ prefixedSchemaFilters,
+ queryExpression,
+ searchSpec,
+ sStatsBuilder);
+ addNextPageToken(callerPackageName, searchResultPage.getNextPageToken());
+ return searchResultPage;
} finally {
mReadWriteLock.readLock().unlock();
@@ -1093,17 +1114,20 @@ public final class AppSearchImpl implements Closeable {
*
* <p>This method belongs to query group.
*
+ * @param packageName Package name of the caller.
* @param nextPageToken The token of pre-loaded results of previously executed query.
* @return The next page of results of previously executed query.
- * @throws AppSearchException on IcingSearchEngine error.
+ * @throws AppSearchException on IcingSearchEngine error or if can't advance on nextPageToken.
*/
@NonNull
- public SearchResultPage getNextPage(long nextPageToken) throws AppSearchException {
+ public SearchResultPage getNextPage(@NonNull String packageName, long nextPageToken)
+ throws AppSearchException {
mReadWriteLock.readLock().lock();
try {
throwIfClosedLocked();
mLogUtil.piiTrace("getNextPage, request", nextPageToken);
+ checkNextPageToken(packageName, nextPageToken);
SearchResultProto searchResultProto =
mIcingSearchEngineLocked.getNextPage(nextPageToken);
mLogUtil.piiTrace(
@@ -1122,16 +1146,26 @@ public final class AppSearchImpl implements Closeable {
*
* <p>This method belongs to query group.
*
+ * @param packageName Package name of the caller.
* @param nextPageToken The token of pre-loaded results of previously executed query to be
* Invalidated.
+ * @throws AppSearchException if nextPageToken is unusable.
*/
- public void invalidateNextPageToken(long nextPageToken) {
+ public void invalidateNextPageToken(@NonNull String packageName, long nextPageToken)
+ throws AppSearchException {
mReadWriteLock.readLock().lock();
try {
throwIfClosedLocked();
mLogUtil.piiTrace("invalidateNextPageToken, request", nextPageToken);
+ checkNextPageToken(packageName, nextPageToken);
mIcingSearchEngineLocked.invalidateNextPageToken(nextPageToken);
+
+ synchronized (mNextPageTokensLocked) {
+ // At this point, we're guaranteed that this nextPageToken exists for this package,
+ // otherwise checkNextPageToken would've thrown an exception.
+ mNextPageTokensLocked.get(packageName).remove(nextPageToken);
+ }
} finally {
mReadWriteLock.readLock().unlock();
}
@@ -1568,6 +1602,9 @@ public final class AppSearchImpl implements Closeable {
Set<String> databaseNames = entry.getValue();
if (!installedPackages.contains(packageName) && databaseNames != null) {
mDocumentCountMapLocked.remove(packageName);
+ synchronized (mNextPageTokensLocked) {
+ mNextPageTokensLocked.remove(packageName);
+ }
for (String databaseName : databaseNames) {
String removedPrefix = createPrefix(packageName, databaseName);
mSchemaMapLocked.remove(removedPrefix);
@@ -1601,6 +1638,9 @@ public final class AppSearchImpl implements Closeable {
mSchemaMapLocked.clear();
mNamespaceMapLocked.clear();
mDocumentCountMapLocked.clear();
+ synchronized (mNextPageTokensLocked) {
+ mNextPageTokensLocked.clear();
+ }
if (initStatsBuilder != null) {
initStatsBuilder
.setHasReset(true)
@@ -2015,6 +2055,32 @@ public final class AppSearchImpl implements Closeable {
return schemaProto.getSchema();
}
+ private void addNextPageToken(String packageName, long nextPageToken) {
+ synchronized (mNextPageTokensLocked) {
+ Set<Long> tokens = mNextPageTokensLocked.get(packageName);
+ if (tokens == null) {
+ tokens = new ArraySet<>();
+ mNextPageTokensLocked.put(packageName, tokens);
+ }
+ tokens.add(nextPageToken);
+ }
+ }
+
+ private void checkNextPageToken(String packageName, long nextPageToken)
+ throws AppSearchException {
+ synchronized (mNextPageTokensLocked) {
+ Set<Long> nextPageTokens = mNextPageTokensLocked.get(packageName);
+ if (nextPageTokens == null || !nextPageTokens.contains(nextPageToken)) {
+ throw new AppSearchException(
+ AppSearchResult.RESULT_SECURITY_ERROR,
+ "Package \""
+ + packageName
+ + "\" cannot use nextPageToken: "
+ + nextPageToken);
+ }
+ }
+ }
+
private static void addToMap(
Map<String, Set<String>> map, String prefix, String prefixedValue) {
Set<String> values = map.get(prefix);
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index ed80ddbd2cd7..9f529548833d 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -256,6 +256,7 @@ public class AlarmManagerService extends SystemService {
AlarmHandler mHandler;
AppWakeupHistory mAppWakeupHistory;
AppWakeupHistory mAllowWhileIdleHistory;
+ AppWakeupHistory mAllowWhileIdleCompatHistory;
private final SparseLongArray mLastPriorityAlarmDispatch = new SparseLongArray();
private final SparseArray<RingBuffer<RemovedAlarm>> mRemovalHistory = new SparseArray<>();
ClockReceiver mClockReceiver;
@@ -1633,6 +1634,7 @@ public class AlarmManagerService extends SystemService {
mAppWakeupHistory = new AppWakeupHistory(Constants.DEFAULT_APP_STANDBY_WINDOW);
mAllowWhileIdleHistory = new AppWakeupHistory(INTERVAL_HOUR);
+ mAllowWhileIdleCompatHistory = new AppWakeupHistory(INTERVAL_HOUR);
mNextWakeup = mNextNonWakeup = 0;
@@ -2142,20 +2144,23 @@ public class AlarmManagerService extends SystemService {
final int userId = UserHandle.getUserId(alarm.creatorUid);
final int quota;
final long window;
+ final AppWakeupHistory history;
if ((alarm.flags & FLAG_ALLOW_WHILE_IDLE) != 0) {
quota = mConstants.ALLOW_WHILE_IDLE_QUOTA;
window = mConstants.ALLOW_WHILE_IDLE_WINDOW;
+ history = mAllowWhileIdleHistory;
} else {
quota = mConstants.ALLOW_WHILE_IDLE_COMPAT_QUOTA;
window = mConstants.ALLOW_WHILE_IDLE_COMPAT_WINDOW;
+ history = mAllowWhileIdleCompatHistory;
}
- final int dispatchesInWindow = mAllowWhileIdleHistory.getTotalWakeupsInWindow(
+ final int dispatchesInHistory = history.getTotalWakeupsInWindow(
alarm.sourcePackage, userId);
- if (dispatchesInWindow < quota) {
+ if (dispatchesInHistory < quota) {
// fine to go out immediately.
batterySaverPolicyElapsed = nowElapsed;
} else {
- batterySaverPolicyElapsed = mAllowWhileIdleHistory.getNthLastWakeupForPackage(
+ batterySaverPolicyElapsed = history.getNthLastWakeupForPackage(
alarm.sourcePackage, userId, quota) + window;
}
} else if ((alarm.flags & FLAG_PRIORITIZE) != 0) {
@@ -2201,20 +2206,23 @@ public class AlarmManagerService extends SystemService {
final int userId = UserHandle.getUserId(alarm.creatorUid);
final int quota;
final long window;
+ final AppWakeupHistory history;
if ((alarm.flags & FLAG_ALLOW_WHILE_IDLE) != 0) {
quota = mConstants.ALLOW_WHILE_IDLE_QUOTA;
window = mConstants.ALLOW_WHILE_IDLE_WINDOW;
+ history = mAllowWhileIdleHistory;
} else {
quota = mConstants.ALLOW_WHILE_IDLE_COMPAT_QUOTA;
window = mConstants.ALLOW_WHILE_IDLE_COMPAT_WINDOW;
+ history = mAllowWhileIdleCompatHistory;
}
- final int dispatchesInWindow = mAllowWhileIdleHistory.getTotalWakeupsInWindow(
+ final int dispatchesInHistory = history.getTotalWakeupsInWindow(
alarm.sourcePackage, userId);
- if (dispatchesInWindow < quota) {
+ if (dispatchesInHistory < quota) {
// fine to go out immediately.
deviceIdlePolicyTime = nowElapsed;
} else {
- final long whenInQuota = mAllowWhileIdleHistory.getNthLastWakeupForPackage(
+ final long whenInQuota = history.getNthLastWakeupForPackage(
alarm.sourcePackage, userId, quota) + window;
deviceIdlePolicyTime = Math.min(whenInQuota, mPendingIdleUntil.getWhenElapsed());
}
@@ -2502,6 +2510,7 @@ public class AlarmManagerService extends SystemService {
Binder.getCallingPid(), callingUid, "AlarmManager.setPrioritized");
// The API doesn't allow using both together.
flags &= ~FLAG_ALLOW_WHILE_IDLE;
+ // Prioritized alarms don't need any extra permission to be exact.
} else if (exact || allowWhileIdle) {
final boolean needsPermission;
boolean lowerQuota;
@@ -2992,6 +3001,10 @@ public class AlarmManagerService extends SystemService {
mAllowWhileIdleHistory.dump(pw, nowELAPSED);
pw.println();
+ pw.println("Allow while idle compat history:");
+ mAllowWhileIdleCompatHistory.dump(pw, nowELAPSED);
+ pw.println();
+
if (mLastPriorityAlarmDispatch.size() > 0) {
pw.println("Last priority alarm dispatches:");
pw.increaseIndent();
@@ -4553,6 +4566,7 @@ public class AlarmManagerService extends SystemService {
removeUserLocked(userHandle);
mAppWakeupHistory.removeForUser(userHandle);
mAllowWhileIdleHistory.removeForUser(userHandle);
+ mAllowWhileIdleCompatHistory.removeForUser(userHandle);
}
return;
case Intent.ACTION_UID_REMOVED:
@@ -4588,6 +4602,8 @@ public class AlarmManagerService extends SystemService {
// package-removed and package-restarted case
mAppWakeupHistory.removeForPackage(pkg, UserHandle.getUserId(uid));
mAllowWhileIdleHistory.removeForPackage(pkg, UserHandle.getUserId(uid));
+ mAllowWhileIdleCompatHistory.removeForPackage(pkg,
+ UserHandle.getUserId(uid));
removeLocked(uid, REMOVE_REASON_UNDEFINED);
} else {
// external-applications-unavailable case
@@ -4965,7 +4981,10 @@ public class AlarmManagerService extends SystemService {
if (isAllowedWhileIdleRestricted(alarm)) {
// Record the last time this uid handled an ALLOW_WHILE_IDLE alarm while the
// device was in doze or battery saver.
- mAllowWhileIdleHistory.recordAlarmForPackage(alarm.sourcePackage,
+ final AppWakeupHistory history = ((alarm.flags & FLAG_ALLOW_WHILE_IDLE) != 0)
+ ? mAllowWhileIdleHistory
+ : mAllowWhileIdleCompatHistory;
+ history.recordAlarmForPackage(alarm.sourcePackage,
UserHandle.getUserId(alarm.creatorUid), nowELAPSED);
mAlarmStore.updateAlarmDeliveries(a -> {
if (a.creatorUid != alarm.creatorUid || !isAllowedWhileIdleRestricted(a)) {
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 91e2d88ad7cb..4376d225e676 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -406,6 +406,12 @@ public class ActivityManager {
public static final int BROADCAST_FAILED_USER_STOPPED = -2;
/**
+ * Type for IActivityManaqer.getIntentSender: this PendingIntent type is unknown.
+ * @hide
+ */
+ public static final int INTENT_SENDER_UNKNOWN = 0;
+
+ /**
* Type for IActivityManaqer.getIntentSender: this PendingIntent is
* for a sendBroadcast operation.
* @hide
@@ -4860,12 +4866,12 @@ public class ActivityManager {
*/
public static final class PendingIntentInfo implements Parcelable {
- private final String mCreatorPackage;
+ @Nullable private final String mCreatorPackage;
private final int mCreatorUid;
private final boolean mImmutable;
private final int mIntentSenderType;
- public PendingIntentInfo(String creatorPackage, int creatorUid, boolean immutable,
+ public PendingIntentInfo(@Nullable String creatorPackage, int creatorUid, boolean immutable,
int intentSenderType) {
mCreatorPackage = creatorPackage;
mCreatorUid = creatorUid;
@@ -4873,6 +4879,7 @@ public class ActivityManager {
mIntentSenderType = intentSenderType;
}
+ @Nullable
public String getCreatorPackage() {
return mCreatorPackage;
}
diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java
index 444cc4eedcb1..85758a92fa98 100644
--- a/core/java/android/app/TaskInfo.java
+++ b/core/java/android/app/TaskInfo.java
@@ -28,11 +28,13 @@ import android.content.LocusId;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Point;
+import android.graphics.Rect;
import android.os.Build;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.util.Log;
+import android.view.DisplayCutout;
import android.window.TaskSnapshot;
import android.window.WindowContainerToken;
@@ -174,6 +176,15 @@ public class TaskInfo {
public PictureInPictureParams pictureInPictureParams;
/**
+ * The {@link Rect} copied from {@link DisplayCutout#getSafeInsets()} if the cutout is not of
+ * (LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES, LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS),
+ * {@code null} otherwise.
+ * @hide
+ */
+ @Nullable
+ public Rect displayCutoutInsets;
+
+ /**
* The activity type of the top activity in this task.
* @hide
*/
@@ -332,6 +343,7 @@ public class TaskInfo {
&& supportsMultiWindow == that.supportsMultiWindow
&& Objects.equals(positionInParent, that.positionInParent)
&& Objects.equals(pictureInPictureParams, that.pictureInPictureParams)
+ && Objects.equals(displayCutoutInsets, that.displayCutoutInsets)
&& getWindowingMode() == that.getWindowingMode()
&& Objects.equals(taskDescription, that.taskDescription)
&& isFocused == that.isFocused
@@ -382,6 +394,7 @@ public class TaskInfo {
token = WindowContainerToken.CREATOR.createFromParcel(source);
topActivityType = source.readInt();
pictureInPictureParams = source.readTypedObject(PictureInPictureParams.CREATOR);
+ displayCutoutInsets = source.readTypedObject(Rect.CREATOR);
topActivityInfo = source.readTypedObject(ActivityInfo.CREATOR);
isResizeable = source.readBoolean();
source.readBinderList(launchCookies);
@@ -419,6 +432,7 @@ public class TaskInfo {
token.writeToParcel(dest, flags);
dest.writeInt(topActivityType);
dest.writeTypedObject(pictureInPictureParams, flags);
+ dest.writeTypedObject(displayCutoutInsets, flags);
dest.writeTypedObject(topActivityInfo, flags);
dest.writeBoolean(isResizeable);
dest.writeBinderList(launchCookies);
@@ -447,6 +461,7 @@ public class TaskInfo {
+ " token=" + token
+ " topActivityType=" + topActivityType
+ " pictureInPictureParams=" + pictureInPictureParams
+ + " displayCutoutSafeInsets=" + displayCutoutInsets
+ " topActivityInfo=" + topActivityInfo
+ " launchCookies=" + launchCookies
+ " positionInParent=" + positionInParent
diff --git a/core/java/android/content/AttributionSource.java b/core/java/android/content/AttributionSource.java
index 0e22705146af..bdb7900b5bb9 100644
--- a/core/java/android/content/AttributionSource.java
+++ b/core/java/android/content/AttributionSource.java
@@ -252,7 +252,8 @@ public final class AttributionSource implements Parcelable {
*/
public boolean checkCallingUid() {
final int callingUid = Binder.getCallingUid();
- if (callingUid != Process.SYSTEM_UID
+ if (callingUid != Process.ROOT_UID
+ && callingUid != Process.SYSTEM_UID
&& callingUid != mAttributionSourceState.uid) {
return false;
}
diff --git a/core/java/android/hardware/location/ContextHubClientCallback.java b/core/java/android/hardware/location/ContextHubClientCallback.java
index 35d00f03de67..9309c5b0d8e3 100644
--- a/core/java/android/hardware/location/ContextHubClientCallback.java
+++ b/core/java/android/hardware/location/ContextHubClientCallback.java
@@ -68,8 +68,11 @@ public class ContextHubClientCallback {
/**
* Callback invoked when a nanoapp is dynamically loaded at the attached Context Hub through
- * the {@link android.hardware.location.ContextHubManager}. This callback is not invoked for a
- * nanoapp that is loaded internally by CHRE (e.g. nanoapps that are preloaded by the system).
+ * the {@link android.hardware.location.ContextHubManager}.
+ *
+ * NOTE: This callback is <b>not</b> invoked for a nanoapp that is loaded internally by CHRE
+ * (e.g. nanoapps that are preloaded by the system). To check the availability of these
+ * nanoapps, use the {@link ContextHubManager#queryNanoApps(ContextHubInfo)} API.
*
* @param client the client that is associated with this callback
* @param nanoAppId the ID of the nanoapp that had been loaded
diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
index f69a7d7e5f16..9af0e09ee97a 100644
--- a/core/java/android/hardware/location/ContextHubManager.java
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -128,7 +128,8 @@ public final class ContextHubManager {
public static final int AUTHORIZATION_GRANTED = 2;
/**
- * Constants describing the type of events from a Context Hub.
+ * Constants describing the type of events from a Context Hub, as defined in
+ * {@link ContextHubClientCallback}.
* {@hide}
*/
@Retention(RetentionPolicy.SOURCE)
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index d90e129d36f7..b4930fa931eb 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -2599,11 +2599,11 @@ public final class Debug
public static native long getIonPoolsSizeKb();
/**
- * Return GPU DMA buffer usage in kB or -1 on error.
+ * Returns the global total GPU-private memory in kB or -1 on error.
*
* @hide
*/
- public static native long getGpuDmaBufUsageKb();
+ public static native long getGpuPrivateMemoryKb();
/**
* Return DMA-BUF memory mapped by processes in kB.
diff --git a/core/java/android/speech/RecognitionService.java b/core/java/android/speech/RecognitionService.java
index a6ec399e7d30..362ea8c87f7f 100644
--- a/core/java/android/speech/RecognitionService.java
+++ b/core/java/android/speech/RecognitionService.java
@@ -115,18 +115,14 @@ public abstract class RecognitionService extends Service {
@NonNull AttributionSource attributionSource) {
try {
if (mCurrentCallback == null) {
- Context attributionContext = createContext(new ContextParams.Builder()
- .setNextAttributionSource(attributionSource)
- .build());
boolean preflightPermissionCheckPassed = checkPermissionForPreflight(
- attributionContext.getAttributionSource());
+ attributionSource);
if (preflightPermissionCheckPassed) {
if (DBG) {
Log.d(TAG, "created new mCurrentCallback, listener = "
+ listener.asBinder());
}
- mCurrentCallback = new Callback(listener, attributionSource,
- attributionContext);
+ mCurrentCallback = new Callback(listener, attributionSource);
RecognitionService.this.onStartListening(intent, mCurrentCallback);
}
@@ -293,15 +289,8 @@ public abstract class RecognitionService extends Service {
private Callback(IRecognitionListener listener,
@NonNull AttributionSource attributionSource) {
- this(listener, attributionSource, null);
- }
-
- private Callback(IRecognitionListener listener,
- @NonNull AttributionSource attributionSource,
- @Nullable Context attributionContext) {
mListener = listener;
mCallingAttributionSource = attributionSource;
- mAttributionContext = attributionContext;
}
/**
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 125182cab254..91a19e087bf1 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -237,7 +237,6 @@ cc_library_shared {
],
shared_libs: [
- "android.hardware.memtrack-V1-ndk_platform",
"audioclient-types-aidl-cpp",
"audioflinger-aidl-cpp",
"av-types-aidl-cpp",
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 41804480122c..4c2b114c724a 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -33,7 +33,6 @@
#include <string>
#include <vector>
-#include <aidl/android/hardware/memtrack/DeviceInfo.h>
#include <android-base/logging.h>
#include <bionic/malloc.h>
#include <debuggerd/client.h>
@@ -46,7 +45,6 @@
#include "jni.h"
#include <dmabufinfo/dmabuf_sysfs_stats.h>
#include <dmabufinfo/dmabufinfo.h>
-#include <dmabufinfo/dmabuf_sysfs_stats.h>
#include <meminfo/procmeminfo.h>
#include <meminfo/sysmeminfo.h>
#include <memtrack/memtrack.h>
@@ -861,29 +859,24 @@ static jlong android_os_Debug_getDmabufHeapPoolsSizeKb(JNIEnv* env, jobject claz
return poolsSizeKb;
}
-static jlong android_os_Debug_getGpuDmaBufUsageKb(JNIEnv* env, jobject clazz) {
- std::vector<aidl::android::hardware::memtrack::DeviceInfo> gpu_device_info;
- if (!memtrack_gpu_device_info(&gpu_device_info)) {
+static jlong android_os_Debug_getGpuPrivateMemoryKb(JNIEnv* env, jobject clazz) {
+ struct memtrack_proc* p = memtrack_proc_new();
+ if (p == nullptr) {
+ LOG(ERROR) << "getGpuPrivateMemoryKb: Failed to create memtrack_proc";
return -1;
}
- dmabufinfo::DmabufSysfsStats stats;
- if (!GetDmabufSysfsStats(&stats)) {
+ // Memtrack hal defines PID 0 as global total for GPU-private (GL) memory.
+ if (memtrack_proc_get(p, 0) != 0) {
+ // The memtrack HAL may not be available, avoid flooding the log.
+ memtrack_proc_destroy(p);
return -1;
}
- jlong sizeKb = 0;
- const auto& importer_stats = stats.importer_info();
- for (const auto& dev_info : gpu_device_info) {
- const auto& importer_info = importer_stats.find(dev_info.name);
- if (importer_info == importer_stats.end()) {
- continue;
- }
-
- sizeKb += importer_info->second.size / 1024;
- }
+ ssize_t gpuPrivateMem = memtrack_proc_gl_pss(p);
- return sizeKb;
+ memtrack_proc_destroy(p);
+ return gpuPrivateMem / 1024;
}
static jlong android_os_Debug_getDmabufMappedSizeKb(JNIEnv* env, jobject clazz) {
@@ -994,8 +987,8 @@ static const JNINativeMethod gMethods[] = {
(void*)android_os_Debug_getIonHeapsSizeKb },
{ "getDmabufTotalExportedKb", "()J",
(void*)android_os_Debug_getDmabufTotalExportedKb },
- { "getGpuDmaBufUsageKb", "()J",
- (void*)android_os_Debug_getGpuDmaBufUsageKb },
+ { "getGpuPrivateMemoryKb", "()J",
+ (void*)android_os_Debug_getGpuPrivateMemoryKb },
{ "getDmabufHeapTotalExportedKb", "()J",
(void*)android_os_Debug_getDmabufHeapTotalExportedKb },
{ "getIonPoolsSizeKb", "()J",
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 667dd9c46055..93e25a6b014e 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -2287,10 +2287,10 @@
<string name="window_magnification_prompt_content" msgid="8159173903032344891">"Nú geturðu stækkað hluta skjásins"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Kveikja á í stillingum"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Hunsa"</string>
- <string name="sensor_privacy_start_use_mic_notification_content_title" msgid="2420858361276370367">"Opna á hljóðnema tækisins"</string>
+ <string name="sensor_privacy_start_use_mic_notification_content_title" msgid="2420858361276370367">"Opna fyrir hljóðnema tækisins"</string>
<string name="sensor_privacy_start_use_camera_notification_content_title" msgid="7287720213963466672">"Opna fyrir myndavél tækisins"</string>
<string name="sensor_privacy_start_use_notification_content_text" msgid="7595608891015777346">"Fyrir &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; og öll forrit og þjónustur"</string>
- <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7089318886628390827">"Opna á"</string>
+ <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7089318886628390827">"Opna fyrir"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Persónuvernd skynjara"</string>
<string name="splash_screen_view_icon_description" msgid="180638751260598187">"Forritstákn"</string>
<string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Mynd af merki forrits"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 51395222e24c..68a5ce7ee349 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -142,7 +142,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"WLAN"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"WLAN 通话"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <string name="wifi_calling_off_summary" msgid="5626710010766902560">"关闭"</string>
+ <string name="wifi_calling_off_summary" msgid="5626710010766902560">"已关闭"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"通过 WLAN 进行通话"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"通过移动网络进行通话"</string>
<string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"仅限 WLAN"</string>
@@ -1696,8 +1696,8 @@
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"同时按住两个音量键几秒钟,即可开启<xliff:g id="SERVICE">%1$s</xliff:g>无障碍功能。这样做可能会改变您设备的工作方式。\n\n您可以在“设置”&gt;“无障碍”中将此快捷方式更改为开启另一项功能。"</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"开启"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"不开启"</string>
- <string name="accessibility_shortcut_menu_item_status_on" msgid="6608392117189732543">"开启"</string>
- <string name="accessibility_shortcut_menu_item_status_off" msgid="5531598275559472393">"关闭"</string>
+ <string name="accessibility_shortcut_menu_item_status_on" msgid="6608392117189732543">"已开启"</string>
+ <string name="accessibility_shortcut_menu_item_status_off" msgid="5531598275559472393">"已关闭"</string>
<string name="accessibility_enable_service_title" msgid="3931558336268541484">"要允许<xliff:g id="SERVICE">%1$s</xliff:g>完全控制您的设备吗?"</string>
<string name="accessibility_enable_service_encryption_warning" msgid="8603532708618236909">"如果您开启<xliff:g id="SERVICE">%1$s</xliff:g>,您的设备将无法使用屏幕锁定功能来增强数据加密效果。"</string>
<string name="accessibility_service_warning_description" msgid="291674995220940133">"对于能满足您的无障碍功能需求的应用,可授予其完全控制权限;但对大部分应用来说,都不适合授予此权限。"</string>
diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp
index d8735ce57b65..a743d30939d0 100644
--- a/libs/hwui/Readback.cpp
+++ b/libs/hwui/Readback.cpp
@@ -183,8 +183,10 @@ CopyResult Readback::copySurfaceInto(ANativeWindow* window, const Rect& inSrcRec
SkPaint paint;
paint.setAlpha(255);
paint.setBlendMode(SkBlendMode::kSrc);
- canvas->drawImageRect(image, imageSrcRect, imageDstRect, sampling, &paint,
- SkCanvas::kFast_SrcRectConstraint);
+ const bool hasBufferCrop = cropRect.left < cropRect.right && cropRect.top < cropRect.bottom;
+ auto constraint =
+ hasBufferCrop ? SkCanvas::kStrict_SrcRectConstraint : SkCanvas::kFast_SrcRectConstraint;
+ canvas->drawImageRect(image, imageSrcRect, imageDstRect, sampling, &paint, constraint);
canvas->restore();
if (!tmpSurface->readPixels(*bitmap, 0, 0)) {
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 44a6e4354608..4e7471d5d888 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -207,12 +207,16 @@ bool SkiaPipeline::createOrUpdateLayer(RenderNode* node, const DamageAccumulator
void SkiaPipeline::prepareToDraw(const RenderThread& thread, Bitmap* bitmap) {
GrDirectContext* context = thread.getGrContext();
- if (context) {
+ if (context && !bitmap->isHardware()) {
ATRACE_FORMAT("Bitmap#prepareToDraw %dx%d", bitmap->width(), bitmap->height());
auto image = bitmap->makeImage();
- if (image.get() && !bitmap->isHardware()) {
+ if (image.get()) {
SkImage_pinAsTexture(image.get(), context);
SkImage_unpinAsTexture(image.get(), context);
+ // A submit is necessary as there may not be a frame coming soon, so without a call
+ // to submit these texture uploads can just sit in the queue building up until
+ // we run out of RAM
+ context->flushAndSubmit();
}
}
}
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index 5c4b9019b0ad..db29e342855b 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -130,6 +130,12 @@ void DrawFrameTask::run() {
if (CC_LIKELY(canDrawThisFrame)) {
dequeueBufferDuration = context->draw();
} else {
+ // Do a flush in case syncFrameState performed any texture uploads. Since we skipped
+ // the draw() call, those uploads (or deletes) will end up sitting in the queue.
+ // Do them now
+ if (GrDirectContext* grContext = mRenderThread->getGrContext()) {
+ grContext->flushAndSubmit();
+ }
// wait on fences so tasks don't overlap next frame
context->waitOnFences();
}
diff --git a/media/java/android/media/tv/tuner/Lnb.java b/media/java/android/media/tv/tuner/Lnb.java
index 59ef4b890320..8b69d33722c5 100644
--- a/media/java/android/media/tv/tuner/Lnb.java
+++ b/media/java/android/media/tv/tuner/Lnb.java
@@ -148,6 +148,7 @@ public class Lnb implements AutoCloseable {
LnbCallback mCallback;
Executor mExecutor;
Tuner mTuner;
+ private final Object mCallbackLock = new Object();
private native int nativeSetVoltage(int voltage);
@@ -164,20 +165,26 @@ public class Lnb implements AutoCloseable {
private Lnb() {}
void setCallback(Executor executor, @Nullable LnbCallback callback, Tuner tuner) {
- mCallback = callback;
- mExecutor = executor;
- mTuner = tuner;
+ synchronized (mCallbackLock) {
+ mCallback = callback;
+ mExecutor = executor;
+ mTuner = tuner;
+ }
}
private void onEvent(int eventType) {
- if (mExecutor != null && mCallback != null) {
- mExecutor.execute(() -> mCallback.onEvent(eventType));
+ synchronized (mCallbackLock) {
+ if (mExecutor != null && mCallback != null) {
+ mExecutor.execute(() -> mCallback.onEvent(eventType));
+ }
}
}
private void onDiseqcMessage(byte[] diseqcMessage) {
- if (mExecutor != null && mCallback != null) {
- mExecutor.execute(() -> mCallback.onDiseqcMessage(diseqcMessage));
+ synchronized (mCallbackLock) {
+ if (mExecutor != null && mCallback != null) {
+ mExecutor.execute(() -> mCallback.onDiseqcMessage(diseqcMessage));
+ }
}
}
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 2ea745b44288..325436648e63 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -291,7 +291,7 @@ public class Tuner implements AutoCloseable {
@Nullable
private OnTuneEventListener mOnTuneEventListener;
@Nullable
- private Executor mOnTunerEventExecutor;
+ private Executor mOnTuneEventExecutor;
@Nullable
private ScanCallback mScanCallback;
@Nullable
@@ -301,6 +301,10 @@ public class Tuner implements AutoCloseable {
@Nullable
private Executor mOnResourceLostListenerExecutor;
+ private final Object mOnTuneEventLock = new Object();
+ private final Object mScanCallbackLock = new Object();
+ private final Object mOnResourceLostListenerLock = new Object();
+
private Integer mDemuxHandle;
private Integer mFrontendCiCamHandle;
private Integer mFrontendCiCamId;
@@ -398,18 +402,22 @@ public class Tuner implements AutoCloseable {
*/
public void setResourceLostListener(@NonNull @CallbackExecutor Executor executor,
@NonNull OnResourceLostListener listener) {
- Objects.requireNonNull(executor, "OnResourceLostListener must not be null");
- Objects.requireNonNull(listener, "executor must not be null");
- mOnResourceLostListener = listener;
- mOnResourceLostListenerExecutor = executor;
+ synchronized (mOnResourceLostListenerLock) {
+ Objects.requireNonNull(executor, "OnResourceLostListener must not be null");
+ Objects.requireNonNull(listener, "executor must not be null");
+ mOnResourceLostListener = listener;
+ mOnResourceLostListenerExecutor = executor;
+ }
}
/**
* Removes the listener for resource lost.
*/
public void clearResourceLostListener() {
- mOnResourceLostListener = null;
- mOnResourceLostListenerExecutor = null;
+ synchronized (mOnResourceLostListenerLock) {
+ mOnResourceLostListener = null;
+ mOnResourceLostListenerExecutor = null;
+ }
}
/**
@@ -618,10 +626,12 @@ public class Tuner implements AutoCloseable {
break;
}
case MSG_RESOURCE_LOST: {
- if (mOnResourceLostListener != null
+ synchronized (mOnResourceLostListenerLock) {
+ if (mOnResourceLostListener != null
&& mOnResourceLostListenerExecutor != null) {
- mOnResourceLostListenerExecutor.execute(
- () -> mOnResourceLostListener.onResourceLost(Tuner.this));
+ mOnResourceLostListenerExecutor.execute(
+ () -> mOnResourceLostListener.onResourceLost(Tuner.this));
+ }
}
break;
}
@@ -652,8 +662,10 @@ public class Tuner implements AutoCloseable {
*/
public void setOnTuneEventListener(@NonNull @CallbackExecutor Executor executor,
@NonNull OnTuneEventListener eventListener) {
- mOnTuneEventListener = eventListener;
- mOnTunerEventExecutor = executor;
+ synchronized (mOnTuneEventLock) {
+ mOnTuneEventListener = eventListener;
+ mOnTuneEventExecutor = executor;
+ }
}
/**
@@ -663,9 +675,10 @@ public class Tuner implements AutoCloseable {
* @see #setOnTuneEventListener(Executor, OnTuneEventListener)
*/
public void clearOnTuneEventListener() {
- mOnTuneEventListener = null;
- mOnTunerEventExecutor = null;
-
+ synchronized (mOnTuneEventLock) {
+ mOnTuneEventListener = null;
+ mOnTuneEventExecutor = null;
+ }
}
/**
@@ -747,32 +760,34 @@ public class Tuner implements AutoCloseable {
@Result
public int scan(@NonNull FrontendSettings settings, @ScanType int scanType,
@NonNull @CallbackExecutor Executor executor, @NonNull ScanCallback scanCallback) {
- /**
- * Scan can be called again for blink scan if scanCallback and executor are same as before.
- */
- if (((mScanCallback != null) && (mScanCallback != scanCallback))
+ synchronized (mScanCallbackLock) {
+ // Scan can be called again for blink scan if scanCallback and executor are same as
+ //before.
+ if (((mScanCallback != null) && (mScanCallback != scanCallback))
|| ((mScanCallbackExecutor != null) && (mScanCallbackExecutor != executor))) {
- throw new IllegalStateException(
+ throw new IllegalStateException(
"Different Scan session already in progress. stopScan must be called "
+ "before a new scan session can be " + "started.");
- }
- mFrontendType = settings.getType();
- if (mFrontendType == FrontendSettings.TYPE_DTMB) {
- if (!TunerVersionChecker.checkHigherOrEqualVersionTo(
- TunerVersionChecker.TUNER_VERSION_1_1, "Scan with DTMB Frontend")) {
- return RESULT_UNAVAILABLE;
}
- }
- if (checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND)) {
- mScanCallback = scanCallback;
- mScanCallbackExecutor = executor;
- mFrontendInfo = null;
- FrameworkStatsLog
+ mFrontendType = settings.getType();
+ if (mFrontendType == FrontendSettings.TYPE_DTMB) {
+ if (!TunerVersionChecker.checkHigherOrEqualVersionTo(
+ TunerVersionChecker.TUNER_VERSION_1_1,
+ "Scan with DTMB Frontend")) {
+ return RESULT_UNAVAILABLE;
+ }
+ }
+ if (checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND)) {
+ mScanCallback = scanCallback;
+ mScanCallbackExecutor = executor;
+ mFrontendInfo = null;
+ FrameworkStatsLog
.write(FrameworkStatsLog.TV_TUNER_STATE_CHANGED, mUserId,
FrameworkStatsLog.TV_TUNER_STATE_CHANGED__STATE__SCANNING);
- return nativeScan(settings.getType(), settings, scanType);
+ return nativeScan(settings.getType(), settings, scanType);
+ }
+ return RESULT_UNAVAILABLE;
}
- return RESULT_UNAVAILABLE;
}
/**
@@ -788,14 +803,15 @@ public class Tuner implements AutoCloseable {
*/
@Result
public int cancelScanning() {
- FrameworkStatsLog
- .write(FrameworkStatsLog.TV_TUNER_STATE_CHANGED, mUserId,
+ synchronized (mScanCallbackLock) {
+ FrameworkStatsLog.write(FrameworkStatsLog.TV_TUNER_STATE_CHANGED, mUserId,
FrameworkStatsLog.TV_TUNER_STATE_CHANGED__STATE__SCAN_STOPPED);
- int retVal = nativeStopScan();
- mScanCallback = null;
- mScanCallbackExecutor = null;
- return retVal;
+ int retVal = nativeStopScan();
+ mScanCallback = null;
+ mScanCallbackExecutor = null;
+ return retVal;
+ }
}
private boolean requestFrontend() {
@@ -1050,8 +1066,10 @@ public class Tuner implements AutoCloseable {
private void onFrontendEvent(int eventType) {
Log.d(TAG, "Got event from tuning. Event type: " + eventType);
- if (mOnTunerEventExecutor != null && mOnTuneEventListener != null) {
- mOnTunerEventExecutor.execute(() -> mOnTuneEventListener.onTuneEvent(eventType));
+ synchronized (mOnTuneEventLock) {
+ if (mOnTuneEventExecutor != null && mOnTuneEventListener != null) {
+ mOnTuneEventExecutor.execute(() -> mOnTuneEventListener.onTuneEvent(eventType));
+ }
}
Log.d(TAG, "Wrote Stats Log for the events from tuning.");
@@ -1072,114 +1090,149 @@ public class Tuner implements AutoCloseable {
private void onLocked() {
Log.d(TAG, "Wrote Stats Log for locked event from scanning.");
- FrameworkStatsLog
- .write(FrameworkStatsLog.TV_TUNER_STATE_CHANGED, mUserId,
- FrameworkStatsLog.TV_TUNER_STATE_CHANGED__STATE__LOCKED);
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.TV_TUNER_STATE_CHANGED, mUserId,
+ FrameworkStatsLog.TV_TUNER_STATE_CHANGED__STATE__LOCKED);
- if (mScanCallbackExecutor != null && mScanCallback != null) {
- mScanCallbackExecutor.execute(() -> mScanCallback.onLocked());
+ synchronized (mScanCallbackLock) {
+ if (mScanCallbackExecutor != null && mScanCallback != null) {
+ mScanCallbackExecutor.execute(() -> mScanCallback.onLocked());
+ }
}
}
private void onScanStopped() {
- if (mScanCallbackExecutor != null && mScanCallback != null) {
- mScanCallbackExecutor.execute(() -> mScanCallback.onScanStopped());
+ synchronized (mScanCallbackLock) {
+ if (mScanCallbackExecutor != null && mScanCallback != null) {
+ mScanCallbackExecutor.execute(() -> mScanCallback.onScanStopped());
+ }
}
}
private void onProgress(int percent) {
- if (mScanCallbackExecutor != null && mScanCallback != null) {
- mScanCallbackExecutor.execute(() -> mScanCallback.onProgress(percent));
+ synchronized (mScanCallbackLock) {
+ if (mScanCallbackExecutor != null && mScanCallback != null) {
+ mScanCallbackExecutor.execute(() -> mScanCallback.onProgress(percent));
+ }
}
}
private void onFrequenciesReport(int[] frequency) {
- if (mScanCallbackExecutor != null && mScanCallback != null) {
- mScanCallbackExecutor.execute(() -> mScanCallback.onFrequenciesReported(frequency));
+ synchronized (mScanCallbackLock) {
+ if (mScanCallbackExecutor != null && mScanCallback != null) {
+ mScanCallbackExecutor.execute(() -> mScanCallback.onFrequenciesReported(frequency));
+ }
}
}
private void onSymbolRates(int[] rate) {
- if (mScanCallbackExecutor != null && mScanCallback != null) {
- mScanCallbackExecutor.execute(() -> mScanCallback.onSymbolRatesReported(rate));
+ synchronized (mScanCallbackLock) {
+ if (mScanCallbackExecutor != null && mScanCallback != null) {
+ mScanCallbackExecutor.execute(() -> mScanCallback.onSymbolRatesReported(rate));
+ }
}
}
private void onHierarchy(int hierarchy) {
- if (mScanCallbackExecutor != null && mScanCallback != null) {
- mScanCallbackExecutor.execute(() -> mScanCallback.onHierarchyReported(hierarchy));
+ synchronized (mScanCallbackLock) {
+ if (mScanCallbackExecutor != null && mScanCallback != null) {
+ mScanCallbackExecutor.execute(() -> mScanCallback.onHierarchyReported(hierarchy));
+ }
}
}
private void onSignalType(int signalType) {
- if (mScanCallbackExecutor != null && mScanCallback != null) {
- mScanCallbackExecutor.execute(() -> mScanCallback.onSignalTypeReported(signalType));
+ synchronized (mScanCallbackLock) {
+ if (mScanCallbackExecutor != null && mScanCallback != null) {
+ mScanCallbackExecutor.execute(() -> mScanCallback.onSignalTypeReported(signalType));
+ }
}
}
private void onPlpIds(int[] plpIds) {
- if (mScanCallbackExecutor != null && mScanCallback != null) {
- mScanCallbackExecutor.execute(() -> mScanCallback.onPlpIdsReported(plpIds));
+ synchronized (mScanCallbackLock) {
+ if (mScanCallbackExecutor != null && mScanCallback != null) {
+ mScanCallbackExecutor.execute(() -> mScanCallback.onPlpIdsReported(plpIds));
+ }
}
}
private void onGroupIds(int[] groupIds) {
- if (mScanCallbackExecutor != null && mScanCallback != null) {
- mScanCallbackExecutor.execute(() -> mScanCallback.onGroupIdsReported(groupIds));
+ synchronized (mScanCallbackLock) {
+ if (mScanCallbackExecutor != null && mScanCallback != null) {
+ mScanCallbackExecutor.execute(() -> mScanCallback.onGroupIdsReported(groupIds));
+ }
}
}
private void onInputStreamIds(int[] inputStreamIds) {
- if (mScanCallbackExecutor != null && mScanCallback != null) {
- mScanCallbackExecutor.execute(
- () -> mScanCallback.onInputStreamIdsReported(inputStreamIds));
+ synchronized (mScanCallbackLock) {
+ if (mScanCallbackExecutor != null && mScanCallback != null) {
+ mScanCallbackExecutor.execute(
+ () -> mScanCallback.onInputStreamIdsReported(inputStreamIds));
+ }
}
}
private void onDvbsStandard(int dvbsStandandard) {
- if (mScanCallbackExecutor != null && mScanCallback != null) {
- mScanCallbackExecutor.execute(
- () -> mScanCallback.onDvbsStandardReported(dvbsStandandard));
+ synchronized (mScanCallbackLock) {
+ if (mScanCallbackExecutor != null && mScanCallback != null) {
+ mScanCallbackExecutor.execute(
+ () -> mScanCallback.onDvbsStandardReported(dvbsStandandard));
+ }
}
}
private void onDvbtStandard(int dvbtStandard) {
- if (mScanCallbackExecutor != null && mScanCallback != null) {
- mScanCallbackExecutor.execute(() -> mScanCallback.onDvbtStandardReported(dvbtStandard));
+ synchronized (mScanCallbackLock) {
+ if (mScanCallbackExecutor != null && mScanCallback != null) {
+ mScanCallbackExecutor.execute(
+ () -> mScanCallback.onDvbtStandardReported(dvbtStandard));
+ }
}
}
private void onAnalogSifStandard(int sif) {
- if (mScanCallbackExecutor != null && mScanCallback != null) {
- mScanCallbackExecutor.execute(() -> mScanCallback.onAnalogSifStandardReported(sif));
+ synchronized (mScanCallbackLock) {
+ if (mScanCallbackExecutor != null && mScanCallback != null) {
+ mScanCallbackExecutor.execute(() -> mScanCallback.onAnalogSifStandardReported(sif));
+ }
}
}
private void onAtsc3PlpInfos(Atsc3PlpInfo[] atsc3PlpInfos) {
- if (mScanCallbackExecutor != null && mScanCallback != null) {
- mScanCallbackExecutor.execute(
- () -> mScanCallback.onAtsc3PlpInfosReported(atsc3PlpInfos));
+ synchronized (mScanCallbackLock) {
+ if (mScanCallbackExecutor != null && mScanCallback != null) {
+ mScanCallbackExecutor.execute(
+ () -> mScanCallback.onAtsc3PlpInfosReported(atsc3PlpInfos));
+ }
}
}
private void onModulationReported(int modulation) {
- if (mScanCallbackExecutor != null && mScanCallback != null) {
- mScanCallbackExecutor.execute(
- () -> mScanCallback.onModulationReported(modulation));
+ synchronized (mScanCallbackLock) {
+ if (mScanCallbackExecutor != null && mScanCallback != null) {
+ mScanCallbackExecutor.execute(
+ () -> mScanCallback.onModulationReported(modulation));
+ }
}
}
private void onPriorityReported(boolean isHighPriority) {
- if (mScanCallbackExecutor != null && mScanCallback != null) {
- mScanCallbackExecutor.execute(
- () -> mScanCallback.onPriorityReported(isHighPriority));
+ synchronized (mScanCallbackLock) {
+ if (mScanCallbackExecutor != null && mScanCallback != null) {
+ mScanCallbackExecutor.execute(
+ () -> mScanCallback.onPriorityReported(isHighPriority));
+ }
}
}
private void onDvbcAnnexReported(int dvbcAnnex) {
- if (mScanCallbackExecutor != null && mScanCallback != null) {
- mScanCallbackExecutor.execute(
- () -> mScanCallback.onDvbcAnnexReported(dvbcAnnex));
+ synchronized (mScanCallbackLock) {
+ if (mScanCallbackExecutor != null && mScanCallback != null) {
+ mScanCallbackExecutor.execute(
+ () -> mScanCallback.onDvbcAnnexReported(dvbcAnnex));
+ }
}
}
diff --git a/media/java/android/media/tv/tuner/dvr/DvrPlayback.java b/media/java/android/media/tv/tuner/dvr/DvrPlayback.java
index d70b8c29622e..1f805d761d49 100644
--- a/media/java/android/media/tv/tuner/dvr/DvrPlayback.java
+++ b/media/java/android/media/tv/tuner/dvr/DvrPlayback.java
@@ -85,6 +85,7 @@ public class DvrPlayback implements AutoCloseable {
private static int sInstantId = 0;
private int mSegmentId = 0;
private int mUnderflow;
+ private final Object mListenerLock = new Object();
private native int nativeAttachFilter(Filter filter);
private native int nativeDetachFilter(Filter filter);
@@ -106,16 +107,20 @@ public class DvrPlayback implements AutoCloseable {
/** @hide */
public void setListener(
@NonNull Executor executor, @NonNull OnPlaybackStatusChangedListener listener) {
- mExecutor = executor;
- mListener = listener;
+ synchronized (mListenerLock) {
+ mExecutor = executor;
+ mListener = listener;
+ }
}
private void onPlaybackStatusChanged(int status) {
if (status == PLAYBACK_STATUS_EMPTY) {
mUnderflow++;
}
- if (mExecutor != null && mListener != null) {
- mExecutor.execute(() -> mListener.onPlaybackStatusChanged(status));
+ synchronized (mListenerLock) {
+ if (mExecutor != null && mListener != null) {
+ mExecutor.execute(() -> mListener.onPlaybackStatusChanged(status));
+ }
}
}
diff --git a/media/java/android/media/tv/tuner/dvr/DvrRecorder.java b/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
index 0f9f2e7f89a1..2b694668eb03 100644
--- a/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
+++ b/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
@@ -48,6 +48,7 @@ public class DvrRecorder implements AutoCloseable {
private int mSegmentId = 0;
private int mOverflow;
private Boolean mIsStopped = true;
+ private final Object mListenerLock = new Object();
private native int nativeAttachFilter(Filter filter);
private native int nativeDetachFilter(Filter filter);
@@ -69,16 +70,20 @@ public class DvrRecorder implements AutoCloseable {
/** @hide */
public void setListener(
@NonNull Executor executor, @NonNull OnRecordStatusChangedListener listener) {
- mExecutor = executor;
- mListener = listener;
+ synchronized (mListenerLock) {
+ mExecutor = executor;
+ mListener = listener;
+ }
}
private void onRecordStatusChanged(int status) {
if (status == Filter.STATUS_OVERFLOW) {
mOverflow++;
}
- if (mExecutor != null && mListener != null) {
- mExecutor.execute(() -> mListener.onRecordStatusChanged(status));
+ synchronized (mListenerLock) {
+ if (mExecutor != null && mListener != null) {
+ mExecutor.execute(() -> mListener.onRecordStatusChanged(status));
+ }
}
}
diff --git a/media/java/android/media/tv/tuner/filter/Filter.java b/media/java/android/media/tv/tuner/filter/Filter.java
index 2f3e2d8d5dd9..33742ffd99bf 100644
--- a/media/java/android/media/tv/tuner/filter/Filter.java
+++ b/media/java/android/media/tv/tuner/filter/Filter.java
@@ -227,6 +227,7 @@ public class Filter implements AutoCloseable {
private long mNativeContext;
private FilterCallback mCallback;
private Executor mExecutor;
+ private final Object mCallbackLock = new Object();
private final long mId;
private int mMainType;
private int mSubtype;
@@ -253,14 +254,18 @@ public class Filter implements AutoCloseable {
}
private void onFilterStatus(int status) {
- if (mCallback != null && mExecutor != null) {
- mExecutor.execute(() -> mCallback.onFilterStatusChanged(this, status));
+ synchronized (mCallbackLock) {
+ if (mCallback != null && mExecutor != null) {
+ mExecutor.execute(() -> mCallback.onFilterStatusChanged(this, status));
+ }
}
}
private void onFilterEvent(FilterEvent[] events) {
- if (mCallback != null && mExecutor != null) {
- mExecutor.execute(() -> mCallback.onFilterEvent(this, events));
+ synchronized (mCallbackLock) {
+ if (mCallback != null && mExecutor != null) {
+ mExecutor.execute(() -> mCallback.onFilterEvent(this, events));
+ }
}
}
@@ -272,13 +277,17 @@ public class Filter implements AutoCloseable {
/** @hide */
public void setCallback(FilterCallback cb, Executor executor) {
- mCallback = cb;
- mExecutor = executor;
+ synchronized (mCallbackLock) {
+ mCallback = cb;
+ mExecutor = executor;
+ }
}
/** @hide */
public FilterCallback getCallback() {
- return mCallback;
+ synchronized (mCallbackLock) {
+ return mCallback;
+ }
}
/**
diff --git a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
index 2cf872cc7c71..1dcd3375c1cf 100644
--- a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
@@ -20,7 +20,7 @@
<string name="chooser_title" msgid="2262294130493605839">"Choisissez un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> qui sera géré par &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"appareil"</string>
<string name="profile_name_watch" msgid="576290739483672360">"montre"</string>
- <string name="confirmation_title" msgid="8455544820286920304">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pour gérer votre &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="confirmation_title" msgid="8455544820286920304">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à gérer votre &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_summary" msgid="2059360676631420073">"Cette application est nécessaire pour gérer votre <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
<string name="consent_yes" msgid="8344487259618762872">"Autoriser"</string>
<string name="consent_no" msgid="2640796915611404382">"Ne pas autoriser"</string>
diff --git a/packages/CtsShim/apk/arm/CtsShim.apk b/packages/CtsShim/apk/arm/CtsShim.apk
index e88e1ba97ca7..0c3c4bb24208 100644
--- a/packages/CtsShim/apk/arm/CtsShim.apk
+++ b/packages/CtsShim/apk/arm/CtsShim.apk
Binary files differ
diff --git a/packages/CtsShim/apk/arm/CtsShimPriv.apk b/packages/CtsShim/apk/arm/CtsShimPriv.apk
index f35732cec024..ee42d081f2f2 100644
--- a/packages/CtsShim/apk/arm/CtsShimPriv.apk
+++ b/packages/CtsShim/apk/arm/CtsShimPriv.apk
Binary files differ
diff --git a/packages/CtsShim/apk/x86/CtsShim.apk b/packages/CtsShim/apk/x86/CtsShim.apk
index e88e1ba97ca7..0c3c4bb24208 100644
--- a/packages/CtsShim/apk/x86/CtsShim.apk
+++ b/packages/CtsShim/apk/x86/CtsShim.apk
Binary files differ
diff --git a/packages/CtsShim/apk/x86/CtsShimPriv.apk b/packages/CtsShim/apk/x86/CtsShimPriv.apk
index 3d9f749f4e48..2bb3750b200d 100644
--- a/packages/CtsShim/apk/x86/CtsShimPriv.apk
+++ b/packages/CtsShim/apk/x86/CtsShimPriv.apk
Binary files differ
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp b/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
index e50019680deb..2f911c4e6546 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
@@ -18,6 +18,7 @@ android_library {
"androidx.core_core",
"com.google.android.material_material",
"SettingsLibSettingsTransition",
+ "SettingsLibUtils",
],
sdk_version: "system_current",
min_sdk_version: "29",
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java
index a1cd37189b51..84a6b36e3d7c 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java
@@ -28,6 +28,8 @@ import androidx.annotation.Nullable;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.fragment.app.FragmentActivity;
+import com.android.settingslib.utils.BuildCompatUtils;
+
import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.appbar.CollapsingToolbarLayout;
import com.google.android.material.resources.TextAppearanceConfig;
@@ -44,10 +46,15 @@ public class CollapsingToolbarBaseActivity extends FragmentActivity {
private CollapsingToolbarLayout mCollapsingToolbarLayout;
@Nullable
private AppBarLayout mAppBarLayout;
+ private int mCustomizeLayoutResId = 0;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ if (mCustomizeLayoutResId > 0 && !BuildCompatUtils.isAtLeastS()) {
+ super.setContentView(mCustomizeLayoutResId);
+ return;
+ }
// Force loading font synchronously for collapsing toolbar layout
TextAppearanceConfig.setShouldLoadFontSynchronously(true);
super.setContentView(R.layout.collapsing_toolbar_base_layout);
@@ -81,12 +88,27 @@ public class CollapsingToolbarBaseActivity extends FragmentActivity {
@Override
public void setContentView(View view) {
- ((ViewGroup) findViewById(R.id.content_frame)).addView(view);
+ final ViewGroup parent = findViewById(R.id.content_frame);
+ if (parent != null) {
+ parent.addView(view);
+ }
}
@Override
public void setContentView(View view, ViewGroup.LayoutParams params) {
- ((ViewGroup) findViewById(R.id.content_frame)).addView(view, params);
+ final ViewGroup parent = findViewById(R.id.content_frame);
+ if (parent != null) {
+ parent.addView(view, params);
+ }
+ }
+
+ /**
+ * This method allows an activity to replace the default layout with a customize layout. Notice
+ * that it will no longer apply the features being provided by this class when this method
+ * gets called.
+ */
+ protected void setCustomizeContentView(int layoutResId) {
+ mCustomizeLayoutResId = layoutResId;
}
@Override
diff --git a/packages/SystemUI/animation/Android.bp b/packages/SystemUI/animation/Android.bp
index 761b1f460bb5..1b15d20d2c52 100644
--- a/packages/SystemUI/animation/Android.bp
+++ b/packages/SystemUI/animation/Android.bp
@@ -36,7 +36,6 @@ android_library {
static_libs: [
"PluginCoreLib",
- "WindowManager-Shell",
],
manifest: "AndroidManifest.xml",
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 8505a6254b28..a50efd731cf6 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
@@ -7,6 +7,7 @@ import android.app.ActivityManager
import android.app.ActivityTaskManager
import android.app.AppGlobals
import android.app.PendingIntent
+import android.app.TaskInfo
import android.content.Context
import android.graphics.Matrix
import android.graphics.PorterDuff
@@ -30,8 +31,6 @@ import android.view.animation.AnimationUtils
import android.view.animation.PathInterpolator
import com.android.internal.annotations.VisibleForTesting
import com.android.internal.policy.ScreenDecorationsUtils
-import com.android.wm.shell.startingsurface.SplashscreenContentDrawer
-import com.android.wm.shell.startingsurface.StartingSurface
import kotlin.math.roundToInt
private const val TAG = "ActivityLaunchAnimator"
@@ -41,8 +40,7 @@ private const val TAG = "ActivityLaunchAnimator"
* nicely into the starting window.
*/
class ActivityLaunchAnimator(
- private val keyguardHandler: KeyguardHandler,
- private val startingSurface: StartingSurface?,
+ private val callback: Callback,
context: Context
) {
companion object {
@@ -120,7 +118,7 @@ class ActivityLaunchAnimator(
Log.d(TAG, "Starting intent with a launch animation")
val runner = Runner(controller)
- val isOnKeyguard = keyguardHandler.isOnKeyguard()
+ val isOnKeyguard = callback.isOnKeyguard()
// Pass the RemoteAnimationAdapter to the intent starter only if we are not on the keyguard.
val animationAdapter = if (!isOnKeyguard) {
@@ -163,7 +161,7 @@ class ActivityLaunchAnimator(
// Hide the keyguard using the launch animation instead of the default unlock animation.
if (isOnKeyguard) {
- keyguardHandler.hideKeyguardWithAnimation(runner)
+ callback.hideKeyguardWithAnimation(runner)
}
}
}
@@ -212,7 +210,7 @@ class ActivityLaunchAnimator(
fun startPendingIntent(animationAdapter: RemoteAnimationAdapter?): Int
}
- interface KeyguardHandler {
+ interface Callback {
/** Whether we are currently on the keyguard or not. */
fun isOnKeyguard(): Boolean
@@ -221,6 +219,9 @@ class ActivityLaunchAnimator(
/** Enable/disable window blur so they don't overlap with the window launch animation **/
fun setBlursDisabledForAppLaunch(disabled: Boolean)
+
+ /* Get the background color of [task]. */
+ fun getBackgroundColor(task: TaskInfo): Int
}
/**
@@ -484,12 +485,7 @@ class ActivityLaunchAnimator(
// which is usually the same color of the app background. We first fade in this layer
// to hide the expanding view, then we fade it out with SRC mode to draw a hole in the
// launch container and reveal the opening window.
- val windowBackgroundColor = if (startingSurface != null) {
- startingSurface.getBackgroundColor(window.taskInfo)
- } else {
- Log.w(TAG, "No starting surface, defaulting to SystemBGColor")
- SplashscreenContentDrawer.getSystemBGColor()
- }
+ val windowBackgroundColor = callback.getBackgroundColor(window.taskInfo)
val windowBackgroundLayer = GradientDrawable().apply {
setColor(windowBackgroundColor)
alpha = 0
@@ -505,7 +501,7 @@ class ActivityLaunchAnimator(
animator.addListener(object : AnimatorListenerAdapter() {
override fun onAnimationStart(animation: Animator?, isReverse: Boolean) {
Log.d(TAG, "Animation started")
- keyguardHandler.setBlursDisabledForAppLaunch(true)
+ callback.setBlursDisabledForAppLaunch(true)
controller.onLaunchAnimationStart(isExpandingFullyAbove)
// Add the drawable to the launch container overlay. Overlays always draw
@@ -516,7 +512,7 @@ class ActivityLaunchAnimator(
override fun onAnimationEnd(animation: Animator?) {
Log.d(TAG, "Animation ended")
- keyguardHandler.setBlursDisabledForAppLaunch(false)
+ callback.setBlursDisabledForAppLaunch(false)
iCallback?.invoke()
controller.onLaunchAnimationEnd(isExpandingFullyAbove)
launchContainerOverlay.remove(windowBackgroundLayer)
diff --git a/packages/SystemUI/res/drawable/fingerprint_bg.xml b/packages/SystemUI/res/drawable/fingerprint_bg.xml
index 2b0ab6f9a8d2..558ec08b2ceb 100644
--- a/packages/SystemUI/res/drawable/fingerprint_bg.xml
+++ b/packages/SystemUI/res/drawable/fingerprint_bg.xml
@@ -14,10 +14,11 @@
-->
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:shape="oval">
<solid
- android:color="?android:attr/colorBackground"/>
+ android:color="?androidprv:attr/colorSurface"/>
<size
android:width="64dp"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 1a912023e33c..b0f1f487b260 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -55,9 +55,23 @@
android:id="@+id/lock_icon_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:padding="48px"
- android:layout_gravity="center"
- android:scaleType="centerCrop"/>
+ android:layout_gravity="center">
+ <!-- Background protection -->
+ <ImageView
+ android:id="@+id/lock_icon_bg"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@drawable/fingerprint_bg"
+ android:visibility="invisible"/>
+
+ <ImageView
+ android:id="@+id/lock_icon"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:padding="48px"
+ android:layout_gravity="center"
+ android:scaleType="centerCrop"/>
+ </com.android.keyguard.LockIconView>
<com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 2e6f01b515e3..cd3966d46276 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -275,7 +275,7 @@
<string name="accessibility_quick_settings_location_off" msgid="6122523378294740598">"स्थान अहवाल बंद."</string>
<string name="accessibility_quick_settings_location_on" msgid="6869947200325467243">"स्थान अहवाल सुरू."</string>
<string name="accessibility_quick_settings_location_changed_off" msgid="5132776369388699133">"स्थान अहवाल बंद केला."</string>
- <string name="accessibility_quick_settings_location_changed_on" msgid="7159115433070112154">"स्थान अहवाल सुरू केला."</string>
+ <string name="accessibility_quick_settings_location_changed_on" msgid="7159115433070112154">"स्थान अहवाल देणे सुरू केले."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"<xliff:g id="TIME">%s</xliff:g> साठी अलार्म सेट केला."</string>
<string name="accessibility_quick_settings_close" msgid="2974895537860082341">"पॅनल बंद करा."</string>
<string name="accessibility_quick_settings_more_time" msgid="7646479831704665284">"अधिक वेळ."</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 409eced5a67d..2bc29234f5b3 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -1149,8 +1149,7 @@
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> మెసేజ్‌ను పంపారు: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ఇమేజ్‌ను పంపారు"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g>, స్టేటస్‌ను గురించిన అప్‌డేట్‌ను కలిగి ఉన్నారు: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
- <!-- no translation found for person_available (2318599327472755472) -->
- <skip />
+ <string name="person_available" msgid="2318599327472755472">"అందుబాటులో ఉంది"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"మీ బ్యాటరీ మీటర్‌ను చదవడంలో సమస్య"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"మరింత సమాచారం కోసం ట్యాప్ చేయండి"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"అలారం సెట్ చేయలేదు"</string>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskInfoCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskInfoCompat.java
deleted file mode 100644
index 7b9ebc0d4656..000000000000
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskInfoCompat.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.shared.system;
-
-import android.app.ActivityManager;
-import android.app.PictureInPictureParams;
-import android.app.TaskInfo;
-import android.content.ComponentName;
-import android.content.pm.ActivityInfo;
-import android.graphics.Rect;
-
-public class TaskInfoCompat {
-
- public static int getUserId(TaskInfo info) {
- return info.userId;
- }
-
- public static int getActivityType(TaskInfo info) {
- return info.configuration.windowConfiguration.getActivityType();
- }
-
- public static int getWindowingMode(TaskInfo info) {
- return info.configuration.windowConfiguration.getWindowingMode();
- }
-
- public static Rect getWindowConfigurationBounds(TaskInfo info) {
- return info.configuration.windowConfiguration.getBounds();
- }
-
- public static boolean supportsSplitScreenMultiWindow(TaskInfo info) {
- return info.supportsSplitScreenMultiWindow;
- }
-
- public static ComponentName getTopActivity(TaskInfo info) {
- return info.topActivity;
- }
-
- public static ActivityManager.TaskDescription getTaskDescription(TaskInfo info) {
- return info.taskDescription;
- }
-
- public static ActivityInfo getTopActivityInfo(TaskInfo info) {
- return info.topActivityInfo;
- }
-
- public static boolean isAutoEnterPipEnabled(PictureInPictureParams params) {
- return params.isAutoEnterEnabled();
- }
-
- public static Rect getPipSourceRectHint(PictureInPictureParams params) {
- return params.getSourceRectHint();
- }
-}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index bd000b2effa3..e6e2ac980889 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -285,7 +285,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
@VisibleForTesting
protected boolean mTelephonyCapable;
- private final boolean mAcquiredHapticEnabled;
+ private final boolean mAcquiredHapticEnabled = false;
@Nullable private final Vibrator mVibrator;
// Device provisioning state
@@ -1413,11 +1413,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
@VisibleForTesting
public void playAcquiredHaptic() {
if (mAcquiredHapticEnabled && mVibrator != null) {
- String effect = Settings.Global.getString(
- mContext.getContentResolver(),
- "udfps_acquired_type");
- mVibrator.vibrate(UdfpsController.getVibration(effect,
- UdfpsController.EFFECT_TICK),
+ mVibrator.vibrate(UdfpsController.EFFECT_CLICK,
UdfpsController.VIBRATION_SONIFICATION_ATTRIBUTES);
}
}
@@ -1730,8 +1726,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
mLockPatternUtils = lockPatternUtils;
mAuthController = authController;
dumpManager.registerDumpable(getClass().getName(), this);
- mAcquiredHapticEnabled = Settings.Global.getInt(mContext.getContentResolver(),
- "udfps_acquired", 0) == 1;
mVibrator = vibrator;
mHandler = new Handler(mainLooper) {
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconView.java b/packages/SystemUI/src/com/android/keyguard/LockIconView.java
index c1d448db1e63..867e3ae6ae8c 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconView.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconView.java
@@ -16,16 +16,29 @@
package com.android.keyguard;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ArgbEvaluator;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
import android.content.Context;
+import android.content.res.ColorStateList;
import android.graphics.PointF;
import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
+import android.view.View;
+import android.view.animation.Interpolator;
+import android.view.animation.PathInterpolator;
import android.widget.FrameLayout;
import android.widget.ImageView;
import androidx.annotation.NonNull;
+import com.android.settingslib.Utils;
import com.android.systemui.Dumpable;
+import com.android.systemui.R;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -33,16 +46,96 @@ import java.io.PrintWriter;
/**
* A view positioned under the notification shade.
*/
-public class LockIconView extends ImageView implements Dumpable {
+public class LockIconView extends FrameLayout implements Dumpable {
@NonNull private final RectF mSensorRect;
@NonNull private PointF mLockIconCenter = new PointF(0f, 0f);
private int mRadius;
+ private ImageView mLockIcon;
+ private ImageView mUnlockBgView;
+
+ private AnimatorSet mBgAnimator;
+ private int mLockIconColor;
+ private int mUnlockStartColor;
+ private int mUnlockEndColor;
+
public LockIconView(Context context, AttributeSet attrs) {
super(context, attrs);
mSensorRect = new RectF();
}
+ @Override
+ public void onFinishInflate() {
+ super.onFinishInflate();
+ mLockIcon = findViewById(R.id.lock_icon);
+ mUnlockBgView = findViewById(R.id.lock_icon_bg);
+ }
+
+ void updateColor() {
+ mLockIconColor = Utils.getColorAttrDefaultColor(getContext(),
+ R.attr.wallpaperTextColorAccent);
+ mUnlockStartColor = mLockIconColor;
+ mUnlockEndColor = Utils.getColorAttrDefaultColor(getContext(),
+ android.R.attr.textColorPrimary);
+ mUnlockBgView.setBackground(getContext().getDrawable(R.drawable.fingerprint_bg));
+ }
+
+ void setImageDrawable(Drawable drawable) {
+ mLockIcon.setImageDrawable(drawable);
+ }
+
+ void hideBg() {
+ mUnlockBgView.setVisibility(View.INVISIBLE);
+ mLockIcon.setImageTintList(ColorStateList.valueOf(mLockIconColor));
+ }
+
+ void animateBg() {
+ ValueAnimator bgAlphaAnimator = ObjectAnimator.ofFloat(mUnlockBgView, View.ALPHA, 0f, 1f);
+ bgAlphaAnimator.setDuration(133);
+
+ Interpolator interpolator = new PathInterpolator(0f, 0f, 0f, 1f);
+ Animator scaleXAnimator = ObjectAnimator.ofFloat(mUnlockBgView, View.SCALE_X, .9f, 1f);
+ scaleXAnimator.setInterpolator(interpolator);
+ scaleXAnimator.setDuration(300);
+ Animator scaleYAnimator = ObjectAnimator.ofFloat(mUnlockBgView, View.SCALE_Y, .9f, 1f);
+ scaleYAnimator.setDuration(300);
+ scaleYAnimator.setInterpolator(interpolator);
+
+ ValueAnimator lockIconColorAnimator =
+ ValueAnimator.ofObject(new ArgbEvaluator(), mUnlockStartColor, mUnlockEndColor);
+ lockIconColorAnimator.addUpdateListener(
+ animation -> mLockIcon.setImageTintList(
+ ColorStateList.valueOf((int) animation.getAnimatedValue())));
+ lockIconColorAnimator.setDuration(150);
+
+ if (mBgAnimator != null) {
+ if (mBgAnimator.isRunning()) {
+ return;
+ }
+ mBgAnimator.cancel();
+ }
+ mBgAnimator = new AnimatorSet();
+ mBgAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ mBgAnimator = null;
+ }
+ });
+ mBgAnimator.playTogether(
+ bgAlphaAnimator,
+ scaleYAnimator,
+ scaleXAnimator,
+ lockIconColorAnimator);
+ mBgAnimator.setStartDelay(167);
+ mUnlockBgView.setAlpha(0f);
+ mUnlockBgView.setScaleX(0);
+ mUnlockBgView.setScaleY(0);
+ mUnlockBgView.setVisibility(View.VISIBLE);
+
+ mBgAnimator.start();
+ }
+
void setCenterLocation(@NonNull PointF center, int radius) {
mLockIconCenter = center;
mRadius = radius;
@@ -70,7 +163,6 @@ public class LockIconView extends ImageView implements Dumpable {
return mLockIconCenter.y - mRadius;
}
-
@Override
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
pw.println("Center in px (x, y)= (" + mLockIconCenter.x + ", " + mLockIconCenter.y + ")");
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index afea27222fbb..a7bd4c8e3d27 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -40,7 +40,6 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
-import com.android.settingslib.Utils;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.biometrics.AuthController;
@@ -145,6 +144,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
mUnlockedLabel = context.getResources().getString(R.string.accessibility_unlock_button);
mLockedLabel = context.getResources().getString(R.string.accessibility_lock_icon);
dumpManager.registerDumpable("LockIconViewController", this);
+
}
@Override
@@ -224,6 +224,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
mView.setImageDrawable(mLockIcon);
mView.setVisibility(View.VISIBLE);
mView.setContentDescription(mLockedLabel);
+ mView.hideBg();
} else if (mShowUnlockIcon) {
if (wasShowingFpIcon) {
mView.setImageDrawable(mFpToUnlockIcon);
@@ -234,9 +235,11 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
mLockToUnlockIcon.forceAnimationOnUI();
mLockToUnlockIcon.start();
}
+ mView.animateBg();
mView.setVisibility(View.VISIBLE);
mView.setContentDescription(mUnlockedLabel);
} else {
+ mView.hideBg();
mView.setVisibility(View.INVISIBLE);
mView.setContentDescription(null);
}
@@ -281,11 +284,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
}
private void updateColors() {
- final int color = Utils.getColorAttrDefaultColor(mView.getContext(),
- R.attr.wallpaperTextColorAccent);
- mFpToUnlockIcon.setTint(color);
- mLockToUnlockIcon.setTint(color);
- mLockIcon.setTint(color);
+ mView.updateColor();
}
private void updateConfiguration() {
@@ -445,6 +444,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
@Override
public void onConfigChanged(Configuration newConfig) {
updateConfiguration();
+ updateColors();
}
};
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
index 099e6f4b5341..57407f1f34c0 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
@@ -88,13 +88,10 @@ public class NumPadButton extends AlphaOptimizedImageButton {
* Reload colors from resources.
**/
public void reloadColors() {
- if (mAnimator != null) {
- mAnimator.reloadColors(getContext());
- } else {
- // Needed for old style pin
- int textColor = Utils.getColorAttr(getContext(), android.R.attr.textColorPrimary)
- .getDefaultColor();
- ((VectorDrawable) getDrawable()).setTintList(ColorStateList.valueOf(textColor));
- }
+ if (mAnimator != null) mAnimator.reloadColors(getContext());
+
+ int textColor = Utils.getColorAttrDefaultColor(getContext(),
+ android.R.attr.colorBackground);
+ ((VectorDrawable) getDrawable()).setTintList(ColorStateList.valueOf(textColor));
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 04dd990929fa..c292dc4b988f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -17,7 +17,6 @@
package com.android.systemui.biometrics;
import static android.hardware.fingerprint.IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD;
-import static android.os.VibrationEffect.Composition.PRIMITIVE_LOW_TICK;
import static com.android.internal.util.Preconditions.checkArgument;
import static com.android.internal.util.Preconditions.checkNotNull;
@@ -27,7 +26,6 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -47,8 +45,6 @@ import android.os.SystemClock;
import android.os.Trace;
import android.os.VibrationEffect;
import android.os.Vibrator;
-import android.provider.Settings;
-import android.text.TextUtils;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
@@ -73,6 +69,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.concurrency.Execution;
@@ -110,6 +107,7 @@ public class UdfpsController implements DozeReceiver {
private final DelayableExecutor mFgExecutor;
@NonNull private final StatusBar mStatusBar;
@NonNull private final StatusBarStateController mStatusBarStateController;
+ @NonNull private final KeyguardStateController mKeyguardStateController;
@NonNull private final StatusBarKeyguardViewManager mKeyguardViewManager;
@NonNull private final DumpManager mDumpManager;
@NonNull private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@@ -152,6 +150,7 @@ public class UdfpsController implements DozeReceiver {
private boolean mScreenOn;
private Runnable mAodInterruptRunnable;
private boolean mOnFingerDown;
+ private boolean mAttemptedToDismissKeyguard;
@VisibleForTesting
public static final AudioAttributes VIBRATION_SONIFICATION_ATTRIBUTES =
@@ -160,16 +159,8 @@ public class UdfpsController implements DozeReceiver {
.setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
.build();
- public static final VibrationEffect EFFECT_TICK =
- VibrationEffect.get(VibrationEffect.EFFECT_TICK);
- private static final VibrationEffect EFFECT_TEXTURE_TICK =
- VibrationEffect.get(VibrationEffect.EFFECT_TEXTURE_TICK);
- @VisibleForTesting
- static final VibrationEffect EFFECT_CLICK = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
- private static final VibrationEffect EFFECT_HEAVY =
- VibrationEffect.get(VibrationEffect.EFFECT_HEAVY_CLICK);
- private static final VibrationEffect EFFECT_DOUBLE_CLICK =
- VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK);
+ public static final VibrationEffect EFFECT_CLICK =
+ VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
private final ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() {
@Override
@@ -391,8 +382,12 @@ public class UdfpsController implements DozeReceiver {
// ACTION_DOWN, in that case we should just reuse the old instance.
mVelocityTracker.clear();
}
- if (isWithinSensorArea(udfpsView, event.getX(), event.getY(), fromUdfpsView)) {
+
+ boolean withinSensorArea =
+ isWithinSensorArea(udfpsView, event.getX(), event.getY(), fromUdfpsView);
+ if (withinSensorArea) {
Trace.beginAsyncSection("UdfpsController.e2e.onPointerDown", 0);
+ Log.v(TAG, "onTouch | action down");
// The pointer that causes ACTION_DOWN is always at index 0.
// We need to persist its ID to track it during ACTION_MOVE that could include
// data for many other pointers because of multi-touch support.
@@ -400,6 +395,11 @@ public class UdfpsController implements DozeReceiver {
mVelocityTracker.addMovement(event);
handled = true;
}
+ if ((withinSensorArea || fromUdfpsView) && shouldTryToDismissKeyguard()) {
+ Log.v(TAG, "onTouch | dismiss keyguard from ACTION_DOWN");
+ mKeyguardViewManager.notifyKeyguardAuthenticated(false /* strongAuth */);
+ mAttemptedToDismissKeyguard = true;
+ }
Trace.endSection();
break;
@@ -410,8 +410,10 @@ public class UdfpsController implements DozeReceiver {
? event.getPointerId(0)
: event.findPointerIndex(mActivePointerId);
if (idx == event.getActionIndex()) {
- if (isWithinSensorArea(udfpsView, event.getX(idx), event.getY(idx),
- fromUdfpsView)) {
+ boolean actionMoveWithinSensorArea =
+ isWithinSensorArea(udfpsView, event.getX(idx), event.getY(idx),
+ fromUdfpsView);
+ if (actionMoveWithinSensorArea) {
if (mVelocityTracker == null) {
// touches could be injected, so the velocity tracker may not have
// been initialized (via ACTION_DOWN).
@@ -437,7 +439,6 @@ public class UdfpsController implements DozeReceiver {
mTouchLogTime = SystemClock.elapsedRealtime();
mPowerManager.userActivity(SystemClock.uptimeMillis(),
PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0);
- playStartHaptic();
handled = true;
} else if (sinceLastLog >= MIN_TOUCH_LOG_INTERVAL) {
Log.v(TAG, "onTouch | finger move: " + touchInfo);
@@ -447,6 +448,12 @@ public class UdfpsController implements DozeReceiver {
Log.v(TAG, "onTouch | finger outside");
onFingerUp();
}
+ if ((fromUdfpsView || actionMoveWithinSensorArea)
+ && shouldTryToDismissKeyguard()) {
+ Log.v(TAG, "onTouch | dismiss keyguard from ACTION_MOVE");
+ mKeyguardViewManager.notifyKeyguardAuthenticated(false /* strongAuth */);
+ mAttemptedToDismissKeyguard = true;
+ }
}
Trace.endSection();
break;
@@ -461,6 +468,7 @@ public class UdfpsController implements DozeReceiver {
mVelocityTracker = null;
}
Log.v(TAG, "onTouch | finger up");
+ mAttemptedToDismissKeyguard = false;
onFingerUp();
mFalsingManager.isFalseTouch(UDFPS_AUTHENTICATION);
Trace.endSection();
@@ -472,6 +480,13 @@ public class UdfpsController implements DozeReceiver {
return handled;
}
+ private boolean shouldTryToDismissKeyguard() {
+ return mView.getAnimationViewController() != null
+ && mView.getAnimationViewController() instanceof UdfpsKeyguardViewController
+ && mKeyguardStateController.canDismissLockScreen()
+ && !mAttemptedToDismissKeyguard;
+ }
+
@Inject
public UdfpsController(@NonNull Context context,
@NonNull Execution execution,
@@ -492,7 +507,8 @@ public class UdfpsController implements DozeReceiver {
@NonNull ScreenLifecycle screenLifecycle,
@Nullable Vibrator vibrator,
@NonNull UdfpsHapticsSimulator udfpsHapticsSimulator,
- @NonNull Optional<UdfpsHbmProvider> hbmProvider) {
+ @NonNull Optional<UdfpsHbmProvider> hbmProvider,
+ @NonNull KeyguardStateController keyguardStateController) {
mContext = context;
mExecution = execution;
// TODO (b/185124905): inject main handler and vibrator once done prototyping
@@ -506,6 +522,7 @@ public class UdfpsController implements DozeReceiver {
mFgExecutor = fgExecutor;
mStatusBar = statusBar;
mStatusBarStateController = statusBarStateController;
+ mKeyguardStateController = keyguardStateController;
mKeyguardViewManager = statusBarKeyguardViewManager;
mDumpManager = dumpManager;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
@@ -552,18 +569,7 @@ public class UdfpsController implements DozeReceiver {
@VisibleForTesting
public void playStartHaptic() {
if (mVibrator != null) {
- final ContentResolver contentResolver =
- mContext.getContentResolver();
- // TODO: these settings checks should eventually be removed after ux testing
- // (b/185124905)
- int startEnabled = Settings.Global.getInt(contentResolver,
- "udfps_start", 1);
- if (startEnabled > 0) {
- String startEffectSetting = Settings.Global.getString(
- contentResolver, "udfps_start_type");
- mVibrator.vibrate(getVibration(startEffectSetting,
- EFFECT_CLICK), VIBRATION_SONIFICATION_ATTRIBUTES);
- }
+ mVibrator.vibrate(EFFECT_CLICK, VIBRATION_SONIFICATION_ATTRIBUTES);
}
}
@@ -691,6 +697,7 @@ public class UdfpsController implements DozeReceiver {
mView.setSensorProperties(mSensorProps);
mView.setHbmProvider(mHbmProvider);
UdfpsAnimationViewController animation = inflateUdfpsAnimation(reason);
+ mAttemptedToDismissKeyguard = false;
animation.init();
mView.setAnimationViewController(animation);
mOrientationListener.enable();
@@ -854,6 +861,9 @@ public class UdfpsController implements DozeReceiver {
Log.w(TAG, "Null view in onFingerDown");
return;
}
+ if (!mOnFingerDown) {
+ playStartHaptic();
+ }
mOnFingerDown = true;
mFingerprintManager.onPointerDown(mSensorProps.sensorId, x, y, minor, major);
Trace.endAsyncSection("UdfpsController.e2e.onPointerDown", 0);
@@ -881,38 +891,6 @@ public class UdfpsController implements DozeReceiver {
}
}
- /**
- * get vibration to play given string
- * used for testing purposes (b/185124905)
- */
- public static VibrationEffect getVibration(String effect, VibrationEffect defaultEffect) {
- if (TextUtils.isEmpty(effect)) {
- return defaultEffect;
- }
-
- switch (effect.toLowerCase()) {
- case "click":
- return EFFECT_CLICK;
- case "heavy":
- return EFFECT_HEAVY;
- case "texture_tick":
- return EFFECT_TEXTURE_TICK;
- case "tick":
- return EFFECT_TICK;
- case "double_tap":
- return EFFECT_DOUBLE_CLICK;
- default:
- try {
- int primitive = Integer.parseInt(effect);
- if (primitive <= PRIMITIVE_LOW_TICK && primitive > -1) {
- return VibrationEffect.startComposition().addPrimitive(primitive).compose();
- }
- } catch (NumberFormatException e) {
- }
- return defaultEffect;
- }
- }
-
private void updateTouchListener() {
if (mView == null) {
return;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
index 131618442c22..eb02aa0d9cdf 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
@@ -162,7 +162,12 @@ public class UdfpsKeyguardView extends UdfpsAnimationView {
}
void updateColor() {
+ mWallpaperTextColor = Utils.getColorAttrDefaultColor(mContext,
+ R.attr.wallpaperTextColorAccent);
+ mTextColorPrimary = Utils.getColorAttrDefaultColor(mContext,
+ android.R.attr.textColorPrimary);
mLockScreenFp.invalidate();
+ mBgProtection.setBackground(getContext().getDrawable(R.drawable.fingerprint_bg));
}
private boolean showingUdfpsBouncer() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
index b6aed23e64ee..180f81c22a9d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
@@ -131,7 +131,7 @@ public class RemoteInputController {
*/
public void removeRemoteInput(NotificationEntry entry, Object token) {
Objects.requireNonNull(entry);
- if (entry.mRemoteEditImeVisible) return;
+ if (entry.mRemoteEditImeVisible && entry.mRemoteEditImeAnimatingAway) return;
// If the view is being removed, this may be called even though we're not active
if (!isRemoteInputActive(entry)) return;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index 96b0e7819c7a..94ee868ceebc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -183,6 +183,7 @@ public final class NotificationEntry extends ListEntry {
private boolean mIsMarkedForUserTriggeredMovement;
private boolean mIsAlerting;
+ public boolean mRemoteEditImeAnimatingAway;
public boolean mRemoteEditImeVisible;
private boolean mExpandAnimationRunning;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 6b8686b45528..db7ead7c1531 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -55,6 +55,7 @@ import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.StatusBarManager;
+import android.app.TaskInfo;
import android.app.UiModeManager;
import android.app.WallpaperInfo;
import android.app.WallpaperManager;
@@ -247,6 +248,7 @@ 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;
import java.io.FileDescriptor;
@@ -269,7 +271,7 @@ public class StatusBar extends SystemUI implements DemoMode,
ColorExtractor.OnColorsChangedListener, ConfigurationListener,
StatusBarStateController.StateListener,
LifecycleOwner, BatteryController.BatteryStateChangeCallback,
- ActivityLaunchAnimator.KeyguardHandler {
+ ActivityLaunchAnimator.Callback {
public static final boolean MULTIUSER_DEBUG = false;
protected static final int MSG_HIDE_RECENT_APPS = 1020;
@@ -1421,9 +1423,7 @@ public class StatusBar extends SystemUI implements DemoMode,
private void setUpPresenter() {
// Set up the initial notification state.
- mActivityLaunchAnimator = new ActivityLaunchAnimator(this,
- mStartingSurfaceOptional.orElse(null),
- mContext);
+ mActivityLaunchAnimator = new ActivityLaunchAnimator(this, mContext);
mNotificationAnimationProvider = new NotificationLaunchAnimatorControllerProvider(
mNotificationShadeWindowViewController,
mStackScrollerController.getNotificationListContainer(),
@@ -2123,6 +2123,16 @@ public class StatusBar extends SystemUI implements DemoMode,
mKeyguardViewMediator.setBlursDisabledForAppLaunch(disabled);
}
+ @Override
+ public int getBackgroundColor(TaskInfo task) {
+ if (!mStartingSurfaceOptional.isPresent()) {
+ Log.w(TAG, "No starting surface, defaulting to SystemBGColor");
+ return SplashscreenContentDrawer.getSystemBGColor();
+ }
+
+ return mStartingSurfaceOptional.get().getBackgroundColor(task);
+ }
+
public boolean isDeviceInVrMode() {
return mPresenter.isDeviceInVrMode();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index bbaf65a399a9..84d7c05ddc14 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -272,6 +272,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
public void onEnd(@NonNull WindowInsetsAnimation animation) {
super.onEnd(animation);
if (animation.getTypeMask() == WindowInsets.Type.ime()) {
+ mEntry.mRemoteEditImeAnimatingAway = false;
mEntry.mRemoteEditImeVisible =
mEditText.getRootWindowInsets().isVisible(WindowInsets.Type.ime());
if (!mEntry.mRemoteEditImeVisible && !mEditText.mShowImeOnInputConnection) {
@@ -392,6 +393,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
mSendButton.setVisibility(INVISIBLE);
mProgressBar.setVisibility(VISIBLE);
mEntry.lastRemoteInputSent = SystemClock.elapsedRealtime();
+ mEntry.mRemoteEditImeAnimatingAway = true;
mController.addSpinning(mEntry.getKey(), mToken);
mController.removeRemoteInput(mEntry, mToken);
mEditText.mShowImeOnInputConnection = false;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt
index 33cc7821eba4..14f112b8b071 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt
@@ -10,6 +10,7 @@ import android.graphics.Rect
import android.os.Looper
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
+import android.util.Log
import android.view.IRemoteAnimationFinishedCallback
import android.view.RemoteAnimationAdapter
import android.view.RemoteAnimationTarget
@@ -21,12 +22,12 @@ import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
-import com.android.wm.shell.startingsurface.StartingSurface
import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertNotNull
import junit.framework.Assert.assertNull
import junit.framework.Assert.assertTrue
import junit.framework.AssertionFailedError
+import kotlin.concurrent.thread
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@@ -39,24 +40,23 @@ import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.Spy
import org.mockito.junit.MockitoJUnit
-import kotlin.concurrent.thread
@SmallTest
@RunWith(AndroidTestingRunner::class)
@RunWithLooper
class ActivityLaunchAnimatorTest : SysuiTestCase() {
private val launchContainer = LinearLayout(mContext)
- @Mock lateinit var keyguardHandler: ActivityLaunchAnimator.KeyguardHandler
+ @Mock lateinit var callback: ActivityLaunchAnimator.Callback
@Spy private val controller = TestLaunchAnimatorController(launchContainer)
@Mock lateinit var iCallback: IRemoteAnimationFinishedCallback
- @Mock lateinit var startingSurface: StartingSurface
+ @Mock lateinit var failHandler: Log.TerribleFailureHandler
private lateinit var activityLaunchAnimator: ActivityLaunchAnimator
@get:Rule val rule = MockitoJUnit.rule()
@Before
fun setup() {
- activityLaunchAnimator = ActivityLaunchAnimator(keyguardHandler, startingSurface, mContext)
+ activityLaunchAnimator = ActivityLaunchAnimator(callback, mContext)
}
private fun startIntentWithAnimation(
@@ -119,8 +119,8 @@ class ActivityLaunchAnimatorTest : SysuiTestCase() {
@Test
fun animatesIfActivityIsAlreadyOpenAndIsOnKeyguard() {
- `when`(keyguardHandler.isOnKeyguard()).thenReturn(true)
- val animator = ActivityLaunchAnimator(keyguardHandler, startingSurface, context)
+ `when`(callback.isOnKeyguard()).thenReturn(true)
+ val animator = ActivityLaunchAnimator(callback, context)
val willAnimateCaptor = ArgumentCaptor.forClass(Boolean::class.java)
var animationAdapter: RemoteAnimationAdapter? = null
@@ -132,7 +132,7 @@ class ActivityLaunchAnimatorTest : SysuiTestCase() {
waitForIdleSync()
verify(controller).onIntentStarted(willAnimateCaptor.capture())
- verify(keyguardHandler).hideKeyguardWithAnimation(any())
+ verify(callback).hideKeyguardWithAnimation(any())
assertTrue(willAnimateCaptor.value)
assertNull(animationAdapter)
@@ -174,13 +174,15 @@ class ActivityLaunchAnimatorTest : SysuiTestCase() {
val runner = activityLaunchAnimator.createRunner(controller)
runner.onAnimationStart(0, arrayOf(fakeWindow()), emptyArray(), emptyArray(), iCallback)
waitForIdleSync()
- verify(keyguardHandler).setBlursDisabledForAppLaunch(eq(true))
+ verify(callback).setBlursDisabledForAppLaunch(eq(true))
verify(controller).onLaunchAnimationStart(anyBoolean())
}
@Test
- fun controllerFromOrphanViewReturnsNull() {
+ fun controllerFromOrphanViewReturnsNullAndIsATerribleFailure() {
+ Log.setWtfHandler(failHandler)
assertNull(ActivityLaunchAnimator.Controller.fromView(View(mContext)))
+ verify(failHandler).onTerribleFailure(any(), any(), anyBoolean())
}
private fun fakeWindow(): RemoteAnimationTarget {
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 d8d3676d4fa2..5156d7c2e87a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -21,6 +21,7 @@ import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
@@ -58,6 +59,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.Execution;
import com.android.systemui.util.concurrency.FakeExecution;
import com.android.systemui.util.concurrency.FakeExecutor;
@@ -130,6 +132,8 @@ public class UdfpsControllerTest extends SysuiTestCase {
private Vibrator mVibrator;
@Mock
private UdfpsHapticsSimulator mUdfpsHapticsSimulator;
+ @Mock
+ private KeyguardStateController mKeyguardStateController;
private FakeExecutor mFgExecutor;
@@ -137,6 +141,8 @@ public class UdfpsControllerTest extends SysuiTestCase {
@Mock
private UdfpsView mUdfpsView;
@Mock
+ private UdfpsKeyguardViewController mUdfpsKeyguardViewController;
+ @Mock
private TypedArray mBrightnessValues;
@Mock
private TypedArray mBrightnessBacklight;
@@ -149,6 +155,8 @@ public class UdfpsControllerTest extends SysuiTestCase {
@Captor private ArgumentCaptor<ScreenLifecycle.Observer> mScreenObserverCaptor;
private ScreenLifecycle.Observer mScreenObserver;
+ @Captor private ArgumentCaptor<UdfpsAnimationViewController> mAnimViewControllerCaptor;
+
@Before
public void setUp() {
setUpResources();
@@ -193,7 +201,8 @@ public class UdfpsControllerTest extends SysuiTestCase {
mScreenLifecycle,
mVibrator,
mUdfpsHapticsSimulator,
- Optional.of(mHbmProvider));
+ Optional.of(mHbmProvider),
+ mKeyguardStateController);
verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture());
mOverlayController = mOverlayCaptor.getValue();
verify(mScreenLifecycle).addObserver(mScreenObserverCaptor.capture());
@@ -221,6 +230,76 @@ public class UdfpsControllerTest extends SysuiTestCase {
}
@Test
+ public void onActionDownTouch_whenCanDismissLockScreen_entersDevice() throws RemoteException {
+ // GIVEN can dismiss lock screen and the current animation is an UdfpsKeyguardViewController
+ when(mKeyguardStateController.canDismissLockScreen()).thenReturn(true);
+ when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
+ when(mUdfpsView.getAnimationViewController()).thenReturn(mUdfpsKeyguardViewController);
+
+ // GIVEN that the overlay is showing
+ mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
+ mFgExecutor.runAllReady();
+
+ // WHEN ACTION_DOWN is received
+ verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
+ MotionEvent downEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0);
+ mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
+ downEvent.recycle();
+
+ // THEN notify keyguard authenticate to dismiss the keyguard
+ verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(anyBoolean());
+ }
+
+ @Test
+ public void onActionMoveTouch_whenCanDismissLockScreen_entersDevice() throws RemoteException {
+ // GIVEN can dismiss lock screen and the current animation is an UdfpsKeyguardViewController
+ when(mKeyguardStateController.canDismissLockScreen()).thenReturn(true);
+ when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
+ when(mUdfpsView.getAnimationViewController()).thenReturn(mUdfpsKeyguardViewController);
+
+ // GIVEN that the overlay is showing
+ mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
+ mFgExecutor.runAllReady();
+
+ // WHEN ACTION_MOVE is received
+ verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
+ MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
+ mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
+ moveEvent.recycle();
+
+ // THEN notify keyguard authenticate to dismiss the keyguard
+ verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(anyBoolean());
+ }
+
+ @Test
+ public void onMultipleTouch_whenCanDismissLockScreen_entersDeviceOnce() throws RemoteException {
+ // GIVEN can dismiss lock screen and the current animation is an UdfpsKeyguardViewController
+ when(mKeyguardStateController.canDismissLockScreen()).thenReturn(true);
+ when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
+ when(mUdfpsView.getAnimationViewController()).thenReturn(mUdfpsKeyguardViewController);
+
+ // GIVEN that the overlay is showing
+ mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
+ mFgExecutor.runAllReady();
+
+ // WHEN multiple touches are received
+ verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
+ MotionEvent downEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0);
+ mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
+ downEvent.recycle();
+ MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
+ mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
+ mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
+ moveEvent.recycle();
+
+ // THEN notify keyguard authenticate to dismiss the keyguard
+ verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(anyBoolean());
+ }
+
+ @Test
public void showUdfpsOverlay_addsViewToWindow() throws RemoteException {
mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
index e1af2c48789f..d7bc04091181 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
@@ -258,7 +258,12 @@ public class TouchExplorer extends BaseEventStreamTransformation
super.onMotionEvent(event, rawEvent, policyFlags);
return;
}
-
+ try {
+ checkForMalformedEvent(event);
+ } catch (IllegalArgumentException e) {
+ Slog.e(LOG_TAG, "Ignoring malformed event: " + event.toString(), e);
+ return;
+ }
if (DEBUG) {
Slog.d(LOG_TAG, "Received event: " + event + ", policyFlags=0x"
+ Integer.toHexString(policyFlags));
@@ -1223,6 +1228,32 @@ public class TouchExplorer extends BaseEventStreamTransformation
}
/**
+ * Checks to see whether an event is consistent with itself.
+ *
+ * @throws IllegalArgumentException in the case of a malformed event.
+ */
+ private static void checkForMalformedEvent(MotionEvent event) {
+ if (event.getPointerCount() < 0) {
+ throw new IllegalArgumentException("Invalid pointer count: " + event.getPointerCount());
+ }
+ for (int i = 0; i < event.getPointerCount(); ++i) {
+ try {
+ int pointerId = event.getPointerId(i);
+ float x = event.getX(i);
+ float y = event.getY(i);
+ if (Float.isNaN(x) || Float.isNaN(y) || x < 0.0f || y < 0.0f) {
+ throw new IllegalArgumentException(
+ "Invalid coordinates: (" + x + ", " + y + ")");
+ }
+ } catch (Exception e) {
+ throw new IllegalArgumentException(
+ "Encountered exception getting details of pointer " + i + " / "
+ + event.getPointerCount(), e);
+ }
+ }
+ }
+
+ /**
* Class for delayed sending of hover enter and move events.
*/
class SendHoverEnterAndMoveDelayed implements Runnable {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 4ec5559a061d..99ae52c00995 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5003,7 +5003,7 @@ public class ActivityManagerService extends IActivityManager.Stub
(res.key.flags & PendingIntent.FLAG_IMMUTABLE) != 0,
res.key.type);
} else {
- throw new IllegalArgumentException();
+ return new PendingIntentInfo(null, -1, false, ActivityManager.INTENT_SENDER_UNKNOWN);
}
}
@@ -11048,9 +11048,9 @@ public class ActivityManagerService extends IActivityManager.Stub
}
final long gpuUsage = Debug.getGpuTotalUsageKb();
if (gpuUsage >= 0) {
- final long gpuDmaBufUsage = Debug.getGpuDmaBufUsageKb();
- if (gpuDmaBufUsage >= 0) {
- final long gpuPrivateUsage = gpuUsage - gpuDmaBufUsage;
+ final long gpuPrivateUsage = Debug.getGpuPrivateMemoryKb();
+ if (gpuPrivateUsage >= 0) {
+ final long gpuDmaBufUsage = gpuUsage - gpuPrivateUsage;
pw.print(" GPU: ");
pw.print(stringifyKBSize(gpuUsage));
pw.print(" (");
@@ -12425,6 +12425,15 @@ public class ActivityManagerService extends IActivityManager.Stub
return sticky;
}
+ // SafetyNet logging for b/177931370. If any process other than system_server tries to
+ // listen to this broadcast action, then log it.
+ if (callingPid != Process.myPid()) {
+ if (filter.hasAction("com.android.server.net.action.SNOOZE_WARNING")
+ || filter.hasAction("com.android.server.net.action.SNOOZE_RAPID")) {
+ EventLog.writeEvent(0x534e4554, "177931370", callingUid, "");
+ }
+ }
+
synchronized (this) {
IApplicationThread thread;
if (callerApp != null && ((thread = callerApp.getThread()) == null
diff --git a/services/core/java/com/android/server/am/AppProfiler.java b/services/core/java/com/android/server/am/AppProfiler.java
index 74094e500de7..36c0de919279 100644
--- a/services/core/java/com/android/server/am/AppProfiler.java
+++ b/services/core/java/com/android/server/am/AppProfiler.java
@@ -1561,9 +1561,9 @@ public class AppProfiler {
final long gpuUsage = Debug.getGpuTotalUsageKb();
if (gpuUsage >= 0) {
- final long gpuDmaBufUsage = Debug.getGpuDmaBufUsageKb();
- if (gpuDmaBufUsage >= 0) {
- final long gpuPrivateUsage = gpuUsage - gpuDmaBufUsage;
+ final long gpuPrivateUsage = Debug.getGpuPrivateMemoryKb();
+ if (gpuPrivateUsage >= 0) {
+ final long gpuDmaBufUsage = gpuUsage - gpuPrivateUsage;
memInfoBuilder.append(" GPU: ");
memInfoBuilder.append(stringifyKBSize(gpuUsage));
memInfoBuilder.append(" (");
diff --git a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
index ca357b4c2cec..f11fe8aee64f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
@@ -188,18 +188,7 @@ public abstract class AcquisitionClient<T> extends HalClientMonitor<T> implement
mPowerManager.userActivity(now, PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0);
}
- protected boolean successHapticsEnabled() {
- return true;
- }
-
- protected boolean errorHapticsEnabled() {
- return true;
- }
-
protected final void vibrateSuccess() {
- if (!successHapticsEnabled()) {
- return;
- }
Vibrator vibrator = getContext().getSystemService(Vibrator.class);
if (vibrator != null) {
vibrator.vibrate(SUCCESS_VIBRATION_EFFECT, VIBRATION_SONIFICATION_ATTRIBUTES);
@@ -207,9 +196,6 @@ public abstract class AcquisitionClient<T> extends HalClientMonitor<T> implement
}
protected final void vibrateError() {
- if (!errorHapticsEnabled()) {
- return;
- }
Vibrator vibrator = getContext().getSystemService(Vibrator.class);
if (vibrator != null) {
vibrator.vibrate(ERROR_VIBRATION_EFFECT, VIBRATION_SONIFICATION_ATTRIBUTES);
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
index db927b227d9a..3757404d226d 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
@@ -19,7 +19,6 @@ package com.android.server.biometrics.sensors.face.aidl;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.NotificationManager;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
import android.hardware.biometrics.BiometricAuthenticator;
@@ -33,7 +32,6 @@ import android.hardware.face.FaceAuthenticationFrame;
import android.hardware.face.FaceManager;
import android.os.IBinder;
import android.os.RemoteException;
-import android.provider.Settings;
import android.util.Slog;
import com.android.internal.R;
@@ -59,9 +57,6 @@ class FaceAuthenticationClient extends AuthenticationClient<ISession> implements
@Nullable private final NotificationManager mNotificationManager;
@Nullable private ICancellationSignal mCancellationSignal;
- @NonNull private final ContentResolver mContentResolver;
- private final boolean mCustomHaptics;
-
private final int[] mBiometricPromptIgnoreList;
private final int[] mBiometricPromptIgnoreListVendor;
private final int[] mKeyguardIgnoreList;
@@ -92,10 +87,6 @@ class FaceAuthenticationClient extends AuthenticationClient<ISession> implements
R.array.config_face_acquire_keyguard_ignorelist);
mKeyguardIgnoreListVendor = resources.getIntArray(
R.array.config_face_acquire_vendor_keyguard_ignorelist);
-
- mContentResolver = context.getContentResolver();
- mCustomHaptics = Settings.Global.getInt(mContentResolver,
- "face_custom_success_error", 0) == 1;
}
@NonNull
@@ -261,18 +252,4 @@ class FaceAuthenticationClient extends AuthenticationClient<ISession> implements
Slog.e(TAG, "Remote exception", e);
}
}
-
- @Override
- protected boolean successHapticsEnabled() {
- return mCustomHaptics
- ? Settings.Global.getInt(mContentResolver, "face_success_enabled", 1) == 0
- : super.successHapticsEnabled();
- }
-
- @Override
- protected boolean errorHapticsEnabled() {
- return mCustomHaptics
- ? Settings.Global.getInt(mContentResolver, "face_error_enabled", 1) == 0
- : super.errorHapticsEnabled();
- }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
index 6c0adafcf2ee..c3de7aa74d15 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
@@ -17,7 +17,6 @@
package com.android.server.biometrics.sensors.face.hidl;
import android.annotation.NonNull;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
import android.hardware.biometrics.BiometricAuthenticator;
@@ -28,7 +27,6 @@ import android.hardware.biometrics.face.V1_0.IBiometricsFace;
import android.hardware.face.FaceManager;
import android.os.IBinder;
import android.os.RemoteException;
-import android.provider.Settings;
import android.util.Slog;
import com.android.internal.R;
@@ -49,8 +47,6 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> {
private static final String TAG = "FaceAuthenticationClient";
- @NonNull private final ContentResolver mContentResolver;
- private final boolean mCustomHaptics;
private final UsageStats mUsageStats;
private final int[] mBiometricPromptIgnoreList;
@@ -81,10 +77,6 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> {
R.array.config_face_acquire_keyguard_ignorelist);
mKeyguardIgnoreListVendor = resources.getIntArray(
R.array.config_face_acquire_vendor_keyguard_ignorelist);
-
- mContentResolver = context.getContentResolver();
- mCustomHaptics = Settings.Global.getInt(mContentResolver,
- "face_custom_success_error", 0) == 1;
}
@NonNull
@@ -200,18 +192,4 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> {
final boolean shouldSend = shouldSend(acquireInfo, vendorCode);
onAcquiredInternal(acquireInfo, vendorCode, shouldSend);
}
-
- @Override
- protected boolean successHapticsEnabled() {
- return mCustomHaptics
- ? Settings.Global.getInt(mContentResolver, "face_success_enabled", 1) == 0
- : super.successHapticsEnabled();
- }
-
- @Override
- protected boolean errorHapticsEnabled() {
- return mCustomHaptics
- ? Settings.Global.getInt(mContentResolver, "face_error_enabled", 1) == 0
- : super.errorHapticsEnabled();
- }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
index 6a05ed470123..19134e46f08f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
@@ -19,7 +19,6 @@ package com.android.server.biometrics.sensors.fingerprint.aidl;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.TaskStackListener;
-import android.content.ContentResolver;
import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricFingerprintConstants;
@@ -30,7 +29,6 @@ import android.hardware.biometrics.fingerprint.ISession;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.os.IBinder;
import android.os.RemoteException;
-import android.provider.Settings;
import android.util.Slog;
import com.android.server.biometrics.Utils;
@@ -57,9 +55,6 @@ class FingerprintAuthenticationClient extends AuthenticationClient<ISession> imp
@Nullable private final IUdfpsOverlayController mUdfpsOverlayController;
@Nullable private ICancellationSignal mCancellationSignal;
- @NonNull private final ContentResolver mContentResolver;
- private final boolean mCustomHaptics;
-
FingerprintAuthenticationClient(@NonNull Context context,
@NonNull LazyDaemon<ISession> lazyDaemon, @NonNull IBinder token,
@NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId,
@@ -74,10 +69,6 @@ class FingerprintAuthenticationClient extends AuthenticationClient<ISession> imp
lockoutCache, allowBackgroundAuthentication);
mLockoutCache = lockoutCache;
mUdfpsOverlayController = udfpsOverlayController;
-
- mContentResolver = context.getContentResolver();
- mCustomHaptics = Settings.Global.getInt(mContentResolver,
- "fp_custom_success_error", 0) == 1;
}
@NonNull
@@ -213,18 +204,4 @@ class FingerprintAuthenticationClient extends AuthenticationClient<ISession> imp
UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
mCallback.onClientFinished(this, false /* success */);
}
-
- @Override
- protected boolean successHapticsEnabled() {
- return mCustomHaptics
- ? Settings.Global.getInt(mContentResolver, "fp_success_enabled", 1) == 0
- : super.successHapticsEnabled();
- }
-
- @Override
- protected boolean errorHapticsEnabled() {
- return mCustomHaptics
- ? Settings.Global.getInt(mContentResolver, "fp_error_enabled", 1) == 0
- : super.errorHapticsEnabled();
- }
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 6adde9ad25fd..00ef97d7a17a 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -1265,12 +1265,13 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
@GuardedBy("mProgressLock")
private void computeProgressLocked(boolean forcePublish) {
- if (!mCommitted) {
+ if (!isIncrementalInstallation() || !mCommitted) {
mProgress = MathUtils.constrain(mClientProgress * 0.8f, 0f, 0.8f)
+ MathUtils.constrain(mInternalProgress * 0.2f, 0f, 0.2f);
} else {
- // For incremental install, continue to publish incremental progress during committing.
- if (isIncrementalInstallation() && (mIncrementalProgress - mProgress) >= 0.01) {
+ // For incremental, publish regular install progress before the session is committed,
+ // but publish incremental progress afterwards.
+ if (mIncrementalProgress - mProgress >= 0.01) {
// It takes some time for data loader to write to incremental file system, so at the
// beginning of the commit, the incremental progress might be very small.
// Wait till the incremental progress is larger than what's already displayed.
@@ -1279,7 +1280,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
}
- // Only publish when meaningful change
+ // Only publish meaningful progress changes.
if (forcePublish || (mProgress - mReportedProgress) >= 0.01) {
mReportedProgress = mProgress;
mCallback.onSessionProgressChanged(this, mProgress);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 04771b99c09f..ee44c10edbf3 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -7955,12 +7955,9 @@ public class PackageManagerService extends IPackageManager.Stub
} catch (PackageManagerException e) {
Slog.w(TAG, "updateAllSharedLibrariesLPw failed: ", e);
}
- final int[] userIds = mUserManager.getUserIds();
- for (final int userId : userIds) {
- mPermissionManager.onPackageInstalled(pkg,
- PermissionManagerServiceInternal.PackageInstalledParams.DEFAULT,
- userId);
- }
+ mPermissionManager.onPackageInstalled(pkg,
+ PermissionManagerServiceInternal.PackageInstalledParams.DEFAULT,
+ UserHandle.USER_ALL);
writeSettingsLPrTEMP();
}
} catch (PackageManagerException e) {
@@ -19213,12 +19210,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
final int autoRevokePermissionsMode = installArgs.autoRevokePermissionsMode;
permissionParamsBuilder.setAutoRevokePermissionsMode(autoRevokePermissionsMode);
- for (int currentUserId : allUsersList) {
- if (ps.getInstalled(currentUserId)) {
- mPermissionManager.onPackageInstalled(pkg, permissionParamsBuilder.build(),
- currentUserId);
- }
- }
+ mPermissionManager.onPackageInstalled(pkg, permissionParamsBuilder.build(), userId);
}
res.name = pkgName;
res.uid = pkg.getUid();
@@ -21862,10 +21854,8 @@ public class PackageManagerService extends IPackageManager.Stub
if (sharedUserPkgs == null) {
sharedUserPkgs = Collections.emptyList();
}
- for (final int userId : allUserHandles) {
- mPermissionManager.onPackageUninstalled(packageName, deletedPs.appId,
- deletedPs.pkg, sharedUserPkgs, userId);
- }
+ mPermissionManager.onPackageUninstalled(packageName, deletedPs.appId,
+ deletedPs.pkg, sharedUserPkgs, UserHandle.USER_ALL);
}
clearPackagePreferredActivitiesLPw(
deletedPs.name, changedUsers, UserHandle.USER_ALL);
@@ -22082,11 +22072,12 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
+ // The method below will take care of removing obsolete permissions and granting
+ // install permissions.
+ mPermissionManager.onPackageInstalled(pkg,
+ PermissionManagerServiceInternal.PackageInstalledParams.DEFAULT,
+ UserHandle.USER_ALL);
for (final int userId : allUserHandles) {
- // The method below will take care of removing obsolete permissions and granting
- // install permissions.
- mPermissionManager.onPackageInstalled(pkg,
- PermissionManagerServiceInternal.PackageInstalledParams.DEFAULT, userId);
if (applyUserRestrictions) {
mSettings.writePermissionStateForUserLPr(userId, false);
}
@@ -22409,10 +22400,9 @@ public class PackageManagerService extends IPackageManager.Stub
}
removeKeystoreDataIfNeeded(mInjector.getUserManagerInternal(), nextUserId, ps.appId);
clearPackagePreferredActivities(ps.name, nextUserId);
- mPermissionManager.onPackageUninstalled(ps.name, ps.appId, pkg, sharedUserPkgs,
- nextUserId);
mDomainVerificationManager.clearPackageForUser(ps.name, nextUserId);
}
+ mPermissionManager.onPackageUninstalled(ps.name, ps.appId, pkg, sharedUserPkgs, userId);
if (outInfo != null) {
if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 97ccfe6e7b2c..dfc14bd733df 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -4040,17 +4040,14 @@ public class PermissionManagerService extends IPermissionManager.Stub {
*
* @param packageName The package that is updated
* @param pkg The package that is updated, or {@code null} if package is deleted
- * @param filterUserId If not {@link UserHandle.USER_ALL}, only restore the permission state for
- * this particular user
*/
- private void updatePermissions(@NonNull String packageName, @Nullable AndroidPackage pkg,
- @UserIdInt int filterUserId) {
+ private void updatePermissions(@NonNull String packageName, @Nullable AndroidPackage pkg) {
// If the package is being deleted, update the permissions of all the apps
final int flags =
(pkg == null ? UPDATE_PERMISSIONS_ALL | UPDATE_PERMISSIONS_REPLACE_PKG
: UPDATE_PERMISSIONS_REPLACE_PKG);
- updatePermissions(packageName, pkg, getVolumeUuidForPackage(pkg), flags,
- mDefaultPermissionCallback, filterUserId);
+ updatePermissions(
+ packageName, pkg, getVolumeUuidForPackage(pkg), flags, mDefaultPermissionCallback);
}
/**
@@ -4072,8 +4069,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
(fingerprintChanged
? UPDATE_PERMISSIONS_REPLACE_PKG | UPDATE_PERMISSIONS_REPLACE_ALL
: 0);
- updatePermissions(null, null, volumeUuid, flags, mDefaultPermissionCallback,
- UserHandle.USER_ALL);
+ updatePermissions(null, null, volumeUuid, flags, mDefaultPermissionCallback);
} finally {
PackageManager.uncorkPackageInfoCache();
}
@@ -4122,14 +4118,12 @@ public class PermissionManagerService extends IPermissionManager.Stub {
* all volumes
* @param flags Control permission for which apps should be updated
* @param callback Callback to call after permission changes
- * @param filterUserId If not {@link UserHandle.USER_ALL}, only restore the permission state for
- * this particular user
*/
private void updatePermissions(final @Nullable String changingPkgName,
final @Nullable AndroidPackage changingPkg,
final @Nullable String replaceVolumeUuid,
@UpdatePermissionFlags int flags,
- final @Nullable PermissionCallback callback, @UserIdInt int filterUserId) {
+ final @Nullable PermissionCallback callback) {
// TODO: Most of the methods exposing BasePermission internals [source package name,
// etc..] shouldn't be needed. Instead, when we've parsed a permission that doesn't
// have package settings, we should make note of it elsewhere [map between
@@ -4165,7 +4159,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
// Only replace for packages on requested volume
final String volumeUuid = getVolumeUuidForPackage(pkg);
final boolean replace = replaceAll && Objects.equals(replaceVolumeUuid, volumeUuid);
- restorePermissionState(pkg, replace, changingPkgName, callback, filterUserId);
+ restorePermissionState(pkg, replace, changingPkgName, callback,
+ UserHandle.USER_ALL);
});
}
@@ -4174,7 +4169,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
final String volumeUuid = getVolumeUuidForPackage(changingPkg);
final boolean replace = ((flags & UPDATE_PERMISSIONS_REPLACE_PKG) != 0)
&& Objects.equals(replaceVolumeUuid, volumeUuid);
- restorePermissionState(changingPkg, replace, changingPkgName, callback, filterUserId);
+ restorePermissionState(changingPkg, replace, changingPkgName, callback,
+ UserHandle.USER_ALL);
}
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
@@ -4841,18 +4837,20 @@ public class PermissionManagerService extends IPermissionManager.Stub {
private void onPackageInstalledInternal(@NonNull AndroidPackage pkg,
@NonNull PermissionManagerServiceInternal.PackageInstalledParams params,
- @UserIdInt int userId) {
- updatePermissions(pkg.getPackageName(), pkg, userId);
- addAllowlistedRestrictedPermissionsInternal(pkg,
- params.getAllowlistedRestrictedPermissions(),
- FLAG_PERMISSION_WHITELIST_INSTALLER, userId);
- final int autoRevokePermissionsMode = params.getAutoRevokePermissionsMode();
- if (autoRevokePermissionsMode == AppOpsManager.MODE_ALLOWED
- || autoRevokePermissionsMode == AppOpsManager.MODE_IGNORED) {
- setAutoRevokeExemptedInternal(pkg,
- autoRevokePermissionsMode == AppOpsManager.MODE_IGNORED, userId);
+ @UserIdInt int[] userIds) {
+ updatePermissions(pkg.getPackageName(), pkg);
+ for (final int userId : userIds) {
+ addAllowlistedRestrictedPermissionsInternal(pkg,
+ params.getAllowlistedRestrictedPermissions(),
+ FLAG_PERMISSION_WHITELIST_INSTALLER, userId);
+ final int autoRevokePermissionsMode = params.getAutoRevokePermissionsMode();
+ if (autoRevokePermissionsMode == AppOpsManager.MODE_ALLOWED
+ || autoRevokePermissionsMode == AppOpsManager.MODE_IGNORED) {
+ setAutoRevokeExemptedInternal(pkg,
+ autoRevokePermissionsMode == AppOpsManager.MODE_IGNORED, userId);
+ }
+ grantRequestedRuntimePermissionsInternal(pkg, params.getGrantedPermissions(), userId);
}
- grantRequestedRuntimePermissionsInternal(pkg, params.getGrantedPermissions(), userId);
}
private void addAllowlistedRestrictedPermissionsInternal(@NonNull AndroidPackage pkg,
@@ -4875,7 +4873,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
private void onPackageUninstalledInternal(@NonNull String packageName, int appId,
@Nullable AndroidPackage pkg, @NonNull List<AndroidPackage> sharedUserPkgs,
- @UserIdInt int userId) {
+ @UserIdInt int[] userIds) {
// TODO: Move these checks to check PackageState to be more reliable.
// System packages should always have an available APK.
if (pkg != null && pkg.isSystem()
@@ -4886,27 +4884,31 @@ public class PermissionManagerService extends IPermissionManager.Stub {
// If we are only marking a system package as uninstalled, we need to keep its
// pregranted permission state so that it still works once it gets reinstalled, thus
// only reset the user modifications to its permission state.
- resetRuntimePermissionsInternal(pkg, userId);
+ for (final int userId : userIds) {
+ resetRuntimePermissionsInternal(pkg, userId);
+ }
return;
}
- updatePermissions(packageName, null, userId);
- if (sharedUserPkgs.isEmpty()) {
- removeUidStateAndResetPackageInstallPermissionsFixed(appId, packageName, userId);
- } else {
- // Remove permissions associated with package. Since runtime
- // permissions are per user we have to kill the removed package
- // or packages running under the shared user of the removed
- // package if revoking the permissions requested only by the removed
- // package is successful and this causes a change in gids.
- final int userIdToKill = revokeSharedUserPermissionsForDeletedPackageInternal(pkg,
- sharedUserPkgs, userId);
- final boolean shouldKill = userIdToKill != UserHandle.USER_NULL;
- // If gids changed, kill all affected packages.
- if (shouldKill) {
- mHandler.post(() -> {
- // This has to happen with no lock held.
- killUid(appId, UserHandle.USER_ALL, KILL_APP_REASON_GIDS_CHANGED);
- });
+ updatePermissions(packageName, null);
+ for (final int userId : userIds) {
+ if (sharedUserPkgs.isEmpty()) {
+ removeUidStateAndResetPackageInstallPermissionsFixed(appId, packageName, userId);
+ } else {
+ // Remove permissions associated with package. Since runtime
+ // permissions are per user we have to kill the removed package
+ // or packages running under the shared user of the removed
+ // package if revoking the permissions requested only by the removed
+ // package is successful and this causes a change in gids.
+ final int userIdToKill = revokeSharedUserPermissionsForDeletedPackageInternal(pkg,
+ sharedUserPkgs, userId);
+ final boolean shouldKill = userIdToKill != UserHandle.USER_NULL;
+ // If gids changed, kill all affected packages.
+ if (shouldKill) {
+ mHandler.post(() -> {
+ // This has to happen with no lock held.
+ killUid(appId, UserHandle.USER_ALL, KILL_APP_REASON_GIDS_CHANGED);
+ });
+ }
}
}
}
@@ -5181,8 +5183,11 @@ public class PermissionManagerService extends IPermissionManager.Stub {
@NonNull PackageInstalledParams params, @UserIdInt int userId) {
Objects.requireNonNull(pkg, "pkg");
Objects.requireNonNull(params, "params");
- Preconditions.checkArgumentNonNegative(userId, "userId");
- onPackageInstalledInternal(pkg, params, userId);
+ Preconditions.checkArgument(userId >= UserHandle.USER_SYSTEM
+ || userId == UserHandle.USER_ALL, "userId");
+ final int[] userIds = userId == UserHandle.USER_ALL ? getAllUserIds()
+ : new int[] { userId };
+ onPackageInstalledInternal(pkg, params, userIds);
}
@Override
@@ -5197,8 +5202,11 @@ public class PermissionManagerService extends IPermissionManager.Stub {
@UserIdInt int userId) {
Objects.requireNonNull(packageName, "packageName");
Objects.requireNonNull(sharedUserPkgs, "sharedUserPkgs");
- Preconditions.checkArgumentNonNegative(userId, "userId");
- onPackageUninstalledInternal(packageName, appId, pkg, sharedUserPkgs, userId);
+ Preconditions.checkArgument(userId >= UserHandle.USER_SYSTEM
+ || userId == UserHandle.USER_ALL, "userId");
+ final int[] userIds = userId == UserHandle.USER_ALL ? getAllUserIds()
+ : new int[] { userId };
+ onPackageUninstalledInternal(packageName, appId, pkg, sharedUserPkgs, userIds);
}
@NonNull
diff --git a/services/core/java/com/android/server/stats/pull/SystemMemoryUtil.java b/services/core/java/com/android/server/stats/pull/SystemMemoryUtil.java
index 9f8b27f5f1bf..30b6e688bab6 100644
--- a/services/core/java/com/android/server/stats/pull/SystemMemoryUtil.java
+++ b/services/core/java/com/android/server/stats/pull/SystemMemoryUtil.java
@@ -28,7 +28,7 @@ final class SystemMemoryUtil {
static Metrics getMetrics() {
int totalIonKb = (int) Debug.getDmabufHeapTotalExportedKb();
int gpuTotalUsageKb = (int) Debug.getGpuTotalUsageKb();
- int gpuDmaBufUsageKb = (int) Debug.getGpuDmaBufUsageKb();
+ int gpuPrivateAllocationsKb = (int) Debug.getGpuPrivateMemoryKb();
int dmaBufTotalExportedKb = (int) Debug.getDmabufTotalExportedKb();
long[] mInfos = new long[Debug.MEMINFO_COUNT];
@@ -58,10 +58,6 @@ final class SystemMemoryUtil {
accountedKb += mInfos[Debug.MEMINFO_KERNEL_STACK];
}
- int gpuPrivateAllocationsKb = -1;
- if (gpuTotalUsageKb >= 0 && gpuDmaBufUsageKb >= 0) {
- gpuPrivateAllocationsKb = gpuTotalUsageKb - gpuDmaBufUsageKb;
- }
// If we can distinguish gpu private allocs it means the dmabuf metrics
// are supported already.
if (dmaBufTotalExportedKb >= 0 && gpuPrivateAllocationsKb >= 0) {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index f3dbed574b06..44682525edd2 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -801,6 +801,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// Tracking cookie for the launch of this activity and it's task.
IBinder mLaunchCookie;
+ // Entering PiP is usually done in two phases, we put the task into pinned mode first and
+ // SystemUi sets the pinned mode on activity after transition is done.
+ boolean mWaitForEnteringPinnedMode;
+
private final Runnable mPauseTimeoutRunnable = new Runnable() {
@Override
public void run() {
@@ -7705,6 +7709,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// mode (see RootWindowContainer#moveActivityToPinnedRootTask). So once the windowing mode
// of activity is changed, it is the signal of the last step to update the PiP states.
if (!wasInPictureInPicture && inPinnedWindowingMode() && task != null) {
+ mWaitForEnteringPinnedMode = false;
mTaskSupervisor.scheduleUpdatePictureInPictureModeIfNeeded(task, task.getBounds());
}
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 97c19ab72918..73d31bf7e0c8 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -1568,6 +1568,10 @@ public class DisplayPolicy {
layoutStatusBar(displayFrames, mBarContentFrames.get(TYPE_STATUS_BAR));
return;
}
+ if (win.mActivityRecord != null && win.mActivityRecord.mWaitForEnteringPinnedMode) {
+ // Skip layout of the window when in transition to pip mode.
+ return;
+ }
final WindowManager.LayoutParams attrs = win.getAttrs();
final int type = attrs.type;
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 9a6a51848317..32147215834f 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2191,6 +2191,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
// from doing work and changing the activity visuals while animating
// TODO(task-org): Figure-out more structured way to do this long term.
r.setWindowingMode(intermediateWindowingMode);
+ r.mWaitForEnteringPinnedMode = true;
rootTask.setWindowingMode(WINDOWING_MODE_PINNED);
rootTask.setDeferTaskAppear(false);
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 777306aa13c5..936b2efa00ad 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -61,6 +61,8 @@ import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.SurfaceControl.METADATA_TASK_ID;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
@@ -4105,6 +4107,7 @@ class Task extends WindowContainer<WindowContainer> {
info.positionInParent = getRelativePosition();
info.pictureInPictureParams = getPictureInPictureParams(top);
+ info.displayCutoutInsets = getDisplayCutoutInsets(top);
info.topActivityInfo = mReuseActivitiesReport.top != null
? mReuseActivitiesReport.top.info
: null;
@@ -4139,6 +4142,18 @@ class Task extends WindowContainer<WindowContainer> {
? null : new PictureInPictureParams(topVisibleActivity.pictureInPictureArgs);
}
+ private Rect getDisplayCutoutInsets(Task top) {
+ if (top == null || top.mDisplayContent == null
+ || top.getDisplayInfo().displayCutout == null) return null;
+ final WindowState w = top.getTopVisibleAppMainWindow();
+ final int displayCutoutMode = w == null
+ ? WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
+ : w.getAttrs().layoutInDisplayCutoutMode;
+ return (displayCutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
+ || displayCutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES)
+ ? null : top.getDisplayInfo().displayCutout.getSafeInsets();
+ }
+
/**
* Returns a {@link TaskInfo} with information from this task.
*/
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index e9babceb87c6..193d92a3b2ff 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -15019,10 +15019,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
if (active) {
if (shouldSendNotification) {
- sendNetworkLoggingNotification();
+ mHandler.post(() -> sendNetworkLoggingNotification());
}
} else {
- mInjector.getNotificationManager().cancel(SystemMessage.NOTE_NETWORK_LOGGING);
+ mHandler.post(() -> mInjector.getNotificationManager().cancel(
+ SystemMessage.NOTE_NETWORK_LOGGING));
}
});
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
index 583797e69995..a254f68e8bed 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
@@ -514,8 +514,16 @@ public class AlarmManagerServiceTest {
}
private void setAllowWhileIdleAlarm(int type, long triggerTime, PendingIntent pi,
- boolean unrestricted) {
- final int flags = unrestricted ? FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED : FLAG_ALLOW_WHILE_IDLE;
+ boolean unrestricted, boolean compat) {
+ assertFalse("Alarm cannot be compat and unrestricted", unrestricted && compat);
+ final int flags;
+ if (unrestricted) {
+ flags = FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED;
+ } else if (compat) {
+ flags = FLAG_ALLOW_WHILE_IDLE_COMPAT;
+ } else {
+ flags = FLAG_ALLOW_WHILE_IDLE;
+ }
setTestAlarm(type, triggerTime, pi, 0, flags, TEST_CALLING_UID);
}
@@ -1600,13 +1608,13 @@ public class AlarmManagerServiceTest {
final long firstTrigger = mNowElapsedTest + 10;
for (int i = 0; i < quota; i++) {
setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, firstTrigger + i,
- getNewMockPendingIntent(), false);
+ getNewMockPendingIntent(), false, false);
mNowElapsedTest = mTestTimer.getElapsed();
mTestTimer.expire();
}
// This one should get deferred on set.
setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, firstTrigger + quota,
- getNewMockPendingIntent(), false);
+ getNewMockPendingIntent(), false, false);
final long expectedNextTrigger = firstTrigger + mAllowWhileIdleWindow;
assertEquals("Incorrect trigger when no quota left", expectedNextTrigger,
mTestTimer.getElapsed());
@@ -1619,6 +1627,108 @@ public class AlarmManagerServiceTest {
}
@Test
+ public void allowWhileIdleCompatAlarmsWhileDeviceIdle() throws Exception {
+ setDeviceConfigLong(KEY_MAX_DEVICE_IDLE_FUZZ, 0);
+
+ final long window = mService.mConstants.ALLOW_WHILE_IDLE_COMPAT_WINDOW;
+ setIdleUntilAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + window + 1000,
+ getNewMockPendingIntent());
+ assertNotNull(mService.mPendingIdleUntil);
+
+ final int quota = mService.mConstants.ALLOW_WHILE_IDLE_COMPAT_QUOTA;
+ final long firstTrigger = mNowElapsedTest + 10;
+ for (int i = 0; i < quota; i++) {
+ setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, firstTrigger + i,
+ getNewMockPendingIntent(), false, true);
+ mNowElapsedTest = mTestTimer.getElapsed();
+ mTestTimer.expire();
+ }
+ // This one should get deferred on set.
+ setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, firstTrigger + quota,
+ getNewMockPendingIntent(), false, true);
+ final long expectedNextTrigger = firstTrigger + window;
+ assertEquals("Incorrect trigger when no quota left", expectedNextTrigger,
+ mTestTimer.getElapsed());
+
+ // Bring the idle until alarm back.
+ setIdleUntilAlarm(ELAPSED_REALTIME_WAKEUP, expectedNextTrigger - 50,
+ getNewMockPendingIntent());
+ assertEquals(expectedNextTrigger - 50, mService.mPendingIdleUntil.getWhenElapsed());
+ assertEquals(expectedNextTrigger - 50, mTestTimer.getElapsed());
+ }
+
+ @Test
+ public void allowWhileIdleCompatHistorySeparate() throws Exception {
+ when(mAppStateTracker.areAlarmsRestrictedByBatterySaver(TEST_CALLING_UID,
+ TEST_CALLING_PACKAGE)).thenReturn(true);
+ when(mAppStateTracker.isForceAllAppsStandbyEnabled()).thenReturn(true);
+
+ final int fullQuota = mService.mConstants.ALLOW_WHILE_IDLE_QUOTA;
+ final int compatQuota = mService.mConstants.ALLOW_WHILE_IDLE_COMPAT_QUOTA;
+
+ final long fullWindow = mAllowWhileIdleWindow;
+ final long compatWindow = mService.mConstants.ALLOW_WHILE_IDLE_COMPAT_WINDOW;
+
+ final long firstFullTrigger = mNowElapsedTest + 10;
+ for (int i = 0; i < fullQuota; i++) {
+ setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, firstFullTrigger + i,
+ getNewMockPendingIntent(), false, false);
+ mNowElapsedTest = mTestTimer.getElapsed();
+ mTestTimer.expire();
+ }
+ // This one should get deferred on set, as full quota is not available.
+ setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, firstFullTrigger + fullQuota,
+ getNewMockPendingIntent(), false, false);
+ final long expectedNextFullTrigger = firstFullTrigger + fullWindow;
+ assertEquals("Incorrect trigger when no quota left", expectedNextFullTrigger,
+ mTestTimer.getElapsed());
+ mService.removeLocked(TEST_CALLING_UID, REMOVE_REASON_UNDEFINED);
+
+ // The following should be allowed, as compat quota should be free.
+ for (int i = 0; i < compatQuota; i++) {
+ final long trigger = mNowElapsedTest + 1;
+ setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, trigger, getNewMockPendingIntent(),
+ false, true);
+ assertEquals(trigger, mTestTimer.getElapsed());
+ mNowElapsedTest = mTestTimer.getElapsed();
+ mTestTimer.expire();
+ }
+
+ // Refresh the state
+ mService.removeLocked(TEST_CALLING_UID, REMOVE_REASON_UNDEFINED);
+ mService.mAllowWhileIdleHistory.removeForPackage(TEST_CALLING_PACKAGE, TEST_CALLING_USER);
+ mService.mAllowWhileIdleCompatHistory.removeForPackage(TEST_CALLING_PACKAGE,
+ TEST_CALLING_USER);
+
+ // Now test with flipped order
+
+ final long firstCompatTrigger = mNowElapsedTest + 10;
+ for (int i = 0; i < compatQuota; i++) {
+ setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, firstCompatTrigger + i,
+ getNewMockPendingIntent(), false, true);
+ mNowElapsedTest = mTestTimer.getElapsed();
+ mTestTimer.expire();
+ }
+ // This one should get deferred on set, as full quota is not available.
+ setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, firstCompatTrigger + compatQuota,
+ getNewMockPendingIntent(), false, true);
+ final long expectedNextCompatTrigger = firstCompatTrigger + compatWindow;
+ assertEquals("Incorrect trigger when no quota left", expectedNextCompatTrigger,
+ mTestTimer.getElapsed());
+ mService.removeLocked(TEST_CALLING_UID, REMOVE_REASON_UNDEFINED);
+
+ // The following should be allowed, as full quota should be free.
+ for (int i = 0; i < fullQuota; i++) {
+ final long trigger = mNowElapsedTest + 1;
+ setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, trigger, getNewMockPendingIntent(),
+ false, false);
+ assertEquals(trigger, mTestTimer.getElapsed());
+ mNowElapsedTest = mTestTimer.getElapsed();
+ mTestTimer.expire();
+ }
+ }
+
+ @Test
public void allowWhileIdleUnrestricted() throws Exception {
setDeviceConfigLong(KEY_MAX_DEVICE_IDLE_FUZZ, 0);
@@ -1634,7 +1744,7 @@ public class AlarmManagerServiceTest {
final long firstTrigger = mNowElapsedTest + 10;
for (int i = 0; i < numAlarms; i++) {
setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, firstTrigger + i,
- getNewMockPendingIntent(), true);
+ getNewMockPendingIntent(), true, false);
}
// All of them should fire as expected.
for (int i = 0; i < numAlarms; i++) {
@@ -1736,7 +1846,7 @@ public class AlarmManagerServiceTest {
final int quota = mService.mConstants.ALLOW_WHILE_IDLE_QUOTA;
testQuotasDeferralOnSet(trigger -> setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, trigger,
- getNewMockPendingIntent(), false), quota, mAllowWhileIdleWindow);
+ getNewMockPendingIntent(), false, false), quota, mAllowWhileIdleWindow);
// Refresh the state
mService.removeLocked(TEST_CALLING_UID,
@@ -1744,7 +1854,7 @@ public class AlarmManagerServiceTest {
mService.mAllowWhileIdleHistory.removeForPackage(TEST_CALLING_PACKAGE, TEST_CALLING_USER);
testQuotasDeferralOnExpiration(trigger -> setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP,
- trigger, getNewMockPendingIntent(), false), quota, mAllowWhileIdleWindow);
+ trigger, getNewMockPendingIntent(), false, false), quota, mAllowWhileIdleWindow);
// Refresh the state
mService.removeLocked(TEST_CALLING_UID,
@@ -1752,7 +1862,36 @@ public class AlarmManagerServiceTest {
mService.mAllowWhileIdleHistory.removeForPackage(TEST_CALLING_PACKAGE, TEST_CALLING_USER);
testQuotasNoDeferral(trigger -> setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, trigger,
- getNewMockPendingIntent(), false), quota, mAllowWhileIdleWindow);
+ getNewMockPendingIntent(), false, false), quota, mAllowWhileIdleWindow);
+ }
+
+ @Test
+ public void allowWhileIdleCompatAlarmsInBatterySaver() throws Exception {
+ when(mAppStateTracker.areAlarmsRestrictedByBatterySaver(TEST_CALLING_UID,
+ TEST_CALLING_PACKAGE)).thenReturn(true);
+ when(mAppStateTracker.isForceAllAppsStandbyEnabled()).thenReturn(true);
+
+ final int quota = mService.mConstants.ALLOW_WHILE_IDLE_COMPAT_QUOTA;
+ final long window = mService.mConstants.ALLOW_WHILE_IDLE_COMPAT_WINDOW;
+
+ testQuotasDeferralOnSet(trigger -> setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, trigger,
+ getNewMockPendingIntent(), false, true), quota, window);
+
+ // Refresh the state
+ mService.removeLocked(TEST_CALLING_UID, REMOVE_REASON_UNDEFINED);
+ mService.mAllowWhileIdleCompatHistory.removeForPackage(TEST_CALLING_PACKAGE,
+ TEST_CALLING_USER);
+
+ testQuotasDeferralOnExpiration(trigger -> setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP,
+ trigger, getNewMockPendingIntent(), false, true), quota, window);
+
+ // Refresh the state
+ mService.removeLocked(TEST_CALLING_UID, REMOVE_REASON_UNDEFINED);
+ mService.mAllowWhileIdleCompatHistory.removeForPackage(TEST_CALLING_PACKAGE,
+ TEST_CALLING_USER);
+
+ testQuotasNoDeferral(trigger -> setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, trigger,
+ getNewMockPendingIntent(), false, true), quota, window);
}
@Test
@@ -2123,7 +2262,7 @@ public class AlarmManagerServiceTest {
final PendingIntent alarmPi = getNewMockPendingIntent();
final AlarmManager.AlarmClockInfo alarmClock = mock(AlarmManager.AlarmClockInfo.class);
mBinder.set(TEST_CALLING_PACKAGE, RTC_WAKEUP, 1234, WINDOW_EXACT, 0, 0,
- alarmPi, null, null, null, alarmClock);
+ alarmPi, null, null, null, alarmClock);
// Correct permission checks are invoked.
verify(mService).hasScheduleExactAlarmInternal(TEST_CALLING_PACKAGE, TEST_CALLING_UID);
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java
index 91f49224fde8..5b067bc58da3 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java
@@ -869,6 +869,446 @@ public class AppSearchImplTest {
}
@Test
+ public void testGetNextPageToken_query() throws Exception {
+ // Insert package1 schema
+ List<AppSearchSchema> schema1 =
+ ImmutableList.of(new AppSearchSchema.Builder("schema1").build());
+ mAppSearchImpl.setSchema(
+ "package1",
+ "database1",
+ schema1,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0);
+
+ // Insert two package1 documents
+ GenericDocument document1 =
+ new GenericDocument.Builder<>("namespace", "id1", "schema1").build();
+ GenericDocument document2 =
+ new GenericDocument.Builder<>("namespace", "id2", "schema1").build();
+ mAppSearchImpl.putDocument("package1", "database1", document1, /*logger=*/ null);
+ mAppSearchImpl.putDocument("package1", "database1", document2, /*logger=*/ null);
+
+ // Query for only 1 result per page
+ SearchSpec searchSpec =
+ new SearchSpec.Builder()
+ .setTermMatch(TermMatchType.Code.PREFIX_VALUE)
+ .setResultCountPerPage(1)
+ .build();
+ SearchResultPage searchResultPage =
+ mAppSearchImpl.query("package1", "database1", "", searchSpec, /*logger=*/ null);
+
+ // Document2 will come first because it was inserted last and default return order is
+ // most recent.
+ assertThat(searchResultPage.getResults()).hasSize(1);
+ assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document2);
+
+ long nextPageToken = searchResultPage.getNextPageToken();
+ searchResultPage = mAppSearchImpl.getNextPage("package1", nextPageToken);
+ assertThat(searchResultPage.getResults()).hasSize(1);
+ assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document1);
+ }
+
+ @Test
+ public void testGetNextPageWithDifferentPackage_query() throws Exception {
+ // Insert package1 schema
+ List<AppSearchSchema> schema1 =
+ ImmutableList.of(new AppSearchSchema.Builder("schema1").build());
+ mAppSearchImpl.setSchema(
+ "package1",
+ "database1",
+ schema1,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0);
+
+ // Insert two package1 documents
+ GenericDocument document1 =
+ new GenericDocument.Builder<>("namespace", "id1", "schema1").build();
+ GenericDocument document2 =
+ new GenericDocument.Builder<>("namespace", "id2", "schema1").build();
+ mAppSearchImpl.putDocument("package1", "database1", document1, /*logger=*/ null);
+ mAppSearchImpl.putDocument("package1", "database1", document2, /*logger=*/ null);
+
+ // Query for only 1 result per page
+ SearchSpec searchSpec =
+ new SearchSpec.Builder()
+ .setTermMatch(TermMatchType.Code.PREFIX_VALUE)
+ .setResultCountPerPage(1)
+ .build();
+ SearchResultPage searchResultPage =
+ mAppSearchImpl.query("package1", "database1", "", searchSpec, /*logger=*/ null);
+
+ // Document2 will come first because it was inserted last and default return order is
+ // most recent.
+ assertThat(searchResultPage.getResults()).hasSize(1);
+ assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document2);
+
+ long nextPageToken = searchResultPage.getNextPageToken();
+
+ // Try getting next page with the wrong package, package2
+ AppSearchException e =
+ assertThrows(
+ AppSearchException.class,
+ () -> mAppSearchImpl.getNextPage("package2", nextPageToken));
+ assertThat(e)
+ .hasMessageThat()
+ .contains("Package \"package2\" cannot use nextPageToken: " + nextPageToken);
+ assertThat(e.getResultCode()).isEqualTo(AppSearchResult.RESULT_SECURITY_ERROR);
+
+ // Can continue getting next page for package1
+ searchResultPage = mAppSearchImpl.getNextPage("package1", nextPageToken);
+ assertThat(searchResultPage.getResults()).hasSize(1);
+ assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document1);
+ }
+
+ @Test
+ public void testGetNextPageToken_globalQuery() throws Exception {
+ // Insert package1 schema
+ List<AppSearchSchema> schema1 =
+ ImmutableList.of(new AppSearchSchema.Builder("schema1").build());
+ mAppSearchImpl.setSchema(
+ "package1",
+ "database1",
+ schema1,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0);
+
+ // Insert two package1 documents
+ GenericDocument document1 =
+ new GenericDocument.Builder<>("namespace", "id1", "schema1").build();
+ GenericDocument document2 =
+ new GenericDocument.Builder<>("namespace", "id2", "schema1").build();
+ mAppSearchImpl.putDocument("package1", "database1", document1, /*logger=*/ null);
+ mAppSearchImpl.putDocument("package1", "database1", document2, /*logger=*/ null);
+
+ // Query for only 1 result per page
+ SearchSpec searchSpec =
+ new SearchSpec.Builder()
+ .setTermMatch(TermMatchType.Code.PREFIX_VALUE)
+ .setResultCountPerPage(1)
+ .build();
+ SearchResultPage searchResultPage =
+ mAppSearchImpl.globalQuery(
+ /*queryExpression=*/ "",
+ searchSpec,
+ "package1",
+ /*visibilityStore=*/ null,
+ Process.myUid(),
+ /*callerHasSystemAccess=*/ false,
+ /*logger=*/ null);
+
+ // Document2 will come first because it was inserted last and default return order is
+ // most recent.
+ assertThat(searchResultPage.getResults()).hasSize(1);
+ assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document2);
+
+ long nextPageToken = searchResultPage.getNextPageToken();
+ searchResultPage = mAppSearchImpl.getNextPage("package1", nextPageToken);
+ assertThat(searchResultPage.getResults()).hasSize(1);
+ assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document1);
+ }
+
+ @Test
+ public void testGetNextPageWithDifferentPackage_globalQuery() throws Exception {
+ // Insert package1 schema
+ List<AppSearchSchema> schema1 =
+ ImmutableList.of(new AppSearchSchema.Builder("schema1").build());
+ mAppSearchImpl.setSchema(
+ "package1",
+ "database1",
+ schema1,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0);
+
+ // Insert two package1 documents
+ GenericDocument document1 =
+ new GenericDocument.Builder<>("namespace", "id1", "schema1").build();
+ GenericDocument document2 =
+ new GenericDocument.Builder<>("namespace", "id2", "schema1").build();
+ mAppSearchImpl.putDocument("package1", "database1", document1, /*logger=*/ null);
+ mAppSearchImpl.putDocument("package1", "database1", document2, /*logger=*/ null);
+
+ // Query for only 1 result per page
+ SearchSpec searchSpec =
+ new SearchSpec.Builder()
+ .setTermMatch(TermMatchType.Code.PREFIX_VALUE)
+ .setResultCountPerPage(1)
+ .build();
+ SearchResultPage searchResultPage =
+ mAppSearchImpl.globalQuery(
+ /*queryExpression=*/ "",
+ searchSpec,
+ "package1",
+ /*visibilityStore=*/ null,
+ Process.myUid(),
+ /*callerHasSystemAccess=*/ false,
+ /*logger=*/ null);
+
+ // Document2 will come first because it was inserted last and default return order is
+ // most recent.
+ assertThat(searchResultPage.getResults()).hasSize(1);
+ assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document2);
+
+ long nextPageToken = searchResultPage.getNextPageToken();
+
+ // Try getting next page with the wrong package, package2
+ AppSearchException e =
+ assertThrows(
+ AppSearchException.class,
+ () -> mAppSearchImpl.getNextPage("package2", nextPageToken));
+ assertThat(e)
+ .hasMessageThat()
+ .contains("Package \"package2\" cannot use nextPageToken: " + nextPageToken);
+ assertThat(e.getResultCode()).isEqualTo(AppSearchResult.RESULT_SECURITY_ERROR);
+
+ // Can continue getting next page for package1
+ searchResultPage = mAppSearchImpl.getNextPage("package1", nextPageToken);
+ assertThat(searchResultPage.getResults()).hasSize(1);
+ assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document1);
+ }
+
+ @Test
+ public void testInvalidateNextPageToken_query() throws Exception {
+ // Insert package1 schema
+ List<AppSearchSchema> schema1 =
+ ImmutableList.of(new AppSearchSchema.Builder("schema1").build());
+ mAppSearchImpl.setSchema(
+ "package1",
+ "database1",
+ schema1,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0);
+
+ // Insert two package1 documents
+ GenericDocument document1 =
+ new GenericDocument.Builder<>("namespace", "id1", "schema1").build();
+ GenericDocument document2 =
+ new GenericDocument.Builder<>("namespace", "id2", "schema1").build();
+ mAppSearchImpl.putDocument("package1", "database1", document1, /*logger=*/ null);
+ mAppSearchImpl.putDocument("package1", "database1", document2, /*logger=*/ null);
+
+ // Query for only 1 result per page
+ SearchSpec searchSpec =
+ new SearchSpec.Builder()
+ .setTermMatch(TermMatchType.Code.PREFIX_VALUE)
+ .setResultCountPerPage(1)
+ .build();
+ SearchResultPage searchResultPage =
+ mAppSearchImpl.query("package1", "database1", "", searchSpec, /*logger=*/ null);
+
+ // Document2 will come first because it was inserted last and default return order is
+ // most recent.
+ assertThat(searchResultPage.getResults()).hasSize(1);
+ assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document2);
+
+ long nextPageToken = searchResultPage.getNextPageToken();
+
+ // Invalidate the token
+ mAppSearchImpl.invalidateNextPageToken("package1", nextPageToken);
+
+ // Can't get next page because we invalidated the token.
+ AppSearchException e =
+ assertThrows(
+ AppSearchException.class,
+ () -> mAppSearchImpl.getNextPage("package1", nextPageToken));
+ assertThat(e)
+ .hasMessageThat()
+ .contains("Package \"package1\" cannot use nextPageToken: " + nextPageToken);
+ assertThat(e.getResultCode()).isEqualTo(AppSearchResult.RESULT_SECURITY_ERROR);
+ }
+
+ @Test
+ public void testInvalidateNextPageTokenWithDifferentPackage_query() throws Exception {
+ // Insert package1 schema
+ List<AppSearchSchema> schema1 =
+ ImmutableList.of(new AppSearchSchema.Builder("schema1").build());
+ mAppSearchImpl.setSchema(
+ "package1",
+ "database1",
+ schema1,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0);
+
+ // Insert two package1 documents
+ GenericDocument document1 =
+ new GenericDocument.Builder<>("namespace", "id1", "schema1").build();
+ GenericDocument document2 =
+ new GenericDocument.Builder<>("namespace", "id2", "schema1").build();
+ mAppSearchImpl.putDocument("package1", "database1", document1, /*logger=*/ null);
+ mAppSearchImpl.putDocument("package1", "database1", document2, /*logger=*/ null);
+
+ // Query for only 1 result per page
+ SearchSpec searchSpec =
+ new SearchSpec.Builder()
+ .setTermMatch(TermMatchType.Code.PREFIX_VALUE)
+ .setResultCountPerPage(1)
+ .build();
+ SearchResultPage searchResultPage =
+ mAppSearchImpl.query("package1", "database1", "", searchSpec, /*logger=*/ null);
+
+ // Document2 will come first because it was inserted last and default return order is
+ // most recent.
+ assertThat(searchResultPage.getResults()).hasSize(1);
+ assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document2);
+
+ long nextPageToken = searchResultPage.getNextPageToken();
+
+ // Try getting next page with the wrong package, package2
+ AppSearchException e =
+ assertThrows(
+ AppSearchException.class,
+ () -> mAppSearchImpl.invalidateNextPageToken("package2", nextPageToken));
+ assertThat(e)
+ .hasMessageThat()
+ .contains("Package \"package2\" cannot use nextPageToken: " + nextPageToken);
+ assertThat(e.getResultCode()).isEqualTo(AppSearchResult.RESULT_SECURITY_ERROR);
+
+ // Can continue getting next page for package1
+ searchResultPage = mAppSearchImpl.getNextPage("package1", nextPageToken);
+ assertThat(searchResultPage.getResults()).hasSize(1);
+ assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document1);
+ }
+
+ @Test
+ public void testInvalidateNextPageToken_globalQuery() throws Exception {
+ // Insert package1 schema
+ List<AppSearchSchema> schema1 =
+ ImmutableList.of(new AppSearchSchema.Builder("schema1").build());
+ mAppSearchImpl.setSchema(
+ "package1",
+ "database1",
+ schema1,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0);
+
+ // Insert two package1 documents
+ GenericDocument document1 =
+ new GenericDocument.Builder<>("namespace", "id1", "schema1").build();
+ GenericDocument document2 =
+ new GenericDocument.Builder<>("namespace", "id2", "schema1").build();
+ mAppSearchImpl.putDocument("package1", "database1", document1, /*logger=*/ null);
+ mAppSearchImpl.putDocument("package1", "database1", document2, /*logger=*/ null);
+
+ // Query for only 1 result per page
+ SearchSpec searchSpec =
+ new SearchSpec.Builder()
+ .setTermMatch(TermMatchType.Code.PREFIX_VALUE)
+ .setResultCountPerPage(1)
+ .build();
+ SearchResultPage searchResultPage =
+ mAppSearchImpl.globalQuery(
+ /*queryExpression=*/ "",
+ searchSpec,
+ "package1",
+ /*visibilityStore=*/ null,
+ Process.myUid(),
+ /*callerHasSystemAccess=*/ false,
+ /*logger=*/ null);
+
+ // Document2 will come first because it was inserted last and default return order is
+ // most recent.
+ assertThat(searchResultPage.getResults()).hasSize(1);
+ assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document2);
+
+ long nextPageToken = searchResultPage.getNextPageToken();
+
+ // Invalidate the token
+ mAppSearchImpl.invalidateNextPageToken("package1", nextPageToken);
+
+ // Can't get next page because we invalidated the token.
+ AppSearchException e =
+ assertThrows(
+ AppSearchException.class,
+ () -> mAppSearchImpl.getNextPage("package1", nextPageToken));
+ assertThat(e)
+ .hasMessageThat()
+ .contains("Package \"package1\" cannot use nextPageToken: " + nextPageToken);
+ assertThat(e.getResultCode()).isEqualTo(AppSearchResult.RESULT_SECURITY_ERROR);
+ }
+
+ @Test
+ public void testInvalidateNextPageTokenWithDifferentPackage_globalQuery() throws Exception {
+ // Insert package1 schema
+ List<AppSearchSchema> schema1 =
+ ImmutableList.of(new AppSearchSchema.Builder("schema1").build());
+ mAppSearchImpl.setSchema(
+ "package1",
+ "database1",
+ schema1,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0);
+
+ // Insert two package1 documents
+ GenericDocument document1 =
+ new GenericDocument.Builder<>("namespace", "id1", "schema1").build();
+ GenericDocument document2 =
+ new GenericDocument.Builder<>("namespace", "id2", "schema1").build();
+ mAppSearchImpl.putDocument("package1", "database1", document1, /*logger=*/ null);
+ mAppSearchImpl.putDocument("package1", "database1", document2, /*logger=*/ null);
+
+ // Query for only 1 result per page
+ SearchSpec searchSpec =
+ new SearchSpec.Builder()
+ .setTermMatch(TermMatchType.Code.PREFIX_VALUE)
+ .setResultCountPerPage(1)
+ .build();
+ SearchResultPage searchResultPage =
+ mAppSearchImpl.globalQuery(
+ /*queryExpression=*/ "",
+ searchSpec,
+ "package1",
+ /*visibilityStore=*/ null,
+ Process.myUid(),
+ /*callerHasSystemAccess=*/ false,
+ /*logger=*/ null);
+
+ // Document2 will come first because it was inserted last and default return order is
+ // most recent.
+ assertThat(searchResultPage.getResults()).hasSize(1);
+ assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document2);
+
+ long nextPageToken = searchResultPage.getNextPageToken();
+
+ // Try getting next page with the wrong package, package2
+ AppSearchException e =
+ assertThrows(
+ AppSearchException.class,
+ () -> mAppSearchImpl.invalidateNextPageToken("package2", nextPageToken));
+ assertThat(e)
+ .hasMessageThat()
+ .contains("Package \"package2\" cannot use nextPageToken: " + nextPageToken);
+ assertThat(e.getResultCode()).isEqualTo(AppSearchResult.RESULT_SECURITY_ERROR);
+
+ // Can continue getting next page for package1
+ searchResultPage = mAppSearchImpl.getNextPage("package1", nextPageToken);
+ assertThat(searchResultPage.getResults()).hasSize(1);
+ assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document1);
+ }
+
+ @Test
public void testRemoveEmptyDatabase_noExceptionThrown() throws Exception {
SearchSpec searchSpec =
new SearchSpec.Builder()
@@ -1777,11 +2217,11 @@ public class AppSearchImplTest {
assertThrows(
IllegalStateException.class,
- () -> appSearchImpl.getNextPage(/*nextPageToken=*/ 1L));
+ () -> appSearchImpl.getNextPage("package", /*nextPageToken=*/ 1L));
assertThrows(
IllegalStateException.class,
- () -> appSearchImpl.invalidateNextPageToken(/*nextPageToken=*/ 1L));
+ () -> appSearchImpl.invalidateNextPageToken("package", /*nextPageToken=*/ 1L));
assertThrows(
IllegalStateException.class,