diff options
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 <b><xliff:g id="APP">%s</xliff:g></b> 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您可以在“设置”>“无障碍”中将此快捷方式更改为开启另一项功能。"</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 <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</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 <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pour gérer votre <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string> + <string name="confirmation_title" msgid="8455544820286920304">"Autoriser <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à gérer votre <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</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 Binary files differindex e88e1ba97ca7..0c3c4bb24208 100644 --- a/packages/CtsShim/apk/arm/CtsShim.apk +++ b/packages/CtsShim/apk/arm/CtsShim.apk diff --git a/packages/CtsShim/apk/arm/CtsShimPriv.apk b/packages/CtsShim/apk/arm/CtsShimPriv.apk Binary files differindex f35732cec024..ee42d081f2f2 100644 --- a/packages/CtsShim/apk/arm/CtsShimPriv.apk +++ b/packages/CtsShim/apk/arm/CtsShimPriv.apk diff --git a/packages/CtsShim/apk/x86/CtsShim.apk b/packages/CtsShim/apk/x86/CtsShim.apk Binary files differindex e88e1ba97ca7..0c3c4bb24208 100644 --- a/packages/CtsShim/apk/x86/CtsShim.apk +++ b/packages/CtsShim/apk/x86/CtsShim.apk diff --git a/packages/CtsShim/apk/x86/CtsShimPriv.apk b/packages/CtsShim/apk/x86/CtsShimPriv.apk Binary files differindex 3d9f749f4e48..2bb3750b200d 100644 --- a/packages/CtsShim/apk/x86/CtsShimPriv.apk +++ b/packages/CtsShim/apk/x86/CtsShimPriv.apk 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, |