diff options
99 files changed, 1590 insertions, 532 deletions
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 77aa14c37d79..28069743d957 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java @@ -37,6 +37,7 @@ import android.os.Bundle;  import android.os.ParcelableException;  import android.os.RemoteException;  import android.os.UserHandle; +import android.os.UserManager;  import android.util.ArrayMap;  import android.util.ArraySet;  import android.util.Log; @@ -58,6 +59,7 @@ public class AppSearchManagerService extends SystemService {      private static final String TAG = "AppSearchManagerService";      private PackageManagerInternal mPackageManagerInternal;      private ImplInstanceManager mImplInstanceManager; +    private UserManager mUserManager;      // Cache of unlocked user ids so we don't have to query UserManager service each time. The      // "locked" suffix refers to the fact that access to the field should be locked; unrelated to @@ -74,10 +76,11 @@ public class AppSearchManagerService extends SystemService {          publishBinderService(Context.APP_SEARCH_SERVICE, new Stub());          mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);          mImplInstanceManager = ImplInstanceManager.getInstance(getContext()); +        mUserManager = getContext().getSystemService(UserManager.class);      }      @Override -    public void onUserUnlocked(@NonNull TargetUser user) { +    public void onUserUnlocking(@NonNull TargetUser user) {          synchronized (mUnlockedUserIdsLocked) {              mUnlockedUserIdsLocked.add(user.getUserIdentifier());          } @@ -509,7 +512,13 @@ public class AppSearchManagerService extends SystemService {          private void verifyUserUnlocked(int callingUserId) {              synchronized (mUnlockedUserIdsLocked) { -                if (!mUnlockedUserIdsLocked.contains(callingUserId)) { +                // First, check the local copy. +                if (mUnlockedUserIdsLocked.contains(callingUserId)) { +                    return; +                } +                // If the local copy says the user is locked, check with UM for the actual state, +                // since the user might just have been unlocked. +                if (!mUserManager.isUserUnlockingOrUnlocked(UserHandle.of(callingUserId))) {                      throw new IllegalStateException(                              "User " + callingUserId + " is locked or not running.");                  } diff --git a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java index 2ce85ee57205..8c06338560bf 100644 --- a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java +++ b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java @@ -136,6 +136,23 @@ public interface AppStandbyInternal {      void restrictApp(@NonNull String packageName, int userId,              @SystemForcedReasons int restrictReason); +    /** +     * Put the specified app in the +     * {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_RESTRICTED} +     * bucket. If it has been used by the user recently, the restriction will delayed +     * until an appropriate time. This should only be used in cases where +     * {@link #restrictApp(String, int, int)} is not sufficient. +     * +     * @param mainReason     The main reason for restricting the app. Must be either {@link +     *                       android.app.usage.UsageStatsManager#REASON_MAIN_FORCED_BY_SYSTEM} or +     *                       {@link android.app.usage.UsageStatsManager#REASON_MAIN_FORCED_BY_USER}. +     *                       Calls providing any other value will be ignored. +     * @param restrictReason The restrictReason for restricting the app. Should be one of the +     *                       UsageStatsManager.REASON_SUB_FORCED_SYSTEM_FLAG_* reasons. +     */ +    void restrictApp(@NonNull String packageName, int userId, int mainReason, +            @SystemForcedReasons int restrictReason); +      void addActiveDeviceAdmin(String adminPkg, int userId);      void setActiveAdminApps(Set<String> adminPkgs, int userId); diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java index 82f2f69bbde5..2b08ba554404 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java @@ -793,6 +793,13 @@ public class JobSchedulerService extends com.android.server.SystemService                          mDebuggableApps.remove(pkgName);                      }                  } +            } else if (Intent.ACTION_USER_ADDED.equals(action)) { +                final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0); +                synchronized (mLock) { +                    for (int c = 0; c < mControllers.size(); ++c) { +                        mControllers.get(c).onUserAddedLocked(userId); +                    } +                }              } else if (Intent.ACTION_USER_REMOVED.equals(action)) {                  final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);                  if (DEBUG) { @@ -1454,6 +1461,7 @@ public class JobSchedulerService extends com.android.server.SystemService              getContext().registerReceiverAsUser(                      mBroadcastReceiver, UserHandle.ALL, filter, null, null);              final IntentFilter userFilter = new IntentFilter(Intent.ACTION_USER_REMOVED); +            userFilter.addAction(Intent.ACTION_USER_ADDED);              getContext().registerReceiverAsUser(                      mBroadcastReceiver, UserHandle.ALL, userFilter, null, null);              try { diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java index 784c63a6cf1f..2b79969f4378 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java @@ -28,6 +28,7 @@ import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX;  import static com.android.server.job.JobSchedulerService.WORKING_INDEX;  import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock; +import android.Manifest;  import android.annotation.NonNull;  import android.annotation.Nullable;  import android.annotation.UserIdInt; @@ -42,7 +43,9 @@ import android.content.BroadcastReceiver;  import android.content.Context;  import android.content.Intent;  import android.content.IntentFilter; -import android.content.pm.PackageManagerInternal; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager;  import android.os.BatteryManager;  import android.os.BatteryManagerInternal;  import android.os.Handler; @@ -118,6 +121,10 @@ public final class QuotaController extends StateController {      private static final String ALARM_TAG_CLEANUP = "*job.cleanup*";      private static final String ALARM_TAG_QUOTA_CHECK = "*job.quota_check*"; +    private static final int SYSTEM_APP_CHECK_FLAGS = +            PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE +                    | PackageManager.GET_PERMISSIONS | PackageManager.MATCH_KNOWN_PACKAGES; +      /**       * Standardize the output of userId-packageName combo.       */ @@ -526,7 +533,9 @@ public final class QuotaController extends StateController {              QcConstants.DEFAULT_EJ_LIMIT_RESTRICTED_MS      }; -    private long mEjLimitSpecialAdditionMs = QcConstants.DEFAULT_EJ_LIMIT_SPECIAL_ADDITION_MS; +    private long mEjLimitAdditionInstallerMs = QcConstants.DEFAULT_EJ_LIMIT_ADDITION_INSTALLER_MS; + +    private long mEjLimitAdditionSpecialMs = QcConstants.DEFAULT_EJ_LIMIT_ADDITION_SPECIAL_MS;      /**       * The period of time used to calculate expedited job sessions. Apps can only have expedited job @@ -560,9 +569,11 @@ public final class QuotaController extends StateController {      private long mEJGracePeriodTopAppMs = QcConstants.DEFAULT_EJ_GRACE_PERIOD_TOP_APP_MS; -    /** The package verifier app. */ -    @Nullable -    private String mPackageVerifier; +    /** +     * List of system apps with the {@link android.Manifest.permission#INSTALL_PACKAGES} permission +     * granted for each user. +     */ +    private final SparseSetArray<String> mSystemInstallers = new SparseSetArray<>();      /** An app has reached its quota. The message should contain a {@link Package} object. */      @VisibleForTesting @@ -627,11 +638,8 @@ public final class QuotaController extends StateController {      @Override      public void onSystemServicesReady() { -        String[] pkgNames = LocalServices.getService(PackageManagerInternal.class) -                .getKnownPackageNames( -                        PackageManagerInternal.PACKAGE_VERIFIER, UserHandle.USER_SYSTEM);          synchronized (mLock) { -            mPackageVerifier = ArrayUtils.firstOrNull(pkgNames); +            cacheInstallerPackagesLocked(UserHandle.USER_SYSTEM);          }      } @@ -731,6 +739,11 @@ public final class QuotaController extends StateController {      }      @Override +    public void onUserAddedLocked(int userId) { +        cacheInstallerPackagesLocked(userId); +    } + +    @Override      public void onUserRemovedLocked(int userId) {          mTrackedJobs.delete(userId);          mPkgTimers.delete(userId); @@ -741,6 +754,7 @@ public final class QuotaController extends StateController {          mExecutionStatsCache.delete(userId);          mEJStats.delete(userId);          mUidToPackageCache.clear(); +        mSystemInstallers.remove(userId);      }      /** Drop all historical stats and stop tracking any active sessions for the specified app. */ @@ -767,6 +781,22 @@ public final class QuotaController extends StateController {          mEJStats.delete(userId, packageName);      } +    private void cacheInstallerPackagesLocked(int userId) { +        final List<PackageInfo> packages = mContext.getPackageManager() +                .getInstalledPackagesAsUser(SYSTEM_APP_CHECK_FLAGS, userId); +        for (int i = packages.size() - 1; i >= 0; --i) { +            final PackageInfo pi = packages.get(i); +            final ApplicationInfo ai = pi.applicationInfo; +            final int idx = ArrayUtils.indexOf( +                    pi.requestedPermissions, Manifest.permission.INSTALL_PACKAGES); + +            if (idx >= 0 && ai != null && PackageManager.PERMISSION_GRANTED +                    == mContext.checkPermission(Manifest.permission.INSTALL_PACKAGES, -1, ai.uid)) { +                mSystemInstallers.add(UserHandle.getUserId(ai.uid), pi.packageName); +            } +        } +    } +      private boolean isUidInForeground(int uid) {          if (UserHandle.isCore(uid)) {              return true; @@ -962,7 +992,8 @@ public final class QuotaController extends StateController {          if (quota.getStandbyBucketLocked() == NEVER_INDEX) {              return 0;          } -        final long limitMs = getEJLimitMsLocked(packageName, quota.getStandbyBucketLocked()); +        final long limitMs = +                getEJLimitMsLocked(userId, packageName, quota.getStandbyBucketLocked());          long remainingMs = limitMs - quota.getTallyLocked();          // Stale sessions may still be factored into tally. Make sure they're removed. @@ -1000,10 +1031,11 @@ public final class QuotaController extends StateController {          return remainingMs - timer.getCurrentDuration(sElapsedRealtimeClock.millis());      } -    private long getEJLimitMsLocked(@NonNull final String packageName, final int standbyBucket) { +    private long getEJLimitMsLocked(final int userId, @NonNull final String packageName, +            final int standbyBucket) {          final long baseLimitMs = mEJLimitsMs[standbyBucket]; -        if (packageName.equals(mPackageVerifier)) { -            return baseLimitMs + mEjLimitSpecialAdditionMs; +        if (mSystemInstallers.contains(userId, packageName)) { +            return baseLimitMs + mEjLimitAdditionInstallerMs;          }          return baseLimitMs;      } @@ -1116,7 +1148,8 @@ public final class QuotaController extends StateController {          final long nowElapsed = sElapsedRealtimeClock.millis();          ShrinkableDebits quota = getEJDebitsLocked(userId, packageName); -        final long limitMs = getEJLimitMsLocked(packageName, quota.getStandbyBucketLocked()); +        final long limitMs = +                getEJLimitMsLocked(userId, packageName, quota.getStandbyBucketLocked());          final long startWindowElapsed = Math.max(0, nowElapsed - mEJLimitWindowSizeMs);          long remainingDeadSpaceMs = remainingExecutionTimeMs;          // Total time looked at where a session wouldn't be phasing out. @@ -1743,7 +1776,8 @@ public final class QuotaController extends StateController {              inRegularQuotaTimeElapsed = inQuotaTimeElapsed;          }          if (remainingEJQuota <= 0) { -            final long limitMs = getEJLimitMsLocked(packageName, standbyBucket) - mQuotaBufferMs; +            final long limitMs = +                    getEJLimitMsLocked(userId, packageName, standbyBucket) - mQuotaBufferMs;              long sumMs = 0;              final Timer ejTimer = mEJPkgTimers.get(userId, packageName);              if (ejTimer != null && ejTimer.isActive()) { @@ -3029,8 +3063,11 @@ public final class QuotaController extends StateController {          static final String KEY_EJ_LIMIT_RESTRICTED_MS =                  QC_CONSTANT_PREFIX + "ej_limit_restricted_ms";          @VisibleForTesting -        static final String KEY_EJ_LIMIT_SPECIAL_ADDITION_MS = -                QC_CONSTANT_PREFIX + "ej_limit_special_addition_ms"; +        static final String KEY_EJ_LIMIT_ADDITION_SPECIAL_MS = +                QC_CONSTANT_PREFIX + "ej_limit_addition_special_ms"; +        @VisibleForTesting +        static final String KEY_EJ_LIMIT_ADDITION_INSTALLER_MS = +                QC_CONSTANT_PREFIX + "ej_limit_addition_installer_ms";          @VisibleForTesting          static final String KEY_EJ_WINDOW_SIZE_MS =                  QC_CONSTANT_PREFIX + "ej_window_size_ms"; @@ -3098,7 +3135,8 @@ public final class QuotaController extends StateController {          private static final long DEFAULT_EJ_LIMIT_FREQUENT_MS = 10 * MINUTE_IN_MILLIS;          private static final long DEFAULT_EJ_LIMIT_RARE_MS = DEFAULT_EJ_LIMIT_FREQUENT_MS;          private static final long DEFAULT_EJ_LIMIT_RESTRICTED_MS = 5 * MINUTE_IN_MILLIS; -        private static final long DEFAULT_EJ_LIMIT_SPECIAL_ADDITION_MS = 30 * MINUTE_IN_MILLIS; +        private static final long DEFAULT_EJ_LIMIT_ADDITION_SPECIAL_MS = 15 * MINUTE_IN_MILLIS; +        private static final long DEFAULT_EJ_LIMIT_ADDITION_INSTALLER_MS = 30 * MINUTE_IN_MILLIS;          private static final long DEFAULT_EJ_WINDOW_SIZE_MS = 24 * HOUR_IN_MILLIS;          private static final long DEFAULT_EJ_TOP_APP_TIME_CHUNK_SIZE_MS = 30 * SECOND_IN_MILLIS;          private static final long DEFAULT_EJ_REWARD_TOP_APP_MS = 10 * SECOND_IN_MILLIS; @@ -3303,7 +3341,13 @@ public final class QuotaController extends StateController {          /**           * How much additional EJ quota special, critical apps should get.           */ -        public long EJ_LIMIT_SPECIAL_ADDITION_MS = DEFAULT_EJ_LIMIT_SPECIAL_ADDITION_MS; +        public long EJ_LIMIT_ADDITION_SPECIAL_MS = DEFAULT_EJ_LIMIT_ADDITION_SPECIAL_MS; + +        /** +         * How much additional EJ quota system installers (with the INSTALL_PACKAGES permission) +         * should get. +         */ +        public long EJ_LIMIT_ADDITION_INSTALLER_MS = DEFAULT_EJ_LIMIT_ADDITION_INSTALLER_MS;          /**           * The period of time used to calculate expedited job sessions. Apps can only have expedited @@ -3369,7 +3413,8 @@ public final class QuotaController extends StateController {                  case KEY_EJ_LIMIT_FREQUENT_MS:                  case KEY_EJ_LIMIT_RARE_MS:                  case KEY_EJ_LIMIT_RESTRICTED_MS: -                case KEY_EJ_LIMIT_SPECIAL_ADDITION_MS: +                case KEY_EJ_LIMIT_ADDITION_SPECIAL_MS: +                case KEY_EJ_LIMIT_ADDITION_INSTALLER_MS:                  case KEY_EJ_WINDOW_SIZE_MS:                      updateEJLimitConstantsLocked();                      break; @@ -3704,7 +3749,8 @@ public final class QuotaController extends StateController {                      DeviceConfig.NAMESPACE_JOB_SCHEDULER,                      KEY_EJ_LIMIT_ACTIVE_MS, KEY_EJ_LIMIT_WORKING_MS,                      KEY_EJ_LIMIT_FREQUENT_MS, KEY_EJ_LIMIT_RARE_MS, -                    KEY_EJ_LIMIT_RESTRICTED_MS, KEY_EJ_LIMIT_SPECIAL_ADDITION_MS, +                    KEY_EJ_LIMIT_RESTRICTED_MS, KEY_EJ_LIMIT_ADDITION_SPECIAL_MS, +                    KEY_EJ_LIMIT_ADDITION_INSTALLER_MS,                      KEY_EJ_WINDOW_SIZE_MS);              EJ_LIMIT_ACTIVE_MS = properties.getLong(                      KEY_EJ_LIMIT_ACTIVE_MS, DEFAULT_EJ_LIMIT_ACTIVE_MS); @@ -3716,8 +3762,10 @@ public final class QuotaController extends StateController {                      KEY_EJ_LIMIT_RARE_MS, DEFAULT_EJ_LIMIT_RARE_MS);              EJ_LIMIT_RESTRICTED_MS = properties.getLong(                      KEY_EJ_LIMIT_RESTRICTED_MS, DEFAULT_EJ_LIMIT_RESTRICTED_MS); -            EJ_LIMIT_SPECIAL_ADDITION_MS = properties.getLong( -                    KEY_EJ_LIMIT_SPECIAL_ADDITION_MS, DEFAULT_EJ_LIMIT_SPECIAL_ADDITION_MS); +            EJ_LIMIT_ADDITION_INSTALLER_MS = properties.getLong( +                    KEY_EJ_LIMIT_ADDITION_INSTALLER_MS, DEFAULT_EJ_LIMIT_ADDITION_INSTALLER_MS); +            EJ_LIMIT_ADDITION_SPECIAL_MS = properties.getLong( +                    KEY_EJ_LIMIT_ADDITION_SPECIAL_MS, DEFAULT_EJ_LIMIT_ADDITION_SPECIAL_MS);              EJ_WINDOW_SIZE_MS = properties.getLong(                      KEY_EJ_WINDOW_SIZE_MS, DEFAULT_EJ_WINDOW_SIZE_MS); @@ -3763,11 +3811,17 @@ public final class QuotaController extends StateController {                  mEJLimitsMs[RESTRICTED_INDEX] = newRestrictedLimitMs;                  mShouldReevaluateConstraints = true;              } -            // The addition must be in the range [0 minutes, window size - active limit]. -            long newSpecialAdditionMs = Math.max(0, -                    Math.min(newWindowSizeMs - newActiveLimitMs, EJ_LIMIT_SPECIAL_ADDITION_MS)); -            if (mEjLimitSpecialAdditionMs != newSpecialAdditionMs) { -                mEjLimitSpecialAdditionMs = newSpecialAdditionMs; +            // The additions must be in the range [0 minutes, window size - active limit]. +            long newAdditionInstallerMs = Math.max(0, +                    Math.min(newWindowSizeMs - newActiveLimitMs, EJ_LIMIT_ADDITION_INSTALLER_MS)); +            if (mEjLimitAdditionInstallerMs != newAdditionInstallerMs) { +                mEjLimitAdditionInstallerMs = newAdditionInstallerMs; +                mShouldReevaluateConstraints = true; +            } +            long newAdditionSpecialMs = Math.max(0, +                    Math.min(newWindowSizeMs - newActiveLimitMs, EJ_LIMIT_ADDITION_SPECIAL_MS)); +            if (mEjLimitAdditionSpecialMs != newAdditionSpecialMs) { +                mEjLimitAdditionSpecialMs = newAdditionSpecialMs;                  mShouldReevaluateConstraints = true;              }          } @@ -3808,7 +3862,8 @@ public final class QuotaController extends StateController {              pw.print(KEY_EJ_LIMIT_FREQUENT_MS, EJ_LIMIT_FREQUENT_MS).println();              pw.print(KEY_EJ_LIMIT_RARE_MS, EJ_LIMIT_RARE_MS).println();              pw.print(KEY_EJ_LIMIT_RESTRICTED_MS, EJ_LIMIT_RESTRICTED_MS).println(); -            pw.print(KEY_EJ_LIMIT_SPECIAL_ADDITION_MS, EJ_LIMIT_SPECIAL_ADDITION_MS).println(); +            pw.print(KEY_EJ_LIMIT_ADDITION_INSTALLER_MS, EJ_LIMIT_ADDITION_INSTALLER_MS).println(); +            pw.print(KEY_EJ_LIMIT_ADDITION_SPECIAL_MS, EJ_LIMIT_ADDITION_SPECIAL_MS).println();              pw.print(KEY_EJ_WINDOW_SIZE_MS, EJ_WINDOW_SIZE_MS).println();              pw.print(KEY_EJ_TOP_APP_TIME_CHUNK_SIZE_MS, EJ_TOP_APP_TIME_CHUNK_SIZE_MS).println();              pw.print(KEY_EJ_REWARD_TOP_APP_MS, EJ_REWARD_TOP_APP_MS).println(); @@ -3945,8 +4000,13 @@ public final class QuotaController extends StateController {      }      @VisibleForTesting -    long getEjLimitSpecialAdditionMs() { -        return mEjLimitSpecialAdditionMs; +    long getEjLimitAdditionInstallerMs() { +        return mEjLimitAdditionInstallerMs; +    } + +    @VisibleForTesting +    long getEjLimitAdditionSpecialMs() { +        return mEjLimitAdditionSpecialMs;      }      @VisibleForTesting @@ -4067,6 +4127,12 @@ public final class QuotaController extends StateController {          pw.decreaseIndent();          pw.println(); +        pw.println("Special apps:"); +        pw.increaseIndent(); +        pw.print("System installers", mSystemInstallers.toString()); +        pw.decreaseIndent(); + +        pw.println();          mTrackedJobs.forEach((jobs) -> {              for (int j = 0; j < jobs.size(); j++) {                  final JobStatus js = jobs.valueAt(j); diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/StateController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/StateController.java index 56b30907b2a1..a33ba5b3f8bc 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/StateController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/StateController.java @@ -103,6 +103,10 @@ public abstract class StateController {      public void onAppRemovedLocked(String packageName, int uid) {      } +    /** Called when a user is added to the device. */ +    public void onUserAddedLocked(int userId) { +    } +      /** Called when a user is removed from the device. */      public void onUserRemovedLocked(int userId) {      } diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java index 1a808c9b3c33..24f7b37aedac 100644 --- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java +++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java @@ -1343,13 +1343,24 @@ public class AppStandbyController      @Override      public void restrictApp(@NonNull String packageName, int userId,              @SystemForcedReasons int restrictReason) { +        restrictApp(packageName, userId, REASON_MAIN_FORCED_BY_SYSTEM, restrictReason); +    } + +    @Override +    public void restrictApp(@NonNull String packageName, int userId, int mainReason, +            @SystemForcedReasons int restrictReason) { +        if (mainReason != REASON_MAIN_FORCED_BY_SYSTEM +                && mainReason != REASON_MAIN_FORCED_BY_USER) { +            Slog.e(TAG, "Tried to restrict app " + packageName + " for an unsupported reason"); +            return; +        }          // If the package is not installed, don't allow the bucket to be set.          if (!mInjector.isPackageInstalled(packageName, 0, userId)) {              Slog.e(TAG, "Tried to restrict uninstalled app: " + packageName);              return;          } -        final int reason = REASON_MAIN_FORCED_BY_SYSTEM | (REASON_SUB_MASK & restrictReason); +        final int reason = (REASON_MAIN_MASK & mainReason) | (REASON_SUB_MASK & restrictReason);          final long nowElapsed = mInjector.elapsedRealtime();          final int bucket = mAllowRestrictedBucket ? STANDBY_BUCKET_RESTRICTED : STANDBY_BUCKET_RARE;          setAppStandbyBucket(packageName, userId, bucket, reason, nowElapsed, false); diff --git a/core/api/current.txt b/core/api/current.txt index 481850e5c138..9dd3a4be049a 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -6943,6 +6943,7 @@ package android.app.admin {      method @Nullable public String onChoosePrivateKeyAlias(@NonNull android.content.Context, @NonNull android.content.Intent, int, @Nullable android.net.Uri, @Nullable String);      method public void onNetworkLogsAvailable(@NonNull android.content.Context, @NonNull android.content.Intent, long, @IntRange(from=1) int);      method public final void onReceive(@NonNull android.content.Context, @NonNull android.content.Intent); +    method public void onSecurityLogsAvailable(@NonNull android.content.Context, @NonNull android.content.Intent);    }    public final class DeviceAdminInfo implements android.os.Parcelable { @@ -7020,6 +7021,7 @@ package android.app.admin {      field public static final String ACTION_PASSWORD_FAILED = "android.app.action.ACTION_PASSWORD_FAILED";      field public static final String ACTION_PASSWORD_SUCCEEDED = "android.app.action.ACTION_PASSWORD_SUCCEEDED";      field public static final String ACTION_PROFILE_PROVISIONING_COMPLETE = "android.app.action.PROFILE_PROVISIONING_COMPLETE"; +    field public static final String ACTION_SECURITY_LOGS_AVAILABLE = "android.app.action.SECURITY_LOGS_AVAILABLE";      field public static final int BUGREPORT_FAILURE_FAILED_COMPLETING = 0; // 0x0      field public static final int BUGREPORT_FAILURE_FILE_NO_LONGER_AVAILABLE = 1; // 0x1      field public static final String DEVICE_ADMIN_META_DATA = "android.app.device_admin"; @@ -7315,6 +7317,7 @@ package android.app.admin {      field public static final String DELEGATION_NETWORK_LOGGING = "delegation-network-logging";      field public static final String DELEGATION_PACKAGE_ACCESS = "delegation-package-access";      field public static final String DELEGATION_PERMISSION_GRANT = "delegation-permission-grant"; +    field public static final String DELEGATION_SECURITY_LOGGING = "delegation-security-logging";      field public static final int ENCRYPTION_STATUS_ACTIVATING = 2; // 0x2      field public static final int ENCRYPTION_STATUS_ACTIVE = 3; // 0x3      field public static final int ENCRYPTION_STATUS_ACTIVE_DEFAULT_KEY = 4; // 0x4 @@ -8006,13 +8009,14 @@ package android.app.people {      method public long getStartTimeMillis();      method public void writeToParcel(@NonNull android.os.Parcel, int);      field public static final int ACTIVITY_ANNIVERSARY = 2; // 0x2 +    field public static final int ACTIVITY_AUDIO = 4; // 0x4      field public static final int ACTIVITY_BIRTHDAY = 1; // 0x1 -    field public static final int ACTIVITY_GAME = 5; // 0x5 -    field public static final int ACTIVITY_LOCATION = 6; // 0x6 -    field public static final int ACTIVITY_MEDIA = 4; // 0x4 +    field public static final int ACTIVITY_GAME = 6; // 0x6 +    field public static final int ACTIVITY_LOCATION = 7; // 0x7      field public static final int ACTIVITY_NEW_STORY = 3; // 0x3      field public static final int ACTIVITY_OTHER = 0; // 0x0 -    field public static final int ACTIVITY_UPCOMING_BIRTHDAY = 7; // 0x7 +    field public static final int ACTIVITY_UPCOMING_BIRTHDAY = 8; // 0x8 +    field public static final int ACTIVITY_VIDEO = 5; // 0x5      field public static final int AVAILABILITY_AVAILABLE = 0; // 0x0      field public static final int AVAILABILITY_BUSY = 1; // 0x1      field public static final int AVAILABILITY_OFFLINE = 2; // 0x2 diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 92dada62b264..4be620652bb3 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -1035,9 +1035,11 @@ package android.hardware.biometrics {    public class BiometricPrompt {      method @NonNull public java.util.List<java.lang.Integer> getAllowedSensorIds(); +    method public boolean isAllowBackgroundAuthentication();    }    public static class BiometricPrompt.Builder { +    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.TEST_BIOMETRIC, "android.permission.USE_BIOMETRIC_INTERNAL"}) public android.hardware.biometrics.BiometricPrompt.Builder setAllowBackgroundAuthentication(boolean);      method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.TEST_BIOMETRIC, "android.permission.USE_BIOMETRIC_INTERNAL"}) public android.hardware.biometrics.BiometricPrompt.Builder setAllowedSensorIds(@NonNull java.util.List<java.lang.Integer>);    } diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index c812e8e1782a..f7a35143916e 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -450,6 +450,21 @@ public abstract class ActivityManagerInternal {      public abstract boolean hasRunningForegroundService(int uid, int foregroundServiceType);      /** +     * Returns {@code true} if the given notification channel currently has a +     * notification associated with a foreground service.  This is an AMS check +     * because that is the source of truth for the FGS state. +     */ +    public abstract boolean hasForegroundServiceNotification(String pkg, @UserIdInt int userId, +            String channelId); + +    /** +     * If the given app has any FGSs whose notifications are in the given channel, +     * stop them. +     */ +    public abstract void stopForegroundServicesForChannel(String pkg, @UserIdInt int userId, +            String channelId); + +    /**       * Registers the specified {@code processObserver} to be notified of future changes to       * process state.       */ diff --git a/core/java/android/app/admin/DelegatedAdminReceiver.java b/core/java/android/app/admin/DelegatedAdminReceiver.java index 25b8eab452bf..36097c928bb0 100644 --- a/core/java/android/app/admin/DelegatedAdminReceiver.java +++ b/core/java/android/app/admin/DelegatedAdminReceiver.java @@ -18,6 +18,7 @@ package android.app.admin;  import static android.app.admin.DeviceAdminReceiver.ACTION_CHOOSE_PRIVATE_KEY_ALIAS;  import static android.app.admin.DeviceAdminReceiver.ACTION_NETWORK_LOGS_AVAILABLE; +import static android.app.admin.DeviceAdminReceiver.ACTION_SECURITY_LOGS_AVAILABLE;  import static android.app.admin.DeviceAdminReceiver.EXTRA_CHOOSE_PRIVATE_KEY_ALIAS;  import static android.app.admin.DeviceAdminReceiver.EXTRA_CHOOSE_PRIVATE_KEY_SENDER_UID;  import static android.app.admin.DeviceAdminReceiver.EXTRA_CHOOSE_PRIVATE_KEY_URI; @@ -115,6 +116,29 @@ public class DelegatedAdminReceiver extends BroadcastReceiver {      }      /** +     * Called each time a new batch of security logs can be retrieved. This callback method will +     * only ever be called when security logging is enabled. The logs can only be retrieved while +     * security logging is enabled. +     * +     * <p>If a secondary user or profile is created, this callback won't be received until all users +     * become affiliated again (even if security logging is enabled). It will also no longer be +     * possible to retrieve the security logs. See {@link DevicePolicyManager#setAffiliationIds}. +     * +     * <p> This callback is only applicable if the delegated app has +     * {@link DevicePolicyManager#DELEGATION_SECURITY_LOGGING} capability. Additionally, it must +     * declare an intent filter for {@link DeviceAdminReceiver#ACTION_SECURITY_LOGS_AVAILABLE} in +     * the receiver's manifest in order to receive this callback. The default implementation +     * simply throws {@link UnsupportedOperationException}. +     * +     * @param context The running context as per {@link #onReceive}. +     * @param intent The received intent as per {@link #onReceive}. +     * @see DevicePolicyManager#retrieveSecurityLogs +     */ +    public void onSecurityLogsAvailable(@NonNull Context context, @NonNull Intent intent) { +        throw new UnsupportedOperationException("onSecurityLogsAvailable should be implemented"); +    } + +    /**       * Intercept delegated device administrator broadcasts. Implementations should not override       * this method; implement the convenience callbacks for each action instead.       */ @@ -132,6 +156,8 @@ public class DelegatedAdminReceiver extends BroadcastReceiver {              long batchToken = intent.getLongExtra(EXTRA_NETWORK_LOGS_TOKEN, -1);              int networkLogsCount = intent.getIntExtra(EXTRA_NETWORK_LOGS_COUNT, 0);              onNetworkLogsAvailable(context, intent, batchToken, networkLogsCount); +        } else if (ACTION_SECURITY_LOGS_AVAILABLE.equals(action)) { +            onSecurityLogsAvailable(context, intent);          } else {              Log.w(TAG, "Unhandled broadcast: " + action);          } diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java index cccc9294c2d5..747a2de80db0 100644 --- a/core/java/android/app/admin/DeviceAdminReceiver.java +++ b/core/java/android/app/admin/DeviceAdminReceiver.java @@ -290,7 +290,6 @@ public class DeviceAdminReceiver extends BroadcastReceiver {      /**       * Broadcast action: notify that a new batch of security logs is ready to be collected. -     * @hide       */      @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)      @BroadcastBehavior(explicitOnly = true) diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 594b0051a113..426159f43095 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -1905,6 +1905,20 @@ public class DevicePolicyManager {      public static final String DELEGATION_CERT_SELECTION = "delegation-cert-selection";      /** +     * Grants access to {@link #setSecurityLoggingEnabled}, {@link #isSecurityLoggingEnabled}, +     * {@link #retrieveSecurityLogs}, and {@link #retrievePreRebootSecurityLogs}. Once granted the +     * delegated app will start receiving {@link DelegatedAdminReceiver#onSecurityLogsAvailable} +     * callback, and Device owner or Profile Owner will no longer receive the +     * {@link DeviceAdminReceiver#onSecurityLogsAvailable} callback. There can be at most one app +     * that has this delegation. If another app already had delegated security logging access, it +     * will lose the delegation when a new app is delegated. +     * +     * <p> Can only be granted by Device Owner or Profile Owner of an organnization owned and +     * managed profile. +     */ +    public static final String DELEGATION_SECURITY_LOGGING = "delegation-security-logging"; + +    /**       * No management for current user in-effect. This is the default.       * @hide       */ @@ -11241,7 +11255,7 @@ public class DevicePolicyManager {      public void setSecurityLoggingEnabled(@NonNull ComponentName admin, boolean enabled) {          throwIfParentInstance("setSecurityLoggingEnabled");          try { -            mService.setSecurityLoggingEnabled(admin, enabled); +            mService.setSecurityLoggingEnabled(admin, mContext.getPackageName(), enabled);          } catch (RemoteException re) {              throw re.rethrowFromSystemServer();          } @@ -11260,7 +11274,7 @@ public class DevicePolicyManager {      public boolean isSecurityLoggingEnabled(@Nullable ComponentName admin) {          throwIfParentInstance("isSecurityLoggingEnabled");          try { -            return mService.isSecurityLoggingEnabled(admin); +            return mService.isSecurityLoggingEnabled(admin, mContext.getPackageName());          } catch (RemoteException re) {              throw re.rethrowFromSystemServer();          } @@ -11285,10 +11299,12 @@ public class DevicePolicyManager {       * @see #isAffiliatedUser       * @see DeviceAdminReceiver#onSecurityLogsAvailable       */ +    @SuppressLint("NullableCollection")      public @Nullable List<SecurityEvent> retrieveSecurityLogs(@NonNull ComponentName admin) {          throwIfParentInstance("retrieveSecurityLogs");          try { -            ParceledListSlice<SecurityEvent> list = mService.retrieveSecurityLogs(admin); +            ParceledListSlice<SecurityEvent> list = mService.retrieveSecurityLogs( +                    admin, mContext.getPackageName());              if (list != null) {                  return list.getList();              } else { @@ -11438,11 +11454,13 @@ public class DevicePolicyManager {       * @see #isAffiliatedUser       * @see #retrieveSecurityLogs       */ +    @SuppressLint("NullableCollection")      public @Nullable List<SecurityEvent> retrievePreRebootSecurityLogs(              @NonNull ComponentName admin) {          throwIfParentInstance("retrievePreRebootSecurityLogs");          try { -            ParceledListSlice<SecurityEvent> list = mService.retrievePreRebootSecurityLogs(admin); +            ParceledListSlice<SecurityEvent> list = mService.retrievePreRebootSecurityLogs( +                    admin, mContext.getPackageName());              if (list != null) {                  return list.getList();              } else { diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index e98720c0d96c..7901791fc7d4 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -386,10 +386,10 @@ interface IDevicePolicyManager {      List<String> getAffiliationIds(in ComponentName admin);      boolean isAffiliatedUser(); -    void setSecurityLoggingEnabled(in ComponentName admin, boolean enabled); -    boolean isSecurityLoggingEnabled(in ComponentName admin); -    ParceledListSlice retrieveSecurityLogs(in ComponentName admin); -    ParceledListSlice retrievePreRebootSecurityLogs(in ComponentName admin); +    void setSecurityLoggingEnabled(in ComponentName admin, String packageName, boolean enabled); +    boolean isSecurityLoggingEnabled(in ComponentName admin, String packageName); +    ParceledListSlice retrieveSecurityLogs(in ComponentName admin, String packageName); +    ParceledListSlice retrievePreRebootSecurityLogs(in ComponentName admin, String packageName);      long forceNetworkLogs();      long forceSecurityLogs(); diff --git a/core/java/android/app/people/ConversationStatus.java b/core/java/android/app/people/ConversationStatus.java index d2a0255d572e..d351683386e2 100644 --- a/core/java/android/app/people/ConversationStatus.java +++ b/core/java/android/app/people/ConversationStatus.java @@ -36,7 +36,8 @@ public final class ConversationStatus implements Parcelable {              ACTIVITY_BIRTHDAY,              ACTIVITY_ANNIVERSARY,              ACTIVITY_NEW_STORY, -            ACTIVITY_MEDIA, +            ACTIVITY_AUDIO, +            ACTIVITY_VIDEO,              ACTIVITY_GAME,              ACTIVITY_LOCATION,              ACTIVITY_UPCOMING_BIRTHDAY @@ -44,14 +45,47 @@ public final class ConversationStatus implements Parcelable {      @Retention(RetentionPolicy.SOURCE)      public @interface ActivityType {} +    /** +     * Constant representing that the conversation user is engaged in an activity that cannot be +     * more specifically represented by another type. +     */      public static final int ACTIVITY_OTHER = 0; +    /** +     * Constant representing that today is the conversation user's birthday. +     */      public static final int ACTIVITY_BIRTHDAY = 1; +    /** +     * Constant representing that the conversation user and the device user are celebrating +     * and anniversary today. +     */      public static final int ACTIVITY_ANNIVERSARY = 2; +    /** +     * Constant representing that the conversation user has posted a new story. +     */      public static final int ACTIVITY_NEW_STORY = 3; -    public static final int ACTIVITY_MEDIA = 4; -    public static final int ACTIVITY_GAME = 5; -    public static final int ACTIVITY_LOCATION = 6; -    public static final int ACTIVITY_UPCOMING_BIRTHDAY = 7; +    /** +     * Constant representing that the conversation user is listening to music or other audio +     * like a podcast. +     */ +    public static final int ACTIVITY_AUDIO = 4; +    /** +     * Constant representing that the conversation user is watching video content. +     */ +    public static final int ACTIVITY_VIDEO = 5; +    /** +     * Constant representing that the conversation user is playing a game. +     */ +    public static final int ACTIVITY_GAME = 6; +    /** +     * Constant representing that the conversation user is sharing status with the device user. +     * Use this to represent a general 'this person is sharing their location with you' status or +     * a more specific 'this is the current location of this person' status. +     */ +    public static final int ACTIVITY_LOCATION = 7; +    /** +     * Constant representing that the conversation user's birthday is approaching soon. +     */ +    public static final int ACTIVITY_UPCOMING_BIRTHDAY = 8;      /** @hide */      @IntDef(prefix = { "AVAILABILITY_" }, value = { diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java index 31781ec79203..1db7e9da0bcb 100644 --- a/core/java/android/app/usage/UsageStatsManager.java +++ b/core/java/android/app/usage/UsageStatsManager.java @@ -1104,6 +1104,14 @@ public final class UsageStatsManager {                  break;              case REASON_MAIN_FORCED_BY_USER:                  sb.append("f"); +                if (subReason > 0) { +                    // Although not expected and shouldn't happen, this could potentially have a +                    // sub-reason if the system tries to give a reason when applying the +                    // FORCED_BY_USER reason. The sub-reason is undefined (though most likely a +                    // REASON_SUB_FORCED_SYSTEM_FLAG_ sub-reason), but it's better to note it in the +                    // log than to exclude it altogether. +                    sb.append("-").append(Integer.toBinaryString(subReason)); +                }                  break;              case REASON_MAIN_PREDICTED:                  sb.append("p"); diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java index 8fd0de7dbb39..a6b4b47f0db2 100644 --- a/core/java/android/appwidget/AppWidgetHostView.java +++ b/core/java/android/appwidget/AppWidgetHostView.java @@ -520,9 +520,7 @@ public class AppWidgetHostView extends FrameLayout {                  return;              }              int layoutId = rvToApply.getLayoutId(); -            // If our stale view has been prepared to match active, and the new -            // layout matches, try recycling it -            if (content == null && layoutId == mLayoutId) { +            if (rvToApply.canRecycleView(mView)) {                  try {                      rvToApply.reapply(mContext, mView, mInteractionHandler, mCurrentSize,                              mColorResources); diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java index 125824707402..2e51dc4427fe 100644 --- a/core/java/android/hardware/biometrics/BiometricPrompt.java +++ b/core/java/android/hardware/biometrics/BiometricPrompt.java @@ -368,6 +368,20 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan          }          /** +         * @param allow If true, allows authentication when the calling package is not in the +         *              foreground. This is set to false by default. +         * @return This builder +         * @hide +         */ +        @TestApi +        @NonNull +        @RequiresPermission(anyOf = {TEST_BIOMETRIC, USE_BIOMETRIC_INTERNAL}) +        public Builder setAllowBackgroundAuthentication(boolean allow) { +            mPromptInfo.setAllowBackgroundAuthentication(allow); +            return this; +        } + +        /**           * If set check the Device Policy Manager for disabled biometrics.           *           * @param checkDevicePolicyManager @@ -620,6 +634,15 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan      }      /** +     * @return The value set by {@link Builder#setAllowBackgroundAuthentication(boolean)} +     * @hide +     */ +    @TestApi +    public boolean isAllowBackgroundAuthentication() { +        return mPromptInfo.isAllowBackgroundAuthentication(); +    } + +    /**       * A wrapper class for the cryptographic operations supported by BiometricPrompt.       *       * <p>Currently the framework supports {@link Signature}, {@link Cipher}, {@link Mac}, and diff --git a/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl b/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl index 059bf2622b00..876513f266e8 100644 --- a/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl +++ b/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl @@ -48,7 +48,7 @@ interface IBiometricAuthenticator {      // startPreparedClient().      void prepareForAuthentication(boolean requireConfirmation, IBinder token, long operationId,              int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName, -            int cookie); +            int cookie, boolean allowBackgroundAuthentication);      // Starts authentication with the previously prepared client.      void startPreparedClient(int cookie); diff --git a/core/java/android/hardware/biometrics/PromptInfo.java b/core/java/android/hardware/biometrics/PromptInfo.java index 20c25fb82b4c..339c654f4d2f 100644 --- a/core/java/android/hardware/biometrics/PromptInfo.java +++ b/core/java/android/hardware/biometrics/PromptInfo.java @@ -44,6 +44,7 @@ public class PromptInfo implements Parcelable {      private boolean mDisallowBiometricsIfPolicyExists;      private boolean mReceiveSystemEvents;      @NonNull private List<Integer> mAllowedSensorIds = new ArrayList<>(); +    private boolean mAllowBackgroundAuthentication;      public PromptInfo() { @@ -64,6 +65,7 @@ public class PromptInfo implements Parcelable {          mDisallowBiometricsIfPolicyExists = in.readBoolean();          mReceiveSystemEvents = in.readBoolean();          mAllowedSensorIds = in.readArrayList(Integer.class.getClassLoader()); +        mAllowBackgroundAuthentication = in.readBoolean();      }      public static final Creator<PromptInfo> CREATOR = new Creator<PromptInfo>() { @@ -99,11 +101,14 @@ public class PromptInfo implements Parcelable {          dest.writeBoolean(mDisallowBiometricsIfPolicyExists);          dest.writeBoolean(mReceiveSystemEvents);          dest.writeList(mAllowedSensorIds); +        dest.writeBoolean(mAllowBackgroundAuthentication);      }      public boolean containsTestConfigurations() {          if (!mAllowedSensorIds.isEmpty()) {              return true; +        } else if (mAllowBackgroundAuthentication) { +            return true;          }          return false;      } @@ -183,6 +188,10 @@ public class PromptInfo implements Parcelable {          mAllowedSensorIds = sensorIds;      } +    public void setAllowBackgroundAuthentication(boolean allow) { +        mAllowBackgroundAuthentication = allow; +    } +      // Getters      public CharSequence getTitle() { @@ -248,4 +257,8 @@ public class PromptInfo implements Parcelable {      public List<Integer> getAllowedSensorIds() {          return mAllowedSensorIds;      } + +    public boolean isAllowBackgroundAuthentication() { +        return mAllowBackgroundAuthentication; +    }  } diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java index a3c6f2f1eafd..b7b1a147c822 100644 --- a/core/java/android/hardware/camera2/CameraManager.java +++ b/core/java/android/hardware/camera2/CameraManager.java @@ -2030,7 +2030,9 @@ public final class CameraManager {                  // Tell listeners that the cameras and torch modes are unavailable and schedule a                  // reconnection to camera service. When camera service is reconnected, the camera                  // and torch statuses will be updated. -                for (int i = 0; i < mDeviceStatus.size(); i++) { +                // Iterate from the end to the beginning befcause onStatusChangedLocked removes +                // entries from the ArrayMap. +                for (int i = mDeviceStatus.size() - 1; i >= 0; i--) {                      String cameraId = mDeviceStatus.keyAt(i);                      onStatusChangedLocked(ICameraServiceListener.STATUS_NOT_PRESENT, cameraId);                  } diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java index 2c3e7f18a3ab..6dd67447c321 100644 --- a/core/java/android/hardware/display/DisplayManager.java +++ b/core/java/android/hardware/display/DisplayManager.java @@ -20,6 +20,7 @@ import static android.view.Display.DEFAULT_DISPLAY;  import android.Manifest;  import android.annotation.IntDef; +import android.annotation.LongDef;  import android.annotation.NonNull;  import android.annotation.Nullable;  import android.annotation.RequiresPermission; @@ -376,6 +377,43 @@ public final class DisplayManager {      @TestApi      public static final int SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS = 2; +    /** +     * @hide +     */ +    @LongDef(flag = true, prefix = {"EVENT_FLAG_"}, value = { +            EVENT_FLAG_DISPLAY_ADDED, +            EVENT_FLAG_DISPLAY_CHANGED, +            EVENT_FLAG_DISPLAY_REMOVED, +    }) +    @Retention(RetentionPolicy.SOURCE) +    public @interface EventsMask {} + +    /** +     * Event type for when a new display is added. +     * +     * @see #registerDisplayListener(DisplayListener, Handler, long) +     * +     * @hide +     */ +    public static final long EVENT_FLAG_DISPLAY_ADDED = 1L << 0; + +    /** +     * Event type for when a display is removed. +     * +     * @see #registerDisplayListener(DisplayListener, Handler, long) +     * +     * @hide +     */ +    public static final long EVENT_FLAG_DISPLAY_REMOVED = 1L << 1; + +    /** +     * Event type for when a display is changed. +     * +     * @see #registerDisplayListener(DisplayListener, Handler, long) +     * +     * @hide +     */ +    public static final long EVENT_FLAG_DISPLAY_CHANGED = 1L << 2;      /** @hide */      public DisplayManager(Context context) { @@ -486,7 +524,7 @@ public final class DisplayManager {      }      /** -     * Registers an display listener to receive notifications about when +     * Registers a display listener to receive notifications about when       * displays are added, removed or changed.       *       * @param listener The listener to register. @@ -496,7 +534,29 @@ public final class DisplayManager {       * @see #unregisterDisplayListener       */      public void registerDisplayListener(DisplayListener listener, Handler handler) { -        mGlobal.registerDisplayListener(listener, handler); +        registerDisplayListener(listener, handler, EVENT_FLAG_DISPLAY_ADDED +                | EVENT_FLAG_DISPLAY_CHANGED | EVENT_FLAG_DISPLAY_REMOVED); +    } + +    /** +     * Registers a display listener to receive notifications about given display event types. +     * +     * @param listener The listener to register. +     * @param handler The handler on which the listener should be invoked, or null +     * if the listener should be invoked on the calling thread's looper. +     * @param eventsMask A bitmask of the event types for which this listener is subscribed. +     * +     * @see #EVENT_FLAG_DISPLAY_ADDED +     * @see #EVENT_FLAG_DISPLAY_CHANGED +     * @see #EVENT_FLAG_DISPLAY_REMOVED +     * @see #registerDisplayListener(DisplayListener, Handler) +     * @see #unregisterDisplayListener +     * +     * @hide +     */ +    public void registerDisplayListener(@NonNull DisplayListener listener, +            @Nullable Handler handler, @EventsMask long eventsMask) { +        mGlobal.registerDisplayListener(listener, handler, eventsMask);      }      /** diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java index 60fe5825d6a1..fd0431c5bc3f 100644 --- a/core/java/android/hardware/display/DisplayManagerGlobal.java +++ b/core/java/android/hardware/display/DisplayManagerGlobal.java @@ -16,6 +16,9 @@  package android.hardware.display; +import static android.hardware.display.DisplayManager.EventsMask; + +import android.annotation.IntDef;  import android.annotation.NonNull;  import android.annotation.Nullable;  import android.app.PropertyInvalidatedCache; @@ -42,6 +45,10 @@ import android.view.DisplayAdjustments;  import android.view.DisplayInfo;  import android.view.Surface; +import com.android.internal.annotations.VisibleForTesting; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy;  import java.util.ArrayList;  import java.util.Collections;  import java.util.List; @@ -66,6 +73,14 @@ public final class DisplayManagerGlobal {      // orientation change before the display info cache has actually been invalidated.      private static final boolean USE_CACHE = false; +    @IntDef(prefix = {"SWITCHING_TYPE_"}, value = { +            EVENT_DISPLAY_ADDED, +            EVENT_DISPLAY_CHANGED, +            EVENT_DISPLAY_REMOVED, +    }) +    @Retention(RetentionPolicy.SOURCE) +    public @interface DisplayEvent {} +      public static final int EVENT_DISPLAY_ADDED = 1;      public static final int EVENT_DISPLAY_CHANGED = 2;      public static final int EVENT_DISPLAY_REMOVED = 3; @@ -81,16 +96,17 @@ public final class DisplayManagerGlobal {      private final IDisplayManager mDm;      private DisplayManagerCallback mCallback; -    private final ArrayList<DisplayListenerDelegate> mDisplayListeners = -            new ArrayList<DisplayListenerDelegate>(); +    private @EventsMask long mRegisteredEventsMask = 0; +    private final ArrayList<DisplayListenerDelegate> mDisplayListeners = new ArrayList<>(); -    private final SparseArray<DisplayInfo> mDisplayInfoCache = new SparseArray<DisplayInfo>(); +    private final SparseArray<DisplayInfo> mDisplayInfoCache = new SparseArray<>();      private final ColorSpace mWideColorSpace;      private int[] mDisplayIdCache;      private int mWifiDisplayScanNestCount; -    private DisplayManagerGlobal(IDisplayManager dm) { +    @VisibleForTesting +    public DisplayManagerGlobal(IDisplayManager dm) {          mDm = dm;          try {              mWideColorSpace = @@ -274,18 +290,25 @@ public final class DisplayManagerGlobal {       * If that is still null, a runtime exception will be thrown.       */      public void registerDisplayListener(@NonNull DisplayListener listener, -            @Nullable Handler handler) { +            @Nullable Handler handler, @EventsMask long eventsMask) {          if (listener == null) {              throw new IllegalArgumentException("listener must not be null");          } +        if (eventsMask == 0) { +            throw new IllegalArgumentException("The set of events to listen to must not be empty."); +        } +          synchronized (mLock) {              int index = findDisplayListenerLocked(listener);              if (index < 0) {                  Looper looper = getLooperForHandler(handler); -                mDisplayListeners.add(new DisplayListenerDelegate(listener, looper)); +                mDisplayListeners.add(new DisplayListenerDelegate(listener, looper, eventsMask));                  registerCallbackIfNeededLocked(); +            } else { +                mDisplayListeners.get(index).setEventsMask(eventsMask);              } +            updateCallbackIfNeededLocked();          }      } @@ -300,6 +323,7 @@ public final class DisplayManagerGlobal {                  DisplayListenerDelegate d = mDisplayListeners.get(index);                  d.clearEvents();                  mDisplayListeners.remove(index); +                updateCallbackIfNeededLocked();              }          }      } @@ -325,18 +349,36 @@ public final class DisplayManagerGlobal {          return -1;      } +    @EventsMask +    private int calculateEventsMaskLocked() { +        int mask = 0; +        final int numListeners = mDisplayListeners.size(); +        for (int i = 0; i < numListeners; i++) { +            mask |= mDisplayListeners.get(i).mEventsMask; +        } +        return mask; +    } +      private void registerCallbackIfNeededLocked() {          if (mCallback == null) {              mCallback = new DisplayManagerCallback(); +            updateCallbackIfNeededLocked(); +        } +    } + +    private void updateCallbackIfNeededLocked() { +        int mask = calculateEventsMaskLocked(); +        if (mask != mRegisteredEventsMask) {              try { -                mDm.registerCallback(mCallback); +                mDm.registerCallbackWithEventMask(mCallback, mask); +                mRegisteredEventsMask = mask;              } catch (RemoteException ex) {                  throw ex.rethrowFromSystemServer();              }          }      } -    private void handleDisplayEvent(int displayId, int event) { +    private void handleDisplayEvent(int displayId, @DisplayEvent int event) {          synchronized (mLock) {              if (USE_CACHE) {                  mDisplayInfoCache.remove(displayId); @@ -754,7 +796,7 @@ public final class DisplayManagerGlobal {      private final class DisplayManagerCallback extends IDisplayManagerCallback.Stub {          @Override -        public void onDisplayEvent(int displayId, int event) { +        public void onDisplayEvent(int displayId, @DisplayEvent int event) {              if (DEBUG) {                  Log.d(TAG, "onDisplayEvent: displayId=" + displayId + ", event=" + event);              } @@ -764,13 +806,16 @@ public final class DisplayManagerGlobal {      private static final class DisplayListenerDelegate extends Handler {          public final DisplayListener mListener; +        public long mEventsMask; -        DisplayListenerDelegate(DisplayListener listener, @NonNull Looper looper) { +        DisplayListenerDelegate(DisplayListener listener, @NonNull Looper looper, +                @EventsMask long eventsMask) {              super(looper, null, true /*async*/);              mListener = listener; +            mEventsMask = eventsMask;          } -        public void sendDisplayEvent(int displayId, int event) { +        public void sendDisplayEvent(int displayId, @DisplayEvent int event) {              Message msg = obtainMessage(event, displayId, 0);              sendMessage(msg);          } @@ -779,17 +824,27 @@ public final class DisplayManagerGlobal {              removeCallbacksAndMessages(null);          } +        public synchronized void setEventsMask(@EventsMask long newEventsMask) { +            mEventsMask = newEventsMask; +        } +          @Override -        public void handleMessage(Message msg) { +        public synchronized void handleMessage(Message msg) {              switch (msg.what) {                  case EVENT_DISPLAY_ADDED: -                    mListener.onDisplayAdded(msg.arg1); +                    if ((mEventsMask & DisplayManager.EVENT_FLAG_DISPLAY_ADDED) != 0) { +                        mListener.onDisplayAdded(msg.arg1); +                    }                      break;                  case EVENT_DISPLAY_CHANGED: -                    mListener.onDisplayChanged(msg.arg1); +                    if ((mEventsMask & DisplayManager.EVENT_FLAG_DISPLAY_CHANGED) != 0) { +                        mListener.onDisplayChanged(msg.arg1); +                    }                      break;                  case EVENT_DISPLAY_REMOVED: -                    mListener.onDisplayRemoved(msg.arg1); +                    if ((mEventsMask & DisplayManager.EVENT_FLAG_DISPLAY_REMOVED) != 0) { +                        mListener.onDisplayRemoved(msg.arg1); +                    }                      break;              }          } diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl index ff8a7208a9f0..dee91445c224 100644 --- a/core/java/android/hardware/display/IDisplayManager.aidl +++ b/core/java/android/hardware/display/IDisplayManager.aidl @@ -38,6 +38,7 @@ interface IDisplayManager {      boolean isUidPresentOnDisplay(int uid, int displayId);      void registerCallback(in IDisplayManagerCallback callback); +    void registerCallbackWithEventMask(in IDisplayManagerCallback callback, long eventsMask);      // Requires CONFIGURE_WIFI_DISPLAY permission.      // The process must have previously registered a callback. diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl index 6e7c701ef5ff..0b44150afa4d 100644 --- a/core/java/android/hardware/face/IFaceService.aidl +++ b/core/java/android/hardware/face/IFaceService.aidl @@ -59,7 +59,7 @@ interface IFaceService {      // startPreparedClient().      void prepareForAuthentication(int sensorId, boolean requireConfirmation, IBinder token, long operationId,              int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName, -            int cookie); +            int cookie, boolean allowBackgroundAuthentication);      // Starts authentication with the previously prepared client.      void startPreparedClient(int sensorId, int cookie); diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl index 054c0d0f6513..469e87e2390a 100644 --- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl +++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl @@ -62,7 +62,8 @@ interface IFingerprintService {      // by BiometricService. To start authentication after the clients are ready, use      // startPreparedClient().      void prepareForAuthentication(int sensorId, IBinder token, long operationId, int userId, -            IBiometricSensorReceiver sensorReceiver, String opPackageName, int cookie); +            IBiometricSensorReceiver sensorReceiver, String opPackageName, int cookie, +            boolean allowBackgroundAuthentication);      // Starts authentication with the previously prepared client.      void startPreparedClient(int sensorId, int cookie); diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index f1c80af54cba..52517b07f861 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -15806,6 +15806,7 @@ public final class Settings {           * 1: Enabled (All apps will receive the new rules)           * @hide           */ +        @Readable          public static final String BACKPORT_S_NOTIF_RULES = "backport_s_notif_rules";          /** diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index 0167147a1067..85d4878d044c 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -105,7 +105,6 @@ public final class SurfaceControl implements Parcelable {      private static native void nativeMergeTransaction(long transactionObj,              long otherTransactionObj);      private static native void nativeSetAnimationTransaction(long transactionObj); -    private static native void nativeSetEarlyWakeup(long transactionObj);      private static native void nativeSetEarlyWakeupStart(long transactionObj);      private static native void nativeSetEarlyWakeupEnd(long transactionObj); @@ -3175,23 +3174,6 @@ public final class SurfaceControl implements Parcelable {              return this;          } -        /** -         * @deprecated use {@link Transaction#setEarlyWakeupStart()} -         * -         * Indicate that SurfaceFlinger should wake up earlier than usual as a result of this -         * transaction. This should be used when the caller thinks that the scene is complex enough -         * that it's likely to hit GL composition, and thus, SurfaceFlinger needs to more time in -         * order not to miss frame deadlines. -         * <p> -         * Corresponds to setting ISurfaceComposer::eEarlyWakeup -         * @hide -         */ -        @Deprecated -        public Transaction setEarlyWakeup() { -            nativeSetEarlyWakeup(mNativeObject); -            return this; -        } -           /**            * Provides a hint to SurfaceFlinger to change its offset so that SurfaceFlinger wakes up            * earlier to compose surfaces. The caller should use this as a hint to SurfaceFlinger diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index 2b73923fc5f4..319e78807684 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -2196,7 +2196,7 @@ public class RemoteViews implements Parcelable, Filter {                  int recycledViewIndex = findViewIndexToRecycle(target, rvToApply);                  if (recycledViewIndex >= 0) {                      View child = target.getChildAt(recycledViewIndex); -                    if (getViewLayoutId(child) == rvToApply.getLayoutId()) { +                    if (rvToApply.canRecycleView(child)) {                          if (nextChild < recycledViewIndex) {                              target.removeViews(nextChild, recycledViewIndex - nextChild);                          } @@ -2254,7 +2254,7 @@ public class RemoteViews implements Parcelable, Filter {                      // application are placed before.                      ViewTree recycled = target.mChildren.get(recycledViewIndex);                      // We can only recycle the view if the layout id is the same. -                    if (getViewLayoutId(recycled.mRoot) == rvToApply.getLayoutId()) { +                    if (rvToApply.canRecycleView(recycled.mRoot)) {                          if (recycledViewIndex > nextChild) {                              target.removeChildren(nextChild, recycledViewIndex - nextChild);                          } @@ -3726,7 +3726,8 @@ public class RemoteViews implements Parcelable, Filter {       *       * The {@code stableId} will be used to identify a potential view to recycled when the remote       * view is inflated. Views can be re-used if inserted in the same order, potentially with -     * some views appearing / disappearing. +     * some views appearing / disappearing. To be recycled the view must not change the layout +     * used to inflate it or its view id (see {@link RemoteViews#setViewId}).       *       * Note: if a view is re-used, all the actions will be re-applied on it. However, its properties       * are not reset, so what was applied in previous round will have an effect. As a view may be @@ -5116,6 +5117,7 @@ public class RemoteViews implements Parcelable, Filter {          View v = inflater.inflate(rv.getLayoutId(), parent, false);          if (mViewId != View.NO_ID) {              v.setId(mViewId); +            v.setTagInternal(R.id.remote_views_override_id, mViewId);          }          v.setTagInternal(R.id.widget_frame, rv.getLayoutId());          return v; @@ -5335,6 +5337,24 @@ public class RemoteViews implements Parcelable, Filter {          reapply(context, v, handler, size, colorResources, true);      } +    /** @hide */ +    public boolean canRecycleView(@Nullable View v) { +        if (v == null) { +            return false; +        } +        Integer previousLayoutId = (Integer) v.getTag(R.id.widget_frame); +        if (previousLayoutId == null) { +            return false; +        } +        Integer overrideIdTag = (Integer) v.getTag(R.id.remote_views_override_id); +        int overrideId = overrideIdTag == null ? View.NO_ID : overrideIdTag; +        // If mViewId is View.NO_ID, we only recycle if overrideId is also View.NO_ID. +        // Otherwise, it might be that, on a previous iteration, the view's ID was set to +        // something else, and it should now be reset to the ID defined in the XML layout file, +        // whatever it is. +        return previousLayoutId == getLayoutId() && mViewId == overrideId; +    } +      // Note: topLevel should be true only for calls on the topLevel RemoteViews, internal calls      // should set it to false.      private void reapply(Context context, View v, InteractionHandler handler, SizeF size, @@ -5347,7 +5367,7 @@ public class RemoteViews implements Parcelable, Filter {          // (orientation or size), we throw an exception, since the layouts may be completely          // unrelated.          if (hasMultipleLayouts()) { -            if ((Integer) v.getTag(R.id.widget_frame) != rvToApply.getLayoutId()) { +            if (!rvToApply.canRecycleView(v)) {                  throw new RuntimeException("Attempting to re-apply RemoteViews to a view that" +                          " that does not share the same root layout id.");              } diff --git a/core/java/com/android/internal/app/OWNERS b/core/java/com/android/internal/app/OWNERS index 7ade05cc6de1..e6c911e5b41d 100644 --- a/core/java/com/android/internal/app/OWNERS +++ b/core/java/com/android/internal/app/OWNERS @@ -3,6 +3,9 @@ per-file *Resolver* = file:/packages/SystemUI/OWNERS  per-file *Chooser* = file:/packages/SystemUI/OWNERS  per-file SimpleIconFactory.java = file:/packages/SystemUI/OWNERS  per-file NetInitiatedActivity.java = file:/location/java/android/location/OWNERS -per-file IVoice* = file:/core/java/android/service/voice/OWNERS -per-file *Hotword* = file:/core/java/android/service/voice/OWNERS  per-file *BatteryStats* = file:/BATTERY_STATS_OWNERS + +# Voice Interaction +per-file *Assist* = file:/core/java/android/service/voice/OWNERS +per-file *Hotword* = file:/core/java/android/service/voice/OWNERS +per-file *Voice* = file:/core/java/android/service/voice/OWNERS diff --git a/core/java/com/android/internal/widget/ViewPager.java b/core/java/com/android/internal/widget/ViewPager.java index 6f377b9b228a..93cde3ddb72d 100644 --- a/core/java/com/android/internal/widget/ViewPager.java +++ b/core/java/com/android/internal/widget/ViewPager.java @@ -353,8 +353,8 @@ public class ViewPager extends ViewGroup {          mTouchSlop = configuration.getScaledPagingTouchSlop();          mMinimumVelocity = (int) (MIN_FLING_VELOCITY * density);          mMaximumVelocity = configuration.getScaledMaximumFlingVelocity(); -        mLeftEdge = new EdgeEffect(context); -        mRightEdge = new EdgeEffect(context); +        mLeftEdge = new EdgeEffect(context, attrs); +        mRightEdge = new EdgeEffect(context, attrs);          mFlingDistance = (int) (MIN_DISTANCE_FOR_FLING * density);          mCloseEnough = (int) (CLOSE_ENOUGH * density); @@ -387,6 +387,28 @@ public class ViewPager extends ViewGroup {      }      /** +     * Returns the {@link EdgeEffect#getType()} for the edge effects. +     * @return the {@link EdgeEffect#getType()} for the edge effects. +     * @attr ref android.R.styleable#EdgeEffect_edgeEffectType +     */ +    @EdgeEffect.EdgeEffectType +    public int getEdgeEffectType() { +        // Both left and right edge have the same edge effect type +        return mLeftEdge.getType(); +    } + +    /** +     * Sets the {@link EdgeEffect#setType(int)} for the edge effects. +     * @param type The edge effect type to use for the edge effects. +     * @attr ref android.R.styleable#EdgeEffect_edgeEffectType +     */ +    public void setEdgeEffectType(@EdgeEffect.EdgeEffectType int type) { +        mLeftEdge.setType(type); +        mRightEdge.setType(type); +        invalidate(); +    } + +    /**       * Set a PagerAdapter that will supply views for this pager as needed.       *       * @param adapter Adapter to use @@ -1891,7 +1913,7 @@ public class ViewPager extends ViewGroup {                  }                  if (mIsBeingDragged) {                      // Scroll to follow the motion event -                    if (performDrag(x)) { +                    if (performDrag(x, y)) {                          postInvalidateOnAnimation();                      }                  } @@ -1918,6 +1940,17 @@ public class ViewPager extends ViewGroup {                      mIsBeingDragged = true;                      requestParentDisallowInterceptTouchEvent(true);                      setScrollState(SCROLL_STATE_DRAGGING); +                } else if (mLeftEdge.getDistance() != 0 +                        || mRightEdge.getDistance() != 0) { +                    // Caught the edge glow animation +                    mIsBeingDragged = true; +                    setScrollState(SCROLL_STATE_DRAGGING); +                    if (mLeftEdge.getDistance() != 0) { +                        mLeftEdge.onPullDistance(0f, 1 - mLastMotionY / getHeight()); +                    } +                    if (mRightEdge.getDistance() != 0) { +                        mRightEdge.onPullDistance(0f, mLastMotionY / getHeight()); +                    }                  } else {                      completeScroll(false);                      mIsBeingDragged = false; @@ -2009,7 +2042,7 @@ public class ViewPager extends ViewGroup {                      // Scroll to follow the motion event                      final int activePointerIndex = ev.findPointerIndex(mActivePointerId);                      final float x = ev.getX(activePointerIndex); -                    needsInvalidate |= performDrag(x); +                    needsInvalidate |= performDrag(x, ev.getY(activePointerIndex));                  }                  break;              case MotionEvent.ACTION_UP: @@ -2080,12 +2113,43 @@ public class ViewPager extends ViewGroup {          }      } -    private boolean performDrag(float x) { +    /** +     * If either of the horizontal edge glows are currently active, this consumes part or all of +     * deltaX on the edge glow. +     * +     * @param deltaX The pointer motion, in pixels, in the horizontal direction, positive +     *                         for moving down and negative for moving up. +     * @param y The vertical position of the pointer. +     * @return The amount of <code>deltaX</code> that has been consumed by the +     * edge glow. +     */ +    private float releaseHorizontalGlow(float deltaX, float y) { +        // First allow releasing existing overscroll effect: +        float consumed = 0; +        float displacement = y / getHeight(); +        float pullDistance = (float) deltaX / getWidth(); +        if (mLeftEdge.getDistance() != 0) { +            consumed = -mLeftEdge.onPullDistance(-pullDistance, 1 - displacement); +        } else if (mRightEdge.getDistance() != 0) { +            consumed = mRightEdge.onPullDistance(pullDistance, displacement); +        } +        return consumed * getWidth(); +    } + +    private boolean performDrag(float x, float y) {          boolean needsInvalidate = false; +        final float dX = mLastMotionX - x;          final int width = getPaddedWidth(); -        final float deltaX = mLastMotionX - x;          mLastMotionX = x; +        final float releaseConsumed = releaseHorizontalGlow(dX, y); +        final float deltaX = dX - releaseConsumed; +        if (releaseConsumed != 0) { +            needsInvalidate = true; +        } +        if (Math.abs(deltaX) < 0.0001f) { // ignore rounding errors from releaseHorizontalGlow() +            return needsInvalidate; +        }          final EdgeEffect startEdge;          final EdgeEffect endEdge; @@ -2128,14 +2192,14 @@ public class ViewPager extends ViewGroup {          if (scrollStart < startBound) {              if (startAbsolute) {                  final float over = startBound - scrollStart; -                startEdge.onPull(Math.abs(over) / width); +                startEdge.onPullDistance(over / width, 1 - y / getHeight());                  needsInvalidate = true;              }              clampedScrollStart = startBound;          } else if (scrollStart > endBound) {              if (endAbsolute) {                  final float over = scrollStart - endBound; -                endEdge.onPull(Math.abs(over) / width); +                endEdge.onPullDistance(over / width, y / getHeight());                  needsInvalidate = true;              }              clampedScrollStart = endBound; @@ -2228,7 +2292,9 @@ public class ViewPager extends ViewGroup {       */      private int determineTargetPage(int currentPage, float pageOffset, int velocity, int deltaX) {          int targetPage; -        if (Math.abs(deltaX) > mFlingDistance && Math.abs(velocity) > mMinimumVelocity) { +        if (Math.abs(deltaX) > mFlingDistance && Math.abs(velocity) > mMinimumVelocity +                && mLeftEdge.getDistance() == 0 // don't fling while stretched +                && mRightEdge.getDistance() == 0) {              targetPage = currentPage - (velocity < 0 ? mLeftIncr : 0);          } else {              final float truncator = currentPage >= mCurItem ? 0.4f : 0.6f; diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index 65b8b988f38b..f54ffc50095b 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -498,19 +498,14 @@ static void nativeSetAnimationTransaction(JNIEnv* env, jclass clazz, jlong trans      transaction->setAnimationTransaction();  } -static void nativeSetEarlyWakeup(JNIEnv* env, jclass clazz, jlong transactionObj) { -    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj); -    transaction->setEarlyWakeup(); -} -  static void nativeSetEarlyWakeupStart(JNIEnv* env, jclass clazz, jlong transactionObj) {      auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj); -    transaction->setExplicitEarlyWakeupStart(); +    transaction->setEarlyWakeupStart();  }  static void nativeSetEarlyWakeupEnd(JNIEnv* env, jclass clazz, jlong transactionObj) {      auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj); -    transaction->setExplicitEarlyWakeupEnd(); +    transaction->setEarlyWakeupEnd();  }  static void nativeSetLayer(JNIEnv* env, jclass clazz, jlong transactionObj, @@ -1737,8 +1732,6 @@ static const JNINativeMethod sSurfaceControlMethods[] = {              (void*)nativeMergeTransaction },      {"nativeSetAnimationTransaction", "(J)V",              (void*)nativeSetAnimationTransaction }, -    {"nativeSetEarlyWakeup", "(J)V", -            (void*)nativeSetEarlyWakeup },      {"nativeSetEarlyWakeupStart", "(J)V",              (void*)nativeSetEarlyWakeupStart },      {"nativeSetEarlyWakeupEnd", "(J)V", diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index f6fee880bf2f..b0327a5decee 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -59,6 +59,7 @@          <item><xliff:g id="id">@string/status_bar_mobile</xliff:g></item>          <item><xliff:g id="id">@string/status_bar_airplane</xliff:g></item>          <item><xliff:g id="id">@string/status_bar_no_calling</xliff:g></item> +        <item><xliff:g id="id">@string/status_bar_call_strength</xliff:g></item>          <item><xliff:g id="id">@string/status_bar_battery</xliff:g></item>          <item><xliff:g id="id">@string/status_bar_sensors_off</xliff:g></item>      </string-array> @@ -96,6 +97,7 @@      <string translatable="false" name="status_bar_camera">camera</string>      <string translatable="false" name="status_bar_airplane">airplane</string>      <string translatable="false" name="status_bar_no_calling">no_calling</string> +    <string translatable="false" name="status_bar_call_strength">call_strength</string>      <string translatable="false" name="status_bar_sensors_off">sensors_off</string>      <string translatable="false" name="status_bar_screen_record">screen_record</string> diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml index 7bc4663d1070..c3b35c81cb66 100644 --- a/core/res/res/values/ids.xml +++ b/core/res/res/values/ids.xml @@ -252,5 +252,8 @@    <item type="id" name="remote_views_next_child" />    <!-- View tag associating a view with its stable id for potential recycling. --> -  <item type="id" name = "remote_views_stable_id" /> +  <item type="id" name="remote_views_stable_id" /> + +  <!-- View tag associating a view with its overridden id, to ensure valid recycling only. --> +  <item type="id" name="remote_views_override_id" />  </resources> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 0228dfd45972..7ea762c2fbbb 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -4592,7 +4592,7 @@      <string name="color_correction_feature_name">Color Correction</string>      <!-- Title of Reduce Brightness feature, shown in the warning dialog about the accessibility shortcut. [CHAR LIMIT=none] --> -    <string name="reduce_bright_colors_feature_name">Reduce brightness</string> +    <string name="reduce_bright_colors_feature_name">Extra dim</string>      <!-- Text in toast to alert the user that the accessibility shortcut turned on an accessibility service. [CHAR LIMIT=none] -->      <string name="accessibility_shortcut_enabling_service">Held volume keys. <xliff:g id="service_name" example="TalkBack">%1$s</xliff:g> turned on.</string> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 0f834933ab70..cdeb71c7f162 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2977,6 +2977,7 @@    <java-symbol type="string" name="status_bar_clock" />    <java-symbol type="string" name="status_bar_airplane" />    <java-symbol type="string" name="status_bar_no_calling" /> +  <java-symbol type="string" name="status_bar_call_strength" />    <java-symbol type="string" name="status_bar_mobile" />    <java-symbol type="string" name="status_bar_ethernet" />    <java-symbol type="string" name="status_bar_vpn" /> @@ -3390,6 +3391,8 @@    <java-symbol type="drawable" name="ic_accessibility_color_correction" />    <java-symbol type="drawable" name="ic_accessibility_magnification" /> +  <java-symbol type="string" name="reduce_bright_colors_feature_name" /> +    <!-- com.android.internal.widget.RecyclerView -->    <java-symbol type="id" name="item_touch_helper_previous_elevation"/>    <java-symbol type="dimen" name="item_touch_helper_max_drag_scroll_per_frame"/> @@ -4321,8 +4324,11 @@    <java-symbol type="bool" name="config_cecRcProfileSourceMediaContextSensitiveMenuNotHandled_allowed" />    <java-symbol type="bool" name="config_cecRcProfileSourceMediaContextSensitiveMenuNotHandled_default" /> +  <!-- Ids for RemoteViews -->    <java-symbol type="id" name="remote_views_next_child" />    <java-symbol type="id" name="remote_views_stable_id" /> +  <java-symbol type="id" name="remote_views_override_id" /> +    <!-- View and control prompt -->    <java-symbol type="drawable" name="ic_accessibility_24dp" />    <java-symbol type="string" name="view_and_control_notification_title" /> diff --git a/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java b/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java new file mode 100644 index 000000000000..dfc9013e3c05 --- /dev/null +++ b/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java @@ -0,0 +1,127 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.display; + +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.eq; + +import android.content.Context; +import android.os.Handler; +import android.os.RemoteException; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class DisplayManagerGlobalTest { + +    private static final long ALL_DISPLAY_EVENTS = DisplayManager.EVENT_FLAG_DISPLAY_ADDED +                    | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED +                    | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED; + +    @Mock +    private IDisplayManager mDisplayManager; + +    @Mock +    private DisplayManager.DisplayListener mListener; + +    @Captor +    private ArgumentCaptor<IDisplayManagerCallback> mCallbackCaptor; + +    private Context mContext; +    private DisplayManagerGlobal mDisplayManagerGlobal; +    private Handler mHandler; + +    @Before +    public void setUp() throws RemoteException { +        MockitoAnnotations.initMocks(this); +        Mockito.when(mDisplayManager.getPreferredWideGamutColorSpaceId()).thenReturn(0); +        mContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); +        mHandler = mContext.getMainThreadHandler(); +        mDisplayManagerGlobal = new DisplayManagerGlobal(mDisplayManager); +    } + +    @Test +    public void testDisplayListenerIsCalled_WhenDisplayEventOccurs() throws RemoteException { +        mDisplayManagerGlobal.registerDisplayListener(mListener, mHandler, ALL_DISPLAY_EVENTS); +        Mockito.verify(mDisplayManager) +                .registerCallbackWithEventMask(mCallbackCaptor.capture(), anyLong()); +        IDisplayManagerCallback callback = mCallbackCaptor.getValue(); + +        int displayId = 1; +        callback.onDisplayEvent(displayId, DisplayManagerGlobal.EVENT_DISPLAY_ADDED); +        waitForHandler(); +        Mockito.verify(mListener).onDisplayAdded(eq(displayId)); +        Mockito.verifyNoMoreInteractions(mListener); + +        Mockito.reset(mListener); +        callback.onDisplayEvent(1, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED); +        waitForHandler(); +        Mockito.verify(mListener).onDisplayChanged(eq(displayId)); +        Mockito.verifyNoMoreInteractions(mListener); + +        Mockito.reset(mListener); +        callback.onDisplayEvent(displayId, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED); +        waitForHandler(); +        Mockito.verify(mListener).onDisplayRemoved(eq(displayId)); +        Mockito.verifyNoMoreInteractions(mListener); +    } + +    @Test +    public void testDisplayListenerIsNotCalled_WhenClientIsNotSubscribed() throws RemoteException { +        // First we subscribe to all events in order to test that the subsequent calls to +        // registerDisplayListener will update the event mask. +        mDisplayManagerGlobal.registerDisplayListener(mListener, mHandler, ALL_DISPLAY_EVENTS); +        Mockito.verify(mDisplayManager) +                .registerCallbackWithEventMask(mCallbackCaptor.capture(), anyLong()); +        IDisplayManagerCallback callback = mCallbackCaptor.getValue(); + +        int displayId = 1; +        mDisplayManagerGlobal.registerDisplayListener(mListener, mHandler, +                ALL_DISPLAY_EVENTS & ~DisplayManager.EVENT_FLAG_DISPLAY_ADDED); +        callback.onDisplayEvent(displayId, DisplayManagerGlobal.EVENT_DISPLAY_ADDED); +        waitForHandler(); +        Mockito.verifyZeroInteractions(mListener); + +        mDisplayManagerGlobal.registerDisplayListener(mListener, mHandler, +                ALL_DISPLAY_EVENTS & ~DisplayManager.EVENT_FLAG_DISPLAY_CHANGED); +        callback.onDisplayEvent(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED); +        waitForHandler(); +        Mockito.verifyZeroInteractions(mListener); + +        mDisplayManagerGlobal.registerDisplayListener(mListener, mHandler, +                ALL_DISPLAY_EVENTS & ~DisplayManager.EVENT_FLAG_DISPLAY_REMOVED); +        callback.onDisplayEvent(displayId, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED); +        waitForHandler(); +        Mockito.verifyZeroInteractions(mListener); +    } + +    private void waitForHandler() { +        mHandler.runWithScissors(() -> { }, 0); +    } +} diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index 9b124ced5663..1924e5fd7941 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -493,6 +493,8 @@ applications that come with the platform          <!-- Permission required for hotword detection service CTS tests -->          <permission name="android.permission.MANAGE_HOTWORD_DETECTION" />          <permission name="android.permission.MANAGE_APP_HIBERNATION"/> +        <!-- Permission required for CTS test - ResourceObserverNativeTest --> +        <permission name="android.permission.REGISTER_MEDIA_RESOURCE_OBSERVER" />      </privapp-permissions>      <privapp-permissions package="com.android.statementservice"> diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp index 17c9da573a7c..3f03302de474 100644 --- a/libs/WindowManager/Shell/Android.bp +++ b/libs/WindowManager/Shell/Android.bp @@ -63,13 +63,13 @@ genrule {      ],      tools: ["protologtool"],      cmd: "$(location protologtool) transform-protolog-calls " + -        "--protolog-class com.android.internal.protolog.common.ProtoLog " + -        "--protolog-impl-class com.android.wm.shell.protolog.ShellProtoLogImpl " + -        "--protolog-cache-class com.android.wm.shell.protolog.ShellProtoLogCache " + -        "--loggroups-class com.android.wm.shell.protolog.ShellProtoLogGroup " + -        "--loggroups-jar $(location :wm_shell_protolog-groups) " + -        "--output-srcjar $(out) " + -        "$(locations :wm_shell-sources)", +      "--protolog-class com.android.internal.protolog.common.ProtoLog " + +      "--protolog-impl-class com.android.wm.shell.protolog.ShellProtoLogImpl " + +      "--protolog-cache-class com.android.wm.shell.protolog.ShellProtoLogCache " + +      "--loggroups-class com.android.wm.shell.protolog.ShellProtoLogGroup " + +      "--loggroups-jar $(location :wm_shell_protolog-groups) " + +      "--output-srcjar $(out) " + +      "$(locations :wm_shell-sources)",      out: ["wm_shell_protolog.srcjar"],  } @@ -81,14 +81,13 @@ genrule {      ],      tools: ["protologtool"],      cmd: "$(location protologtool) generate-viewer-config " + -        "--protolog-class com.android.internal.protolog.common.ProtoLog " + -        "--loggroups-class com.android.wm.shell.protolog.ShellProtoLogGroup " + -        "--loggroups-jar $(location :wm_shell_protolog-groups) " + -        "--viewer-conf $(out) " + -        "$(locations :wm_shell-sources)", +      "--protolog-class com.android.internal.protolog.common.ProtoLog " + +      "--loggroups-class com.android.wm.shell.protolog.ShellProtoLogGroup " + +      "--loggroups-jar $(location :wm_shell_protolog-groups) " + +      "--viewer-conf $(out) " + +      "$(locations :wm_shell-sources)",      out: ["wm_shell_protolog.json"],  } -  // End ProtoLog  java_library { @@ -113,7 +112,7 @@ android_library {          "res",      ],      java_resources: [ -        ":generate-wm_shell_protolog.json", +        ":generate-wm_shell_protolog.json"      ],      static_libs: [          "androidx.appcompat_appcompat", @@ -126,10 +125,10 @@ android_library {          "protolog-lib",          "SettingsLib",          "WindowManager-Shell-proto", -        "jsr330", +        "jsr330"      ],      kotlincflags: ["-Xjvm-default=enable"],      manifest: "AndroidManifest.xml", -    min_sdk_version: "30", +    min_sdk_version: "26",  } diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java index d7112d6dfa63..0d613992f300 100644 --- a/media/java/android/media/AudioRecord.java +++ b/media/java/android/media/AudioRecord.java @@ -612,7 +612,9 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection,          }          /** -         * Sets the context the record belongs to. +         * Sets the context the record belongs to. This context will be used to pull information, +         * such as attribution tags, which will be associated with the AudioRecord. However, the +         * context itself will not be retained by the AudioRecord.           * @param context a non-null {@link Context} instance           * @return the same Builder instance.           */ diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp index 8a3762c91cbe..d6c66b5663af 100644 --- a/packages/SettingsLib/Android.bp +++ b/packages/SettingsLib/Android.bp @@ -17,8 +17,8 @@ android_library {      // TODO(b/149540986): revert this change.      static_libs: [ -        // All other dependent components should be put in -        // "SettingsLibDependenciesWithoutWifiTracker". +         // All other dependent components should be put in +         // "SettingsLibDependenciesWithoutWifiTracker".          "WifiTrackerLib",      ], @@ -27,12 +27,9 @@ android_library {      resource_dirs: ["res"], -    srcs: [ -        "src/**/*.java", -        "src/**/*.kt", -    ], +    srcs: ["src/**/*.java", "src/**/*.kt"], -    min_sdk_version: "30", +    min_sdk_version: "21",  } diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index 8d8e442e094b..b86ae6d199d7 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -435,6 +435,9 @@      <uses-permission android:name="android.permission.MANAGE_APP_HIBERNATION"/> +    <!-- Permission required for CTS test - ResourceObserverNativeTest --> +    <uses-permission android:name="android.permission.REGISTER_MEDIA_RESOURCE_OBSERVER" /> +      <application android:label="@string/app_label"                  android:theme="@android:style/Theme.DeviceDefault.DayNight"                  android:defaultToDeviceProtectedStorage="true" diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 685896523e36..691d111089b8 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -958,8 +958,6 @@      <string name="quick_settings_dark_mode_secondary_label_on_at">On at <xliff:g id="time" example="10 pm">%s</xliff:g></string>      <!-- QuickSettings: Secondary text for when the Dark theme or some other tile will be on until some user-selected time. [CHAR LIMIT=20] -->      <string name="quick_settings_dark_mode_secondary_label_until">Until <xliff:g id="time" example="7 am">%s</xliff:g></string> -    <!-- QuickSettings: Label for the toggle that controls whether Reduce Brightness is enabled. [CHAR LIMIT=NONE] --> -    <string name="quick_settings_reduce_bright_colors_label">Reduce brightness</string>      <!-- QuickSettings: NFC tile [CHAR LIMIT=NONE] -->      <string name="quick_settings_nfc_label">NFC</string> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java index 255fffdb3291..fa2f32fee755 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java @@ -99,11 +99,6 @@ public class TransactionCompat {          return this;      } -    @Deprecated -    public TransactionCompat setEarlyWakeup() { -        return this; -    } -      public TransactionCompat setColor(SurfaceControlCompat surfaceControl, float[] color) {          mTransaction.setColor(surfaceControl.mSurfaceControl, color);          return this; @@ -118,8 +113,4 @@ public class TransactionCompat {              SurfaceControl relativeTo, int z) {          t.setRelativeLayer(surfaceControl, relativeTo, z);      } - -    @Deprecated -    public static void setEarlyWakeup(Transaction t) { -    }  } diff --git a/packages/SystemUI/src/com/android/keyguard/DisabledUdfpsController.java b/packages/SystemUI/src/com/android/keyguard/DisabledUdfpsController.java index 945c9c499401..118f98da11e2 100644 --- a/packages/SystemUI/src/com/android/keyguard/DisabledUdfpsController.java +++ b/packages/SystemUI/src/com/android/keyguard/DisabledUdfpsController.java @@ -154,7 +154,9 @@ public class DisabledUdfpsController extends ViewController<DisabledUdfpsView> i                  @Override                  public void onBiometricRunningStateChanged(boolean running,                          BiometricSourceType biometricSourceType) { -                    mRunningFPS = running && biometricSourceType == FINGERPRINT; +                    if (biometricSourceType == FINGERPRINT) { +                        mRunningFPS = running; +                    }                      mAuthenticated &= !mRunningFPS;                      updateButtonVisibility();                  } diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java index c051b695e823..ca2c034c5d32 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java @@ -49,7 +49,6 @@ import android.view.accessibility.AccessibilityManager;  import com.android.internal.R;  import com.android.internal.accessibility.dialog.AccessibilityButtonChooserActivity;  import com.android.internal.util.ScreenshotHelper; -import com.android.systemui.Dependency;  import com.android.systemui.SystemUI;  import com.android.systemui.dagger.SysUISingleton;  import com.android.systemui.recents.Recents; @@ -140,6 +139,7 @@ public class SystemActions extends SystemUI {      private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";      private final SystemActionsBroadcastReceiver mReceiver; +    private final Recents mRecents;      private Locale mLocale;      private final AccessibilityManager mA11yManager;      private final Lazy<StatusBar> mStatusBar; @@ -150,8 +150,10 @@ public class SystemActions extends SystemUI {      @Inject      public SystemActions(Context context,              NotificationShadeWindowController notificationShadeController, -            Lazy<StatusBar> statusBar) { +            Lazy<StatusBar> statusBar, +            Recents recents) {          super(context); +        mRecents = recents;          mReceiver = new SystemActionsBroadcastReceiver();          mLocale = mContext.getResources().getConfiguration().getLocales().get(0);          mA11yManager = (AccessibilityManager) mContext.getSystemService( @@ -366,15 +368,15 @@ public class SystemActions extends SystemUI {      }      private void handleRecents() { -        Dependency.get(Recents.class).toggleRecentApps(); +        mRecents.toggleRecentApps();      }      private void handleNotifications() { -        Dependency.get(StatusBar.class).animateExpandNotificationsPanel(); +        mStatusBar.get().animateExpandNotificationsPanel();      }      private void handleQuickSettings() { -        Dependency.get(StatusBar.class).animateExpandSettingsPanel(null); +        mStatusBar.get().animateExpandSettingsPanel(null);      }      private void handlePowerDialog() { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java index b9f9b1bc85dd..98b3fe46ff57 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java @@ -321,6 +321,7 @@ public class UdfpsController implements DozeReceiver, HbmCallback {          mSensorProps = findFirstUdfps();          // At least one UDFPS sensor exists          checkArgument(mSensorProps != null); +        mStatusBar.setSensorRect(getSensorLocation());          mCoreLayoutParams = new WindowManager.LayoutParams(                  // TODO(b/152419866): Use the UDFPS window type when it becomes available. @@ -367,7 +368,8 @@ public class UdfpsController implements DozeReceiver, HbmCallback {       */      public RectF getSensorLocation() {          // This is currently used to calculate the amount of space available for notifications -        // on lockscreen. Keyguard is only shown in portrait mode for now, so this will need to +        // on lockscreen and for the udfps light reveal animation on keyguard. +        // Keyguard is only shown in portrait mode for now, so this will need to          // be updated if that ever changes.          return new RectF(mSensorProps.sensorLocationX - mSensorProps.sensorRadius,                  mSensorProps.sensorLocationY - mSensorProps.sensorRadius, diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java index 2c684d688483..f9c2a2aed751 100644 --- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java +++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java @@ -19,12 +19,13 @@ package com.android.systemui.people;  import static android.app.Notification.CATEGORY_MISSED_CALL;  import static android.app.Notification.EXTRA_MESSAGES;  import static android.app.people.ConversationStatus.ACTIVITY_ANNIVERSARY; +import static android.app.people.ConversationStatus.ACTIVITY_AUDIO;  import static android.app.people.ConversationStatus.ACTIVITY_BIRTHDAY;  import static android.app.people.ConversationStatus.ACTIVITY_GAME;  import static android.app.people.ConversationStatus.ACTIVITY_LOCATION; -import static android.app.people.ConversationStatus.ACTIVITY_MEDIA;  import static android.app.people.ConversationStatus.ACTIVITY_NEW_STORY;  import static android.app.people.ConversationStatus.ACTIVITY_UPCOMING_BIRTHDAY; +import static android.app.people.ConversationStatus.ACTIVITY_VIDEO;  import static android.app.people.ConversationStatus.AVAILABILITY_AVAILABLE;  import static android.appwidget.AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT;  import static android.appwidget.AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH; @@ -496,8 +497,10 @@ public class PeopleSpaceUtils {                  return context.getString(R.string.location_status);              case ACTIVITY_NEW_STORY:                  return context.getString(R.string.new_story_status); -            case ACTIVITY_MEDIA: +            case ACTIVITY_VIDEO:                  return context.getString(R.string.video_status); +            case ACTIVITY_AUDIO: +                return context.getString(R.string.audio_status);              case ACTIVITY_GAME:                  return context.getString(R.string.game_status);              default: diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java index 479be659ba10..03a6689bc449 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java @@ -25,8 +25,8 @@ import android.provider.Settings;  import android.service.quicksettings.Tile;  import android.widget.Switch; +import com.android.internal.R;  import com.android.internal.logging.MetricsLogger; -import com.android.systemui.R;  import com.android.systemui.dagger.qualifiers.Background;  import com.android.systemui.dagger.qualifiers.Main;  import com.android.systemui.plugins.ActivityStarter; @@ -98,14 +98,14 @@ public class ReduceBrightColorsTile extends QSTileImpl<QSTile.BooleanState>      @Override      public CharSequence getTileLabel() { -        return mContext.getString(R.string.quick_settings_reduce_bright_colors_label); +        return mContext.getString(R.string.reduce_bright_colors_feature_name);      }      @Override      protected void handleUpdateState(BooleanState state, Object arg) {          state.value = mReduceBrightColorsController.isReduceBrightColorsActivated();          state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE; -        state.label = mContext.getString(R.string.quick_settings_reduce_bright_colors_label); +        state.label = mContext.getString(R.string.reduce_bright_colors_feature_name);          state.expandedAccessibilityClassName = Switch.class.getName();          state.contentDescription = state.label;      } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt index c1feacaba440..563470d1a260 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt @@ -82,6 +82,31 @@ object LiftReveal : LightRevealEffect {      }  } +class CircleReveal( +    /** X-value of the circle center of the reveal. */ +    val centerX: Float, +    /** Y-value of the circle center of the reveal. */ +    val centerY: Float, +    /** Radius of initial state of circle reveal */ +    val startRadius: Float, +    /** Radius of end state of circle reveal */ +    val endRadius: Float +) : LightRevealEffect { +    override fun setRevealAmountOnScrim(amount: Float, scrim: LightRevealScrim) { +        val interpolatedAmount = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(amount) +        val fadeAmount = +            LightRevealEffect.getPercentPastThreshold(interpolatedAmount, 0.75f) +        val radius = startRadius + ((endRadius - startRadius) * interpolatedAmount) +        scrim.revealGradientEndColorAlpha = 1f - fadeAmount +        scrim.setRevealGradientBounds( +            centerX - radius /* left */, +            centerY - radius /* top */, +            centerX + radius /* right */, +            centerY + radius /* bottom */ +        ) +    } +} +  class PowerButtonReveal(      /** Approximate Y-value of the center of the power button on the physical device. */      val powerButtonY: Float diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java index e1199077efb9..3daa2b3e1e64 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java @@ -132,6 +132,7 @@ public class NotificationShelf extends ActivatableNotificationView implements          mHiddenShelfIconSize = res.getDimensionPixelOffset(R.dimen.hidden_shelf_icon_size);          mGapHeight = res.getDimensionPixelSize(R.dimen.qs_notification_padding); +        mShelfIcons.setInNotificationIconShelf(true);          if (!mShowNotificationShelf) {              setVisibility(GONE);          } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java index 6b144c652c56..25de551d2699 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java @@ -152,6 +152,7 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {      private boolean mDozing;      private boolean mOnLockScreen;      private int mLockScreenMode = KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL; +    private boolean mInNotificationIconShelf;      private boolean mChangingViewPositions;      private int mAddAnimationStartIndex = -1;      private int mCannedAnimationStartIndex = -1; @@ -702,6 +703,10 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {          mLockScreenMode = lockScreenMode;      } +    public void setInNotificationIconShelf(boolean inShelf) { +        mInNotificationIconShelf = inShelf; +    } +      public class IconState extends ViewState {          public static final int NO_VALUE = NotificationIconContainer.NO_VALUE;          public float iconAppearAmount = 1.0f; @@ -813,7 +818,7 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {                      }                  }                  icon.setVisibleState(visibleState, animationsAllowed); -                icon.setIconColor(mThemedTextColorPrimary, +                icon.setIconColor(mInNotificationIconShelf ? mThemedTextColorPrimary : iconColor,                          needsCannedAnimation && animationsAllowed);                  if (animate) {                      animateTo(icon, animationProperties); 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 427df5ebbbab..0e1fe22b2454 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -22,6 +22,7 @@ import static android.app.StatusBarManager.WindowType;  import static android.app.StatusBarManager.WindowVisibleState;  import static android.app.StatusBarManager.windowStateToString;  import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY; +import static android.hardware.biometrics.BiometricSourceType.FINGERPRINT;  import static android.view.InsetsState.ITYPE_STATUS_BAR;  import static android.view.InsetsState.containsType;  import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS; @@ -46,6 +47,7 @@ import static com.android.systemui.statusbar.phone.BarTransitions.MODE_WARNING;  import static com.android.systemui.statusbar.phone.BarTransitions.TransitionMode;  import static com.android.wm.shell.bubbles.BubbleController.TASKBAR_CHANGED_BROADCAST; +import android.animation.ValueAnimator;  import android.annotation.NonNull;  import android.annotation.Nullable;  import android.app.ActivityManager; @@ -74,6 +76,7 @@ import android.content.pm.ResolveInfo;  import android.content.res.Configuration;  import android.graphics.Point;  import android.graphics.PointF; +import android.graphics.RectF;  import android.media.AudioAttributes;  import android.metrics.LogMaker;  import android.net.Uri; @@ -179,6 +182,7 @@ import com.android.systemui.settings.brightness.BrightnessSlider;  import com.android.systemui.shared.plugins.PluginManager;  import com.android.systemui.statusbar.AutoHideUiElement;  import com.android.systemui.statusbar.BackDropView; +import com.android.systemui.statusbar.CircleReveal;  import com.android.systemui.statusbar.CommandQueue;  import com.android.systemui.statusbar.CrossFadeHelper;  import com.android.systemui.statusbar.FeatureFlags; @@ -382,6 +386,8 @@ public class StatusBar extends SystemUI implements DemoMode,      private ChargingRippleView mChargingRipple;      private WiredChargingRippleController mChargingRippleAnimationController;      private PowerButtonReveal mPowerButtonReveal; +    private CircleReveal mCircleReveal; +    private ValueAnimator mCircleRevealAnimator = ValueAnimator.ofFloat(0f, 1f);      private final Object mQueueLock = new Object(); @@ -1206,7 +1212,9 @@ public class StatusBar extends SystemUI implements DemoMode,          mLightRevealScrim = mNotificationShadeWindowView.findViewById(R.id.light_reveal_scrim);          mChargingRippleAnimationController.setViewHost(mNotificationShadeWindowView); -        if (mFeatureFlags.useNewLockscreenAnimations() && mDozeParameters.getAlwaysOn()) { + +        if (mFeatureFlags.useNewLockscreenAnimations() +                && (mDozeParameters.getAlwaysOn() || mDozeParameters.isQuickPickupEnabled())) {              mLightRevealScrim.setVisibility(View.VISIBLE);              mLightRevealScrim.setRevealEffect(LiftReveal.INSTANCE);          } else { @@ -3353,6 +3361,9 @@ public class StatusBar extends SystemUI implements DemoMode,          mNotificationPanelViewController.fadeOut(0, FADE_KEYGUARD_DURATION_PULSING,                  ()-> {                  hideKeyguard(); +                if (shouldShowCircleReveal()) { +                    startCircleReveal(); +                }                  mStatusBarKeyguardViewManager.onKeyguardFadedAway();              }).start();      } @@ -3666,15 +3677,16 @@ public class StatusBar extends SystemUI implements DemoMode,          updateQsExpansionEnabled();          mKeyguardViewMediator.setDozing(mDozing); -        final boolean usePowerButtonEffect = -                (isDozing && mWakefulnessLifecycle.getLastSleepReason() -                        == PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON) -                        || (!isDozing && mWakefulnessLifecycle.getLastWakeReason() -                        == PowerManager.WAKE_REASON_POWER_BUTTON); - -        mLightRevealScrim.setRevealEffect(usePowerButtonEffect -                ? mPowerButtonReveal -                : LiftReveal.INSTANCE); +        if (!isDozing && shouldShowCircleReveal()) { +            startCircleReveal(); +        } else if ((isDozing && mWakefulnessLifecycle.getLastSleepReason() +                == PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON) +                || (!isDozing && mWakefulnessLifecycle.getLastWakeReason() +                == PowerManager.WAKE_REASON_POWER_BUTTON)) { +            mLightRevealScrim.setRevealEffect(mPowerButtonReveal); +        } else if (!mCircleRevealAnimator.isRunning()) { +            mLightRevealScrim.setRevealEffect(LiftReveal.INSTANCE); +        }          mNotificationsController.requestNotificationUpdate("onDozingChanged");          updateDozingState(); @@ -3684,6 +3696,22 @@ public class StatusBar extends SystemUI implements DemoMode,          Trace.endSection();      } +    private void startCircleReveal() { +        mLightRevealScrim.setRevealEffect(mCircleReveal); +        mCircleRevealAnimator.cancel(); +        mCircleRevealAnimator.addUpdateListener(animation -> +                mLightRevealScrim.setRevealAmount( +                        (float) mCircleRevealAnimator.getAnimatedValue())); +        mCircleRevealAnimator.setDuration(900); +        mCircleRevealAnimator.start(); +    } + +    private boolean shouldShowCircleReveal() { +        return mCircleReveal != null && !mCircleRevealAnimator.isRunning() +                && mKeyguardUpdateMonitor.isUdfpsEnrolled() +                && mBiometricUnlockController.getBiometricType() == FINGERPRINT; +    } +      private void updateKeyguardState() {          mKeyguardStateController.notifyKeyguardState(mStatusBarKeyguardViewManager.isShowing(),                  mStatusBarKeyguardViewManager.isOccluded()); @@ -4170,6 +4198,15 @@ public class StatusBar extends SystemUI implements DemoMode,                  mBiometricUnlockController.getBiometricType());      } +    /** +     * Set the location of the sensor on UDFPS if existent. +     */ +    public void setSensorRect(RectF rect) { +        final float startRadius = (rect.right - rect.left) / 2f; +        mCircleReveal = new CircleReveal(rect.centerX(), rect.centerY(), +                startRadius, rect.centerY() - startRadius); +    } +      @VisibleForTesting      public void updateScrimController() {          Trace.beginSection("StatusBar#updateScrimController"); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java index 862037617374..8fe9a481ccf6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java @@ -66,7 +66,11 @@ public interface StatusBarIconController {      /**       * Display the no calling & SMS icons.       */ -    void setCallIndicatorIcons(String slot, List<CallIndicatorIconState> states); +    void setCallStrengthIcons(String slot, List<CallIndicatorIconState> states); +    /** +     * Display the no calling & SMS icons. +     */ +    void setNoCallingIcons(String slot, List<CallIndicatorIconState> states);      public void setIconVisibility(String slot, boolean b);      /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java index f0c8527bcb7f..6404aea05a4d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java @@ -219,27 +219,56 @@ public class StatusBarIconControllerImpl extends StatusBarIconList implements Tu      }      /** -     * Accept a list of CallIndicatorIconStates, and show them in the same slot -     * @param slot StatusBar slot +     * Accept a list of CallIndicatorIconStates, and show the call strength icons. +     * @param slot StatusBar slot for the call strength icons       * @param states All of the no Calling & SMS icon states       */      @Override -    public void setCallIndicatorIcons(String slot, List<CallIndicatorIconState> states) { +    public void setCallStrengthIcons(String slot, List<CallIndicatorIconState> states) { +        Slot callStrengthSlot = getSlot(slot); +        int callStrengthSlotIndex = getSlotIndex(slot); +        Collections.reverse(states); +        for (CallIndicatorIconState state : states) { +            if (!state.isNoCalling) { +                StatusBarIconHolder holder = callStrengthSlot.getHolderForTag(state.subId); +                if (holder == null) { +                    holder = StatusBarIconHolder.fromCallIndicatorState(mContext, state); +                    setIcon(callStrengthSlotIndex, holder); +                } else { +                    holder.setIcon(new StatusBarIcon(UserHandle.SYSTEM, mContext.getPackageName(), +                            Icon.createWithResource(mContext, state.callStrengthResId), 0, 0, +                            state.callStrengthDescription)); +                    setIcon(callStrengthSlotIndex, holder); +                } +            } +            setIconVisibility(slot, !state.isNoCalling, state.subId); +        } +    } + +    /** +     * Accept a list of CallIndicatorIconStates, and show the no calling icons. +     * @param slot StatusBar slot for the no calling icons +     * @param states All of the no Calling & SMS icon states +     */ +    @Override +    public void setNoCallingIcons(String slot, List<CallIndicatorIconState> states) {          Slot noCallingSlot = getSlot(slot); -        int slotIndex = getSlotIndex(slot); +        int noCallingSlotIndex = getSlotIndex(slot); +        Collections.reverse(states);          for (CallIndicatorIconState state : states) { -            StatusBarIconHolder holder = noCallingSlot.getHolderForTag(state.subId); -            if (holder == null) { -                holder = StatusBarIconHolder.fromCallIndicatorState(mContext, state); -                setIcon(slotIndex, holder); -            } else { -                int resId = state.isNoCalling ? state.noCallingResId : state.callStrengthResId; -                String contentDescription = state.isNoCalling -                        ? state.noCallingDescription : state.callStrengthDescription; -                holder.setIcon(new StatusBarIcon(UserHandle.SYSTEM, mContext.getPackageName(), -                        Icon.createWithResource(mContext, resId), 0, 0, contentDescription)); -                setIcon(slotIndex, holder); +            if (state.isNoCalling) { +                StatusBarIconHolder holder = noCallingSlot.getHolderForTag(state.subId); +                if (holder == null) { +                    holder = StatusBarIconHolder.fromCallIndicatorState(mContext, state); +                    setIcon(noCallingSlotIndex, holder); +                } else { +                    holder.setIcon(new StatusBarIcon(UserHandle.SYSTEM, mContext.getPackageName(), +                            Icon.createWithResource(mContext, state.noCallingResId), 0, 0, +                            state.noCallingDescription)); +                    setIcon(noCallingSlotIndex, holder); +                }              } +            setIconVisibility(slot, state.isNoCalling, state.subId);          }      } @@ -282,9 +311,15 @@ public class StatusBarIconControllerImpl extends StatusBarIconList implements Tu          }      } +    /** */      public void setIconVisibility(String slot, boolean visibility) { +        setIconVisibility(slot, visibility, 0); +    } + +    /** */ +    public void setIconVisibility(String slot, boolean visibility, int tag) {          int index = getSlotIndex(slot); -        StatusBarIconHolder holder = getIcon(index, 0); +        StatusBarIconHolder holder = getIcon(index, tag);          if (holder == null || holder.isVisible() == visibility) {              return;          } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.java index a1a2d30e9b00..19db02a71777 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.java @@ -83,7 +83,6 @@ public class StatusBarIconHolder {          holder.mIcon = new StatusBarIcon(UserHandle.SYSTEM, context.getPackageName(),                  Icon.createWithResource(context, resId), 0, 0, contentDescription);          holder.mTag = state.subId; -        holder.setVisible(true);          return holder;      } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java index 9ee7b09589d8..3445826eefbe 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java @@ -50,6 +50,7 @@ public class StatusBarSignalPolicy implements NetworkControllerImpl.SignalCallba      private final String mSlotEthernet;      private final String mSlotVpn;      private final String mSlotNoCalling; +    private final String mSlotCallStrength;      private final Context mContext;      private final StatusBarIconController mIconController; @@ -83,6 +84,8 @@ public class StatusBarSignalPolicy implements NetworkControllerImpl.SignalCallba          mSlotEthernet = mContext.getString(com.android.internal.R.string.status_bar_ethernet);          mSlotVpn      = mContext.getString(com.android.internal.R.string.status_bar_vpn);          mSlotNoCalling = mContext.getString(com.android.internal.R.string.status_bar_no_calling); +        mSlotCallStrength = +                mContext.getString(com.android.internal.R.string.status_bar_call_strength);          mActivityEnabled = mContext.getResources().getBoolean(R.bool.config_showActivity);          mIconController = iconController; @@ -212,8 +215,10 @@ public class StatusBarSignalPolicy implements NetworkControllerImpl.SignalCallba              state.callStrengthResId = statusIcon.icon;              state.callStrengthDescription = statusIcon.contentDescription;          } -        mIconController.setCallIndicatorIcons( -                mSlotNoCalling, CallIndicatorIconState.copyStates(mCallIndicatorStates)); +        mIconController.setCallStrengthIcons(mSlotCallStrength, +                CallIndicatorIconState.copyStates(mCallIndicatorStates)); +        mIconController.setNoCallingIcons(mSlotNoCalling, +                CallIndicatorIconState.copyStates(mCallIndicatorStates));      }      @Override @@ -300,6 +305,7 @@ public class StatusBarSignalPolicy implements NetworkControllerImpl.SignalCallba          mIconController.removeAllIconsForSlot(mSlotMobile);          mIconController.removeAllIconsForSlot(mSlotNoCalling); +        mIconController.removeAllIconsForSlot(mSlotCallStrength);          mMobileStates.clear();          List<CallIndicatorIconState> noCallingStates = new ArrayList<CallIndicatorIconState>();          noCallingStates.addAll(mCallIndicatorStates); diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java index 6032e51ab554..979951409aa9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java @@ -30,8 +30,8 @@ import android.testing.TestableLooper;  import androidx.test.filters.SmallTest; +import com.android.internal.R;  import com.android.internal.logging.MetricsLogger; -import com.android.systemui.R;  import com.android.systemui.SysuiTestCase;  import com.android.systemui.classifier.FalsingManagerFake;  import com.android.systemui.plugins.ActivityStarter; @@ -99,7 +99,7 @@ public class ReduceBrightColorsTileTest extends SysuiTestCase {          assertEquals(Tile.STATE_INACTIVE, mTile.getState().state);          assertEquals(mTile.getState().label.toString(), -                mContext.getString(R.string.quick_settings_reduce_bright_colors_label)); +                mContext.getString(R.string.reduce_bright_colors_feature_name));      }      @Test @@ -110,7 +110,7 @@ public class ReduceBrightColorsTileTest extends SysuiTestCase {          assertEquals(Tile.STATE_ACTIVE, mTile.getState().state);          assertEquals(mTile.getState().label.toString(), -                mContext.getString(R.string.quick_settings_reduce_bright_colors_label)); +                mContext.getString(R.string.reduce_bright_colors_feature_name));      }      @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java index 203ece9532ef..8ad6271bfc7e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java +++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java @@ -66,7 +66,11 @@ public class FakeStatusBarIconController extends BaseLeakChecker<IconManager>      }      @Override -    public void setCallIndicatorIcons(String slot, List<CallIndicatorIconState> states) { +    public void setCallStrengthIcons(String slot, List<CallIndicatorIconState> states) { +    } + +    @Override +    public void setNoCallingIcons(String slot, List<CallIndicatorIconState> states) {      }      @Override diff --git a/services/core/java/com/android/server/WatchableIntentResolver.java b/services/core/java/com/android/server/WatchedIntentResolver.java index 2ef94f17e5d9..e514f3c6fd59 100644 --- a/services/core/java/com/android/server/WatchableIntentResolver.java +++ b/services/core/java/com/android/server/WatchedIntentResolver.java @@ -31,7 +31,7 @@ import java.util.List;   * @param <R> The resolver type.   * {@hide}   */ -public abstract class WatchableIntentResolver<F, R extends Object> +public abstract class WatchedIntentResolver<F, R extends Object>          extends IntentResolver<F, R>          implements Watchable { diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 3c445ae4b667..1b352c728554 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -160,6 +160,7 @@ import java.text.SimpleDateFormat;  import java.util.ArrayList;  import java.util.Comparator;  import java.util.List; +import java.util.Objects;  import java.util.Set;  import java.util.function.Predicate; @@ -559,6 +560,45 @@ public final class ActiveServices {          return smap != null ? smap.mStartingBackground.size() >= mMaxStartingBackground : false;      } +    boolean hasForegroundServiceNotificationLocked(String pkg, int userId, String channelId) { +        final ServiceMap smap = mServiceMap.get(userId); +        if (smap != null) { +            for (int i = 0; i < smap.mServicesByInstanceName.size(); i++) { +                final ServiceRecord sr = smap.mServicesByInstanceName.valueAt(i); +                if (sr.appInfo.packageName.equals(pkg) && sr.isForeground) { +                    if (Objects.equals(sr.foregroundNoti.getChannelId(), channelId)) { +                        if (DEBUG_FOREGROUND_SERVICE) { +                            Slog.d(TAG_SERVICE, "Channel u" + userId + "/pkg=" + pkg +                                    + "/channelId=" + channelId +                                    + " has fg service notification"); +                        } +                        return true; +                    } +                } +            } +        } +        return false; +    } + +    void stopForegroundServicesForChannelLocked(String pkg, int userId, String channelId) { +        final ServiceMap smap = mServiceMap.get(userId); +        if (smap != null) { +            for (int i = 0; i < smap.mServicesByInstanceName.size(); i++) { +                final ServiceRecord sr = smap.mServicesByInstanceName.valueAt(i); +                if (sr.appInfo.packageName.equals(pkg) && sr.isForeground) { +                    if (Objects.equals(sr.foregroundNoti.getChannelId(), channelId)) { +                        if (DEBUG_FOREGROUND_SERVICE) { +                            Slog.d(TAG_SERVICE, "Stopping FGS u" + userId + "/pkg=" + pkg +                                    + "/channelId=" + channelId +                                    + " for conversation channel clear"); +                        } +                        stopServiceLocked(sr, false); +                    } +                } +            } +        } +    } +      private ServiceMap getServiceMapLocked(int callingUser) {          ServiceMap smap = mServiceMap.get(callingUser);          if (smap == null) { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 0e8644a6569e..c4548a3070a7 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -15911,6 +15911,22 @@ public class ActivityManagerService extends IActivityManager.Stub          }          @Override +        public boolean hasForegroundServiceNotification(String pkg, int userId, +                String channelId) { +            synchronized (ActivityManagerService.this) { +                return mServices.hasForegroundServiceNotificationLocked(pkg, userId, channelId); +            } +        } + +        @Override +        public void stopForegroundServicesForChannel(String pkg, int userId, +                String channelId) { +            synchronized (ActivityManagerService.this) { +                mServices.stopForegroundServicesForChannelLocked(pkg, userId, channelId); +            } +        } + +        @Override          public void registerProcessObserver(IProcessObserver processObserver) {              ActivityManagerService.this.registerProcessObserver(processObserver);          } diff --git a/services/core/java/com/android/server/am/OWNERS b/services/core/java/com/android/server/am/OWNERS index 9e79b02f8c96..273b9c3430b7 100644 --- a/services/core/java/com/android/server/am/OWNERS +++ b/services/core/java/com/android/server/am/OWNERS @@ -30,6 +30,10 @@ per-file BatteryExternalStats* = file:/BATTERY_STATS_OWNERS  michaelwr@google.com  narayan@google.com +# Voice Interaction +per-file *Assist* = file:/core/java/android/service/voice/OWNERS +per-file *Voice* = file:/core/java/android/service/voice/OWNERS +  per-file SettingsToPropertiesMapper.java = omakoto@google.com, svetoslavganov@google.com, yamasani@google.com  per-file CarUserSwitchingDialog.java = keunyoung@google.com, felipeal@google.com, gurunagarajan@google.com diff --git a/services/core/java/com/android/server/biometrics/AuthSession.java b/services/core/java/com/android/server/biometrics/AuthSession.java index f88820083768..5083c5ecd1ec 100644 --- a/services/core/java/com/android/server/biometrics/AuthSession.java +++ b/services/core/java/com/android/server/biometrics/AuthSession.java @@ -195,7 +195,8 @@ public final class AuthSession implements IBinder.DeathRecipient {              final int cookie = mRandom.nextInt(Integer.MAX_VALUE - 1) + 1;              final boolean requireConfirmation = isConfirmationRequired(sensor);              sensor.goToStateWaitingForCookie(requireConfirmation, mToken, mOperationId, -                    mUserId, mSensorReceiver, mOpPackageName, cookie); +                    mUserId, mSensorReceiver, mOpPackageName, cookie, +                    mPromptInfo.isAllowBackgroundAuthentication());          }      } diff --git a/services/core/java/com/android/server/biometrics/BiometricSensor.java b/services/core/java/com/android/server/biometrics/BiometricSensor.java index 85de81bb3491..c9e148f9b6ff 100644 --- a/services/core/java/com/android/server/biometrics/BiometricSensor.java +++ b/services/core/java/com/android/server/biometrics/BiometricSensor.java @@ -103,11 +103,12 @@ public abstract class BiometricSensor {      void goToStateWaitingForCookie(boolean requireConfirmation, IBinder token, long sessionId,              int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName, -            int cookie) +            int cookie, boolean allowBackgroundAuthentication)              throws RemoteException {          mCookie = cookie;          impl.prepareForAuthentication(requireConfirmation, token, -                sessionId, userId, sensorReceiver, opPackageName, mCookie); +                sessionId, userId, sensorReceiver, opPackageName, mCookie, +                allowBackgroundAuthentication);          mSensorState = STATE_WAITING_FOR_COOKIE;      } diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java index 9617bb09e153..79e75b16dbf2 100644 --- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java @@ -55,7 +55,7 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>      @Nullable private final TaskStackListener mTaskStackListener;      private final LockoutTracker mLockoutTracker;      private final boolean mIsRestricted; -    private final boolean mIsKeyguard; +    private final boolean mAllowBackgroundAuthentication;      protected final long mOperationId; @@ -68,7 +68,7 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>              int targetUserId, long operationId, boolean restricted, @NonNull String owner,              int cookie, boolean requireConfirmation, int sensorId, boolean isStrongBiometric,              int statsModality, int statsClient, @Nullable TaskStackListener taskStackListener, -            @NonNull LockoutTracker lockoutTracker, boolean isKeyguard) { +            @NonNull LockoutTracker lockoutTracker, boolean allowBackgroundAuthentication) {          super(context, lazyDaemon, token, listener, targetUserId, owner, cookie, sensorId,                  statsModality, BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient);          mIsStrongBiometric = isStrongBiometric; @@ -79,7 +79,7 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>          mTaskStackListener = taskStackListener;          mLockoutTracker = lockoutTracker;          mIsRestricted = restricted; -        mIsKeyguard = isKeyguard; +        mAllowBackgroundAuthentication = allowBackgroundAuthentication;      }      public @LockoutTracker.LockoutMode int handleFailedAttempt(int userId) { @@ -120,7 +120,7 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>      }      public boolean isKeyguard() { -        return mIsKeyguard; +        return Utils.isKeyguard(getContext(), getOwnerString());      }      @Override @@ -152,9 +152,15 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>                  pm.incrementAuthForUser(getTargetUserId(), authenticated);              } +            if (mAllowBackgroundAuthentication) { +                Slog.w(TAG, "Allowing background authentication," +                        + " this is allowed only for platform or test invocations"); +            } +              // Ensure authentication only succeeds if the client activity is on top.              boolean isBackgroundAuth = false; -            if (authenticated && !Utils.isKeyguard(getContext(), getOwnerString()) +            if (!mAllowBackgroundAuthentication && authenticated +                    && !Utils.isKeyguard(getContext(), getOwnerString())                      && !Utils.isSystem(getContext(), getOwnerString())) {                  final List<ActivityManager.RunningTaskInfo> tasks =                          mActivityTaskManager.getTasks(1); diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java index 2926260321f1..0002ad249376 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java @@ -61,10 +61,10 @@ public final class FaceAuthenticator extends IBiometricAuthenticator.Stub {      @Override      public void prepareForAuthentication(boolean requireConfirmation, IBinder token,              long operationId, int userId, IBiometricSensorReceiver sensorReceiver, -            String opPackageName, int cookie) +            String opPackageName, int cookie, boolean allowBackgroundAuthentication)              throws RemoteException {          mFaceService.prepareForAuthentication(mSensorId, requireConfirmation, token, operationId, -                userId, sensorReceiver, opPackageName, cookie); +                userId, sensorReceiver, opPackageName, cookie, allowBackgroundAuthentication);      }      @Override diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java index a74e2da30077..9f5dc69b404e 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java @@ -306,7 +306,8 @@ public class FaceService extends SystemService implements BiometricServiceCallba          @Override // Binder call          public void prepareForAuthentication(int sensorId, boolean requireConfirmation,                  IBinder token, long operationId, int userId, -                IBiometricSensorReceiver sensorReceiver, String opPackageName, int cookie) { +                IBiometricSensorReceiver sensorReceiver, String opPackageName, int cookie, +                boolean allowBackgroundAuthentication) {              Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);              final ServiceProvider provider = getProviderForSensor(sensorId); @@ -318,7 +319,7 @@ public class FaceService extends SystemService implements BiometricServiceCallba              final boolean restricted = true; // BiometricPrompt is always restricted              provider.scheduleAuthenticate(sensorId, token, operationId, userId, cookie,                      new ClientMonitorCallbackConverter(sensorReceiver), opPackageName, restricted, -                    BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, false /* isKeyguard */); +                    BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, allowBackgroundAuthentication);          }          @Override // Binder call diff --git a/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java index 88edfbf12df1..9b6fb0b75c57 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java @@ -103,7 +103,8 @@ public interface ServiceProvider {      void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId,              int cookie, @NonNull ClientMonitorCallbackConverter callback, -            @NonNull String opPackageName, boolean restricted, int statsClient, boolean isKeyguard); +            @NonNull String opPackageName, boolean restricted, int statsClient, +            boolean allowBackgroundAuthentication);      void cancelAuthentication(int sensorId, @NonNull IBinder token); 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 089cf1e4cee8..07d173c8da02 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 @@ -69,11 +69,11 @@ class FaceAuthenticationClient extends AuthenticationClient<ISession> implements              @NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId,              boolean restricted, String owner, int cookie, boolean requireConfirmation, int sensorId,              boolean isStrongBiometric, int statsClient, @NonNull UsageStats usageStats, -            @NonNull LockoutCache lockoutCache, boolean isKeyguard) { +            @NonNull LockoutCache lockoutCache, boolean allowBackgroundAuthentication) {          super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted,                  owner, cookie, requireConfirmation, sensorId, isStrongBiometric,                  BiometricsProtoEnums.MODALITY_FACE, statsClient, null /* taskStackListener */, -                lockoutCache, isKeyguard); +                lockoutCache, allowBackgroundAuthentication);          mUsageStats = usageStats;          mLockoutCache = lockoutCache;          mNotificationManager = context.getSystemService(NotificationManager.class); diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java index 82ad655f5878..ca29057c9888 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java @@ -445,7 +445,7 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {      public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,              int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback,              @NonNull String opPackageName, boolean restricted, int statsClient, -            boolean isKeyguard) { +            boolean allowBackgroundAuthentication) {          mHandler.post(() -> {              final IFace daemon = getHalInstance();              if (daemon == null) { @@ -466,7 +466,8 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {                          mContext, mSensors.get(sensorId).getLazySession(), token, callback, userId,                          operationId, restricted, opPackageName, cookie,                          false /* requireConfirmation */, sensorId, isStrongBiometric, statsClient, -                        mUsageStats, mSensors.get(sensorId).getLockoutCache(), isKeyguard); +                        mUsageStats, mSensors.get(sensorId).getLockoutCache(), +                        allowBackgroundAuthentication);                  mSensors.get(sensorId).getScheduler().scheduleClientMonitor(client);              } catch (RemoteException e) {                  Slog.e(getTag(), "Remote exception when scheduling authenticate", e); diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java index 55e9a8384a86..d8aaa22e8300 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java @@ -638,7 +638,7 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {      public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,              int userId, int cookie, @NonNull ClientMonitorCallbackConverter receiver,              @NonNull String opPackageName, boolean restricted, int statsClient, -            boolean isKeyguard) { +            boolean allowBackgroundAuthentication) {          mHandler.post(() -> {              scheduleUpdateActiveUserWithoutHandler(userId); @@ -646,7 +646,7 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {              final FaceAuthenticationClient client = new FaceAuthenticationClient(mContext,                      mLazyDaemon, token, receiver, userId, operationId, restricted, opPackageName,                      cookie, false /* requireConfirmation */, mSensorId, isStrongBiometric, -                    statsClient, mLockoutTracker, mUsageStats, isKeyguard); +                    statsClient, mLockoutTracker, mUsageStats, allowBackgroundAuthentication);              mScheduler.scheduleClientMonitor(client);          });      } 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 3ca51d32797e..ff06a4a30a80 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 @@ -62,11 +62,11 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> {              @NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId,              boolean restricted, String owner, int cookie, boolean requireConfirmation, int sensorId,              boolean isStrongBiometric, int statsClient, @NonNull LockoutTracker lockoutTracker, -            @NonNull UsageStats usageStats, boolean isKeyguard) { +            @NonNull UsageStats usageStats, boolean allowBackgroundAuthentication) {          super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted,                  owner, cookie, requireConfirmation, sensorId, isStrongBiometric,                  BiometricsProtoEnums.MODALITY_FACE, statsClient, null /* taskStackListener */, -                lockoutTracker, isKeyguard); +                lockoutTracker, allowBackgroundAuthentication);          mUsageStats = usageStats;          final Resources resources = getContext().getResources(); diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java index 9e82ffcfadc6..81096802a78b 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java @@ -62,10 +62,10 @@ public final class FingerprintAuthenticator extends IBiometricAuthenticator.Stub      @Override      public void prepareForAuthentication(boolean requireConfirmation, IBinder token,              long operationId, int userId, IBiometricSensorReceiver sensorReceiver, -            String opPackageName, int cookie) +            String opPackageName, int cookie, boolean allowBackgroundAuthentication)              throws RemoteException {          mFingerprintService.prepareForAuthentication(mSensorId, token, operationId, userId, -                sensorReceiver, opPackageName, cookie); +                sensorReceiver, opPackageName, cookie, allowBackgroundAuthentication);      }      @Override diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java index aa5afb728a9b..e4397fd158e1 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java @@ -403,7 +403,7 @@ public class FingerprintService extends SystemService implements BiometricServic          @Override // Binder call          public void prepareForAuthentication(int sensorId, IBinder token, long operationId,                  int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName, -                int cookie) { +                int cookie, boolean allowBackgroundAuthentication) {              Utils.checkPermission(getContext(), MANAGE_BIOMETRIC);              final ServiceProvider provider = getProviderForSensor(sensorId); @@ -415,7 +415,7 @@ public class FingerprintService extends SystemService implements BiometricServic              final boolean restricted = true; // BiometricPrompt is always restricted              provider.scheduleAuthenticate(sensorId, token, operationId, userId, cookie,                      new ClientMonitorCallbackConverter(sensorReceiver), opPackageName, restricted, -                    BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, false /* isKeyguard */); +                    BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, allowBackgroundAuthentication);          }          @Override // Binder call diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java index 0d50499bd02a..c09d2d37de44 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java @@ -96,7 +96,8 @@ public interface ServiceProvider {      void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId,              int cookie, @NonNull ClientMonitorCallbackConverter callback, -            @NonNull String opPackageName, boolean restricted, int statsClient, boolean isKeyguard); +            @NonNull String opPackageName, boolean restricted, int statsClient, +            boolean allowBackgroundAuthentication);      void startPreparedClient(int sensorId, int cookie); 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 e2743f624c37..76a47d382e4b 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 @@ -59,11 +59,12 @@ class FingerprintAuthenticationClient extends AuthenticationClient<ISession> imp              boolean restricted, @NonNull String owner, int cookie, boolean requireConfirmation,              int sensorId, boolean isStrongBiometric, int statsClient,              @Nullable TaskStackListener taskStackListener, @NonNull LockoutCache lockoutCache, -            @Nullable IUdfpsOverlayController udfpsOverlayController, boolean isKeyguard) { +            @Nullable IUdfpsOverlayController udfpsOverlayController, +            boolean allowBackgroundAuthentication) {          super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted, owner,                  cookie, requireConfirmation, sensorId, isStrongBiometric,                  BiometricsProtoEnums.MODALITY_FINGERPRINT, statsClient, taskStackListener, -                lockoutCache, isKeyguard); +                lockoutCache, allowBackgroundAuthentication);          mLockoutCache = lockoutCache;          mUdfpsOverlayController = udfpsOverlayController;      } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java index 227f6f6ca9ae..1b5def6c7063 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java @@ -469,7 +469,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi      public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,              int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback,              @NonNull String opPackageName, boolean restricted, int statsClient, -            boolean isKeyguard) { +            boolean allowBackgroundAuthentication) {          mHandler.post(() -> {              final IFingerprint daemon = getHalInstance();              if (daemon == null) { @@ -491,7 +491,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi                          operationId, restricted, opPackageName, cookie,                          false /* requireConfirmation */, sensorId, isStrongBiometric, statsClient,                          mTaskStackListener, mSensors.get(sensorId).getLockoutCache(), -                        mUdfpsOverlayController, isKeyguard); +                        mUdfpsOverlayController, allowBackgroundAuthentication);                  mSensors.get(sensorId).getScheduler().scheduleClientMonitor(client);              } catch (RemoteException e) {                  Slog.e(getTag(), "Remote exception when scheduling authenticate", e); diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java index f112549002fb..136caeb12111 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java @@ -611,7 +611,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider      public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,              int userId, int cookie, @NonNull ClientMonitorCallbackConverter listener,              @NonNull String opPackageName, boolean restricted, int statsClient, -            boolean isKeyguard) { +            boolean allowBackgroundAuthentication) {          mHandler.post(() -> {              scheduleUpdateActiveUserWithoutHandler(userId); @@ -620,7 +620,8 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider                      mContext, mLazyDaemon, token, listener, userId, operationId, restricted,                      opPackageName, cookie, false /* requireConfirmation */,                      mSensorProperties.sensorId, isStrongBiometric, statsClient, -                    mTaskStackListener, mLockoutTracker, mUdfpsOverlayController, isKeyguard); +                    mTaskStackListener, mLockoutTracker, mUdfpsOverlayController, +                    allowBackgroundAuthentication);              mScheduler.scheduleClientMonitor(client);          });      } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java index db371125478d..97f128748bcc 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java @@ -59,11 +59,12 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi              int sensorId, boolean isStrongBiometric, int statsClient,              @NonNull TaskStackListener taskStackListener,              @NonNull LockoutFrameworkImpl lockoutTracker, -            @Nullable IUdfpsOverlayController udfpsOverlayController, boolean isKeyguard) { +            @Nullable IUdfpsOverlayController udfpsOverlayController, +            boolean allowBackgroundAuthentication) {          super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted,                  owner, cookie, requireConfirmation, sensorId, isStrongBiometric,                  BiometricsProtoEnums.MODALITY_FINGERPRINT, statsClient, taskStackListener, -                lockoutTracker, isKeyguard); +                lockoutTracker, allowBackgroundAuthentication);          mLockoutFrameworkImpl = lockoutTracker;          mUdfpsOverlayController = udfpsOverlayController;      } diff --git a/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java index 95915b7809f3..1003c26f966e 100644 --- a/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java +++ b/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java @@ -59,7 +59,8 @@ public final class IrisAuthenticator extends IBiometricAuthenticator.Stub {      @Override      public void prepareForAuthentication(boolean requireConfirmation, IBinder token,              long sessionId, int userId, IBiometricSensorReceiver sensorReceiver, -            String opPackageName, int cookie) throws RemoteException { +            String opPackageName, int cookie, boolean allowBackgroundAuthentication) +            throws RemoteException {      }      @Override diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 82ca820ec4d7..f8a913aeb7cd 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -20,6 +20,7 @@ import static android.Manifest.permission.ADD_TRUSTED_DISPLAY;  import static android.Manifest.permission.CAPTURE_SECURE_VIDEO_OUTPUT;  import static android.Manifest.permission.CAPTURE_VIDEO_OUTPUT;  import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW; +import static android.hardware.display.DisplayManager.EventsMask;  import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;  import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD;  import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY; @@ -28,6 +29,7 @@ import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLI  import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE;  import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS;  import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED; +import static android.hardware.display.DisplayManagerGlobal.DisplayEvent;  import static android.hardware.display.DisplayViewport.VIEWPORT_EXTERNAL;  import static android.hardware.display.DisplayViewport.VIEWPORT_INTERNAL;  import static android.hardware.display.DisplayViewport.VIEWPORT_VIRTUAL; @@ -125,6 +127,7 @@ import java.util.ArrayList;  import java.util.Arrays;  import java.util.Optional;  import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.atomic.AtomicLong;  import java.util.function.Consumer;  /** @@ -820,14 +823,16 @@ public final class DisplayManagerService extends SystemService {      }      private void registerCallbackInternal(IDisplayManagerCallback callback, int callingPid, -            int callingUid) { +            int callingUid, @EventsMask long eventsMask) {          synchronized (mSyncRoot) { -            if (mCallbacks.get(callingPid) != null) { -                throw new SecurityException("The calling process has already " -                        + "registered an IDisplayManagerCallback."); +            CallbackRecord record = mCallbacks.get(callingPid); + +            if (record != null) { +                record.updateEventsMask(eventsMask); +                return;              } -            CallbackRecord record = new CallbackRecord(callingPid, callingUid, callback); +            record = new CallbackRecord(callingPid, callingUid, callback, eventsMask);              try {                  IBinder binder = callback.asBinder();                  binder.linkToDeath(record, 0); @@ -1695,7 +1700,7 @@ public final class DisplayManagerService extends SystemService {          }      } -    private void sendDisplayEventLocked(int displayId, int event) { +    private void sendDisplayEventLocked(int displayId, @DisplayEvent int event) {          Message msg = mHandler.obtainMessage(MSG_DELIVER_DISPLAY_EVENT, displayId, event);          mHandler.sendMessage(msg);      } @@ -1724,7 +1729,8 @@ public final class DisplayManagerService extends SystemService {      // Runs on Handler thread.      // Delivers display event notifications to callbacks. -    private void deliverDisplayEvent(int displayId, ArraySet<Integer> uids, int event) { +    private void deliverDisplayEvent(int displayId, ArraySet<Integer> uids, +            @DisplayEvent int event) {          if (DEBUG) {              Slog.d(TAG, "Delivering display event: displayId="                      + displayId + ", event=" + event); @@ -2059,13 +2065,20 @@ public final class DisplayManagerService extends SystemService {          public final int mPid;          public final int mUid;          private final IDisplayManagerCallback mCallback; +        private @EventsMask AtomicLong mEventsMask;          public boolean mWifiDisplayScanRequested; -        CallbackRecord(int pid, int uid, IDisplayManagerCallback callback) { +        CallbackRecord(int pid, int uid, IDisplayManagerCallback callback, +                @EventsMask long eventsMask) {              mPid = pid;              mUid = uid;              mCallback = callback; +            mEventsMask = new AtomicLong(eventsMask); +        } + +        public void updateEventsMask(@EventsMask long eventsMask) { +            mEventsMask.set(eventsMask);          }          @Override @@ -2076,7 +2089,11 @@ public final class DisplayManagerService extends SystemService {              onCallbackDied(this);          } -        public void notifyDisplayEventAsync(int displayId, int event) { +        public void notifyDisplayEventAsync(int displayId, @DisplayEvent int event) { +            if (!shouldSendEvent(event)) { +                return; +            } +              try {                  mCallback.onDisplayEvent(displayId, event);              } catch (RemoteException ex) { @@ -2085,6 +2102,22 @@ public final class DisplayManagerService extends SystemService {                  binderDied();              }          } + +        private boolean shouldSendEvent(@DisplayEvent int event) { +            final long mask = mEventsMask.get(); +            switch (event) { +                case DisplayManagerGlobal.EVENT_DISPLAY_ADDED: +                    return (mask & DisplayManager.EVENT_FLAG_DISPLAY_ADDED) != 0; +                case DisplayManagerGlobal.EVENT_DISPLAY_CHANGED: +                    return (mask & DisplayManager.EVENT_FLAG_DISPLAY_CHANGED) != 0; +                case DisplayManagerGlobal.EVENT_DISPLAY_REMOVED: +                    return (mask & DisplayManager.EVENT_FLAG_DISPLAY_REMOVED) != 0; +                default: +                    // This should never happen. +                    Slog.e(TAG, "Unknown display event " + event); +                    return true; +            } +        }      }      @VisibleForTesting @@ -2149,6 +2182,14 @@ public final class DisplayManagerService extends SystemService {          @Override // Binder call          public void registerCallback(IDisplayManagerCallback callback) { +            registerCallbackWithEventMask(callback, DisplayManager.EVENT_FLAG_DISPLAY_ADDED +                    | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED +                    | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED); +        } + +        @Override // Binder call +        public void registerCallbackWithEventMask(IDisplayManagerCallback callback, +                @EventsMask long eventsMask) {              if (callback == null) {                  throw new IllegalArgumentException("listener must not be null");              } @@ -2157,7 +2198,7 @@ public final class DisplayManagerService extends SystemService {              final int callingUid = Binder.getCallingUid();              final long token = Binder.clearCallingIdentity();              try { -                registerCallbackInternal(callback, callingPid, callingUid); +                registerCallbackInternal(callback, callingPid, callingUid, eventsMask);              } finally {                  Binder.restoreCallingIdentity(token);              } diff --git a/services/core/java/com/android/server/display/color/ColorDisplayShellCommand.java b/services/core/java/com/android/server/display/color/ColorDisplayShellCommand.java index b4555f851d4d..7d9b0aa03179 100644 --- a/services/core/java/com/android/server/display/color/ColorDisplayShellCommand.java +++ b/services/core/java/com/android/server/display/color/ColorDisplayShellCommand.java @@ -28,7 +28,7 @@ class ColorDisplayShellCommand extends ShellCommand {              + "      Shows this message.\n"              + "    set-saturation LEVEL\n"              + "      Sets the device saturation to the given LEVEL, 0-100 inclusive.\n" -            + "    set-layer-saturation CALLER_PACKAGE TARGET_PACKAGE LEVEL\n" +            + "    set-layer-saturation LEVEL CALLER_PACKAGE TARGET_PACKAGE\n"              + "      Sets the saturation LEVEL for all layers of the TARGET_PACKAGE, attributed\n"              + "      to the CALLER_PACKAGE. The lowest LEVEL from any CALLER_PACKAGE is applied.\n"; diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index e58836659189..eb4f9d305a27 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -3576,15 +3576,30 @@ public class NotificationManagerService extends SystemService {                      pkg, uid, channelId, conversationId, true, includeDeleted);          } +        // Returns 'true' if the given channel has a notification associated +        // with an active foreground service. +        private void enforceDeletingChannelHasNoFgService(String pkg, int userId, +                String channelId) { +            if (mAmi.hasForegroundServiceNotification(pkg, userId, channelId)) { +                Slog.w(TAG, "Package u" + userId + "/" + pkg +                        + " may not delete notification channel '" +                        + channelId + "' with fg service"); +                throw new SecurityException("Not allowed to delete channel " + channelId +                        + " with a foreground service"); +            } +        } +          @Override          public void deleteNotificationChannel(String pkg, String channelId) {              checkCallerIsSystemOrSameApp(pkg);              final int callingUid = Binder.getCallingUid(); +            final int callingUser = UserHandle.getUserId(callingUid);              if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {                  throw new IllegalArgumentException("Cannot delete default channel");              } +            enforceDeletingChannelHasNoFgService(pkg, callingUser, channelId);              cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true, -                    UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null); +                    callingUser, REASON_CHANNEL_BANNED, null);              mPreferencesHelper.deleteNotificationChannel(pkg, callingUid, channelId);              mListeners.notifyNotificationChannelChanged(pkg,                      UserHandle.getUserHandleForUid(callingUid), @@ -3597,19 +3612,23 @@ public class NotificationManagerService extends SystemService {          public void deleteConversationNotificationChannels(String pkg, int uid,                  String conversationId) {              checkCallerIsSystem(); -            final int callingUid = Binder.getCallingUid();              List<NotificationChannel> channels =                      mPreferencesHelper.getNotificationChannelsByConversationId(                              pkg, uid, conversationId);              if (!channels.isEmpty()) { +                // Preflight for fg service notifications in these channels:  do nothing +                // unless they're all eligible +                final int appUserId = UserHandle.getUserId(uid);                  for (NotificationChannel nc : channels) { +                    final String channelId = nc.getId(); +                    mAmi.stopForegroundServicesForChannel(pkg, appUserId, channelId);                      cancelAllNotificationsInt(MY_UID, MY_PID, pkg, nc.getId(), 0, 0, true, -                            UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null); -                    mPreferencesHelper.deleteNotificationChannel(pkg, callingUid, nc.getId()); +                            appUserId, REASON_CHANNEL_BANNED, null); +                    mPreferencesHelper.deleteNotificationChannel(pkg, uid, channelId);                      mListeners.notifyNotificationChannelChanged(pkg, -                            UserHandle.getUserHandleForUid(callingUid), +                            UserHandle.getUserHandleForUid(uid),                              mPreferencesHelper.getNotificationChannel( -                                    pkg, callingUid, nc.getId(), true), +                                    pkg, uid, channelId, true),                              NOTIFICATION_CHANNEL_OR_GROUP_DELETED);                  }                  handleSavePolicyFile(); @@ -3640,13 +3659,20 @@ public class NotificationManagerService extends SystemService {              NotificationChannelGroup groupToDelete =                      mPreferencesHelper.getNotificationChannelGroup(groupId, pkg, callingUid);              if (groupToDelete != null) { +                // Preflight for allowability +                final int userId = UserHandle.getUserId(callingUid); +                List<NotificationChannel> groupChannels = groupToDelete.getChannels(); +                for (int i = 0; i < groupChannels.size(); i++) { +                    enforceDeletingChannelHasNoFgService(pkg, userId, +                            groupChannels.get(i).getId()); +                }                  List<NotificationChannel> deletedChannels =                          mPreferencesHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId);                  for (int i = 0; i < deletedChannels.size(); i++) {                      final NotificationChannel deletedChannel = deletedChannels.get(i);                      cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0,                              true, -                            UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, +                            userId, REASON_CHANNEL_BANNED,                              null);                      mListeners.notifyNotificationChannelChanged(pkg,                              UserHandle.getUserHandleForUid(callingUid), diff --git a/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java b/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java index aae6ce46de66..791a1057d112 100644 --- a/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java +++ b/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java @@ -19,7 +19,7 @@ package com.android.server.pm;  import android.annotation.NonNull;  import android.content.IntentFilter; -import com.android.server.WatchableIntentResolver; +import com.android.server.WatchedIntentResolver;  import com.android.server.utils.Snappable;  import java.util.List; @@ -28,7 +28,7 @@ import java.util.List;   * Used to find a list of {@link CrossProfileIntentFilter}s that match an intent.   */  class CrossProfileIntentResolver -        extends WatchableIntentResolver<CrossProfileIntentFilter, CrossProfileIntentFilter> +        extends WatchedIntentResolver<CrossProfileIntentFilter, CrossProfileIntentFilter>          implements Snappable {      @Override      protected CrossProfileIntentFilter[] newArray(int size) { diff --git a/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java b/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java index c1bfcac50772..2b11a4297835 100644 --- a/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java +++ b/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java @@ -19,11 +19,11 @@ package com.android.server.pm;  import android.annotation.NonNull;  import android.content.IntentFilter; -import com.android.server.WatchableIntentResolver; +import com.android.server.WatchedIntentResolver;  import com.android.server.utils.Snappable;  public class PersistentPreferredIntentResolver -        extends WatchableIntentResolver<PersistentPreferredActivity, PersistentPreferredActivity> +        extends WatchedIntentResolver<PersistentPreferredActivity, PersistentPreferredActivity>          implements Snappable {      @Override      protected PersistentPreferredActivity[] newArray(int size) { diff --git a/services/core/java/com/android/server/pm/PreferredIntentResolver.java b/services/core/java/com/android/server/pm/PreferredIntentResolver.java index 0e3b85ca677a..10a6b3f69fde 100644 --- a/services/core/java/com/android/server/pm/PreferredIntentResolver.java +++ b/services/core/java/com/android/server/pm/PreferredIntentResolver.java @@ -19,14 +19,14 @@ package com.android.server.pm;  import android.annotation.NonNull;  import android.content.IntentFilter; -import com.android.server.WatchableIntentResolver; +import com.android.server.WatchedIntentResolver;  import com.android.server.utils.Snappable;  import java.io.PrintWriter;  import java.util.ArrayList;  public class PreferredIntentResolver -        extends WatchableIntentResolver<PreferredActivity, PreferredActivity> +        extends WatchedIntentResolver<PreferredActivity, PreferredActivity>          implements Snappable {      @Override      protected PreferredActivity[] newArray(int size) { diff --git a/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java b/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java index 0c8e36b75425..c8dc1b1ff562 100644 --- a/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java +++ b/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java @@ -146,47 +146,11 @@ public class ArtStatsLogUtils {                  uid,                  compilationReason,                  compilerFilter, -                ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_DEX_CODE_BYTES, -                getDexBytes(path), -                dexMetadataType); -        logger.write( -                sessionId, -                uid, -                compilationReason, -                compilerFilter,                  ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_TOTAL_TIME,                  compileTime,                  dexMetadataType);      } -    private static long getDexBytes(String apkPath) { -        StrictJarFile jarFile = null; -        long dexBytes = 0; -        try { -            jarFile = new StrictJarFile(apkPath, -                    /*verify=*/ false, -                    /*signatureSchemeRollbackProtectionsEnforced=*/ false); -            Iterator<ZipEntry> it = jarFile.iterator(); -            while (it.hasNext()) { -                ZipEntry entry = it.next(); -                if (entry.getName().matches("classes(\\d)*[.]dex")) { -                    dexBytes += entry.getSize(); -                } -            } -            return dexBytes; -        } catch (IOException ignore) { -            Slog.e(TAG, "Error when parsing APK " + apkPath); -            return -1L; -        } finally { -            try { -                if (jarFile != null) { -                    jarFile.close(); -                } -            } catch (IOException ignore) { -            } -        } -    } -      private static int getDexMetadataType(String dexMetadataPath) {          if (dexMetadataPath == null) {              return ArtStatsLog.ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_NONE; diff --git a/services/core/java/com/android/server/wm/LocalAnimationAdapter.java b/services/core/java/com/android/server/wm/LocalAnimationAdapter.java index f0629fa953fc..520bd8b2108e 100644 --- a/services/core/java/com/android/server/wm/LocalAnimationAdapter.java +++ b/services/core/java/com/android/server/wm/LocalAnimationAdapter.java @@ -126,7 +126,7 @@ class LocalAnimationAdapter implements AnimationAdapter {          /**           * @return {@code true} if we need to wake-up SurfaceFlinger earlier during this animation.           * -         * @see Transaction#setEarlyWakeup +         * @see Transaction#setEarlyWakeupStart and Transaction#setEarlyWakeupEnd           */          default boolean needsEarlyWakeup() { return false; } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index a8131e4e00ce..283895bb53e2 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -51,6 +51,7 @@ import static android.app.admin.DevicePolicyManager.DELEGATION_KEEP_UNINSTALLED_  import static android.app.admin.DevicePolicyManager.DELEGATION_NETWORK_LOGGING;  import static android.app.admin.DevicePolicyManager.DELEGATION_PACKAGE_ACCESS;  import static android.app.admin.DevicePolicyManager.DELEGATION_PERMISSION_GRANT; +import static android.app.admin.DevicePolicyManager.DELEGATION_SECURITY_LOGGING;  import static android.app.admin.DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_PER_USER;  import static android.app.admin.DevicePolicyManager.ID_TYPE_BASE_INFO;  import static android.app.admin.DevicePolicyManager.ID_TYPE_IMEI; @@ -430,6 +431,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {          DELEGATION_INSTALL_EXISTING_PACKAGE,          DELEGATION_KEEP_UNINSTALLED_PACKAGES,          DELEGATION_NETWORK_LOGGING, +        DELEGATION_SECURITY_LOGGING,          DELEGATION_CERT_SELECTION,      }; @@ -440,9 +442,18 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {                      DELEGATION_NETWORK_LOGGING,              }); +    // Subset of delegations that can only be delegated by Device Owner or Profile Owner of an +    // organization-owned and managed profile. +    private static final List<String> +            DEVICE_OWNER_OR_ORGANIZATION_OWNED_MANAGED_PROFILE_OWNER_DELEGATIONS = +            Arrays.asList(new String[]{ +                    DELEGATION_SECURITY_LOGGING, +            }); +      // Subset of delegations that only one single package within a given user can hold      private static final List<String> EXCLUSIVE_DELEGATIONS = Arrays.asList(new String[] {              DELEGATION_NETWORK_LOGGING, +            DELEGATION_SECURITY_LOGGING,              DELEGATION_CERT_SELECTION,      }); @@ -6024,6 +6035,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {          if (!Collections.disjoint(scopes, DEVICE_OWNER_OR_MANAGED_PROFILE_OWNER_DELEGATIONS)) {              Preconditions.checkCallAuthorization(isDeviceOwner(caller)                      || (isProfileOwner(caller) && isManagedProfile(caller.getUserId()))); +        } else if (!Collections.disjoint( +                scopes, DEVICE_OWNER_OR_ORGANIZATION_OWNED_MANAGED_PROFILE_OWNER_DELEGATIONS)) { +            Preconditions.checkCallAuthorization(isDeviceOwner(caller) +                    || isProfileOwnerOfOrganizationOwnedDevice(caller));          } else {              Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller));          } @@ -7658,6 +7673,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {              receiverComponent = resolveDelegateReceiver(DELEGATION_NETWORK_LOGGING, action,                      deviceOwnerUserId);          } +        if (action.equals(DeviceAdminReceiver.ACTION_SECURITY_LOGS_AVAILABLE)) { +            receiverComponent = resolveDelegateReceiver(DELEGATION_SECURITY_LOGGING, action, +                    deviceOwnerUserId); +        }          if (receiverComponent == null) {              synchronized (getLockObject()) {                  receiverComponent = mOwners.getDeviceOwnerComponent(); @@ -7674,6 +7693,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {          if (action.equals(DeviceAdminReceiver.ACTION_NETWORK_LOGS_AVAILABLE)) {              receiverComponent = resolveDelegateReceiver(DELEGATION_NETWORK_LOGGING, action, userId);          } +        if (action.equals(DeviceAdminReceiver.ACTION_SECURITY_LOGS_AVAILABLE)) { +            receiverComponent = resolveDelegateReceiver( +                DELEGATION_SECURITY_LOGGING, action, userId); +        }          if (receiverComponent == null) {              receiverComponent = getOwnerComponent(userId);          } @@ -13920,16 +13943,24 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {      }      @Override -    public void setSecurityLoggingEnabled(ComponentName admin, boolean enabled) { +    public void setSecurityLoggingEnabled(ComponentName admin, String packageName, +            boolean enabled) {          if (!mHasFeature) {              return;          } -        Objects.requireNonNull(admin); -        final CallerIdentity caller = getCallerIdentity(admin); +        final CallerIdentity caller = getCallerIdentity(admin, packageName);          synchronized (getLockObject()) { -            Preconditions.checkCallAuthorization(isProfileOwnerOfOrganizationOwnedDevice(caller) -                    || isDeviceOwner(caller)); +            if (admin != null) { +                Preconditions.checkCallAuthorization( +                        isProfileOwnerOfOrganizationOwnedDevice(caller) +                        || isDeviceOwner(caller)); +            } else { +                // A delegate app passes a null admin component, which is expected +                Preconditions.checkCallAuthorization( +                        isCallerDelegate(caller, DELEGATION_SECURITY_LOGGING)); +            } +              if (enabled == mInjector.securityLogGetLoggingEnabledProperty()) {                  return;              } @@ -13949,17 +13980,23 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {      }      @Override -    public boolean isSecurityLoggingEnabled(ComponentName admin) { +    public boolean isSecurityLoggingEnabled(ComponentName admin, String packageName) {          if (!mHasFeature) {              return false;          }          synchronized (getLockObject()) {              if (!isCallerWithSystemUid()) { -                Objects.requireNonNull(admin); -                final CallerIdentity caller = getCallerIdentity(admin); -                Preconditions.checkCallAuthorization( -                        isProfileOwnerOfOrganizationOwnedDevice(caller) || isDeviceOwner(caller)); +                final CallerIdentity caller = getCallerIdentity(admin, packageName); +                if (admin != null) { +                    Preconditions.checkCallAuthorization( +                            isProfileOwnerOfOrganizationOwnedDevice(caller) +                            || isDeviceOwner(caller)); +                } else { +                    // A delegate app passes a null admin component, which is expected +                    Preconditions.checkCallAuthorization( +                            isCallerDelegate(caller, DELEGATION_SECURITY_LOGGING)); +                }              }              return mInjector.securityLogGetLoggingEnabledProperty();          } @@ -13977,15 +14014,23 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {      }      @Override -    public ParceledListSlice<SecurityEvent> retrievePreRebootSecurityLogs(ComponentName admin) { +    public ParceledListSlice<SecurityEvent> retrievePreRebootSecurityLogs(ComponentName admin, +            String packageName) {          if (!mHasFeature) {              return null;          } -        Objects.requireNonNull(admin, "ComponentName is null"); -        final CallerIdentity caller = getCallerIdentity(admin); -        Preconditions.checkCallAuthorization(isDeviceOwner(caller) -                || isProfileOwnerOfOrganizationOwnedDevice(caller)); +        final CallerIdentity caller = getCallerIdentity(admin, packageName); +        if (admin != null) { +            Preconditions.checkCallAuthorization( +                    isProfileOwnerOfOrganizationOwnedDevice(caller) +                    || isDeviceOwner(caller)); +        } else { +            // A delegate app passes a null admin component, which is expected +            Preconditions.checkCallAuthorization( +                    isCallerDelegate(caller, DELEGATION_SECURITY_LOGGING)); +        } +          Preconditions.checkCallAuthorization(isOrganizationOwnedDeviceWithManagedProfile()                  || areAllUsersAffiliatedWithDeviceLocked()); @@ -14015,15 +14060,22 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {      }      @Override -    public ParceledListSlice<SecurityEvent> retrieveSecurityLogs(ComponentName admin) { +    public ParceledListSlice<SecurityEvent> retrieveSecurityLogs(ComponentName admin, +            String packageName) {          if (!mHasFeature) {              return null;          } -        Objects.requireNonNull(admin, "ComponentName is null"); -        final CallerIdentity caller = getCallerIdentity(admin); -        Preconditions.checkCallAuthorization(isDeviceOwner(caller) -                || isProfileOwnerOfOrganizationOwnedDevice(caller)); +        final CallerIdentity caller = getCallerIdentity(admin, packageName); +        if (admin != null) { +            Preconditions.checkCallAuthorization( +                    isProfileOwnerOfOrganizationOwnedDevice(caller) +                    || isDeviceOwner(caller)); +        } else { +            // A delegate app passes a null admin component, which is expected +            Preconditions.checkCallAuthorization( +                    isCallerDelegate(caller, DELEGATION_SECURITY_LOGGING)); +        }          Preconditions.checkCallAuthorization(isOrganizationOwnedDeviceWithManagedProfile()                  || areAllUsersAffiliatedWithDeviceLocked()); diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java index 281c1aafe049..f73af535f452 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java @@ -52,6 +52,7 @@ import static org.mockito.Mockito.timeout;  import static org.mockito.Mockito.times;  import static org.mockito.Mockito.verify; +import android.Manifest;  import android.app.ActivityManager;  import android.app.ActivityManagerInternal;  import android.app.AlarmManager; @@ -66,7 +67,10 @@ import android.content.BroadcastReceiver;  import android.content.ComponentName;  import android.content.Context;  import android.content.Intent; +import android.content.pm.ApplicationInfo;  import android.content.pm.IPackageManager; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager;  import android.content.pm.PackageManagerInternal;  import android.content.pm.ServiceInfo;  import android.os.BatteryManager; @@ -142,6 +146,8 @@ public class QuotaControllerTest {      @Mock      private JobSchedulerService mJobSchedulerService;      @Mock +    private PackageManager mPackageManager; +    @Mock      private PackageManagerInternal mPackageManagerInternal;      @Mock      private PowerAllowlistInternal mPowerAllowlistInternal; @@ -201,6 +207,8 @@ public class QuotaControllerTest {                          -> mDeviceConfigPropertiesBuilder.build())                  .when(() -> DeviceConfig.getProperties(                          eq(DeviceConfig.NAMESPACE_JOB_SCHEDULER), ArgumentMatchers.<String>any())); +        // Used in QuotaController.onSystemServicesReady +        when(mContext.getPackageManager()).thenReturn(mPackageManager);          // Freeze the clocks at 24 hours after this moment in time. Several tests create sessions          // in the past, and QuotaController sometimes floors values at 0, so if the test time @@ -2704,7 +2712,8 @@ public class QuotaControllerTest {          setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_FREQUENT_MS, 1 * HOUR_IN_MILLIS);          setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_RARE_MS, 30 * MINUTE_IN_MILLIS);          setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_RESTRICTED_MS, 27 * MINUTE_IN_MILLIS); -        setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_SPECIAL_ADDITION_MS, 10 * HOUR_IN_MILLIS); +        setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_ADDITION_INSTALLER_MS, 7 * HOUR_IN_MILLIS); +        setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_ADDITION_SPECIAL_MS, 10 * HOUR_IN_MILLIS);          setDeviceConfigLong(QcConstants.KEY_EJ_WINDOW_SIZE_MS, 12 * HOUR_IN_MILLIS);          setDeviceConfigLong(QcConstants.KEY_EJ_TOP_APP_TIME_CHUNK_SIZE_MS, 10 * MINUTE_IN_MILLIS);          setDeviceConfigLong(QcConstants.KEY_EJ_REWARD_TOP_APP_MS, 87 * SECOND_IN_MILLIS); @@ -2745,7 +2754,8 @@ public class QuotaControllerTest {          assertEquals(HOUR_IN_MILLIS, mQuotaController.getEJLimitsMs()[FREQUENT_INDEX]);          assertEquals(30 * MINUTE_IN_MILLIS, mQuotaController.getEJLimitsMs()[RARE_INDEX]);          assertEquals(27 * MINUTE_IN_MILLIS, mQuotaController.getEJLimitsMs()[RESTRICTED_INDEX]); -        assertEquals(10 * HOUR_IN_MILLIS, mQuotaController.getEjLimitSpecialAdditionMs()); +        assertEquals(7 * HOUR_IN_MILLIS, mQuotaController.getEjLimitAdditionInstallerMs()); +        assertEquals(10 * HOUR_IN_MILLIS, mQuotaController.getEjLimitAdditionSpecialMs());          assertEquals(12 * HOUR_IN_MILLIS, mQuotaController.getEJLimitWindowSizeMs());          assertEquals(10 * MINUTE_IN_MILLIS, mQuotaController.getEJTopAppTimeChunkSizeMs());          assertEquals(87 * SECOND_IN_MILLIS, mQuotaController.getEJRewardTopAppMs()); @@ -2786,7 +2796,8 @@ public class QuotaControllerTest {          setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_FREQUENT_MS, -1);          setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_RARE_MS, -1);          setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_RESTRICTED_MS, -1); -        setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_SPECIAL_ADDITION_MS, -1); +        setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_ADDITION_INSTALLER_MS, -1); +        setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_ADDITION_SPECIAL_MS, -1);          setDeviceConfigLong(QcConstants.KEY_EJ_WINDOW_SIZE_MS, -1);          setDeviceConfigLong(QcConstants.KEY_EJ_TOP_APP_TIME_CHUNK_SIZE_MS, -1);          setDeviceConfigLong(QcConstants.KEY_EJ_REWARD_TOP_APP_MS, -1); @@ -2823,7 +2834,8 @@ public class QuotaControllerTest {          assertEquals(10 * MINUTE_IN_MILLIS, mQuotaController.getEJLimitsMs()[FREQUENT_INDEX]);          assertEquals(10 * MINUTE_IN_MILLIS, mQuotaController.getEJLimitsMs()[RARE_INDEX]);          assertEquals(5 * MINUTE_IN_MILLIS, mQuotaController.getEJLimitsMs()[RESTRICTED_INDEX]); -        assertEquals(0, mQuotaController.getEjLimitSpecialAdditionMs()); +        assertEquals(0, mQuotaController.getEjLimitAdditionInstallerMs()); +        assertEquals(0, mQuotaController.getEjLimitAdditionSpecialMs());          assertEquals(HOUR_IN_MILLIS, mQuotaController.getEJLimitWindowSizeMs());          assertEquals(1, mQuotaController.getEJTopAppTimeChunkSizeMs());          assertEquals(10 * SECOND_IN_MILLIS, mQuotaController.getEJRewardTopAppMs()); @@ -2858,7 +2870,8 @@ public class QuotaControllerTest {          setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_FREQUENT_MS, 25 * HOUR_IN_MILLIS);          setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_RARE_MS, 25 * HOUR_IN_MILLIS);          setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_RESTRICTED_MS, 25 * HOUR_IN_MILLIS); -        setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_SPECIAL_ADDITION_MS, 25 * HOUR_IN_MILLIS); +        setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_ADDITION_INSTALLER_MS, 25 * HOUR_IN_MILLIS); +        setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_ADDITION_SPECIAL_MS, 25 * HOUR_IN_MILLIS);          setDeviceConfigLong(QcConstants.KEY_EJ_WINDOW_SIZE_MS, 25 * HOUR_IN_MILLIS);          setDeviceConfigLong(QcConstants.KEY_EJ_TOP_APP_TIME_CHUNK_SIZE_MS, 25 * HOUR_IN_MILLIS);          setDeviceConfigLong(QcConstants.KEY_EJ_REWARD_TOP_APP_MS, 25 * HOUR_IN_MILLIS); @@ -2885,7 +2898,8 @@ public class QuotaControllerTest {          assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getEJLimitsMs()[FREQUENT_INDEX]);          assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getEJLimitsMs()[RARE_INDEX]);          assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getEJLimitsMs()[RESTRICTED_INDEX]); -        assertEquals(0, mQuotaController.getEjLimitSpecialAdditionMs()); +        assertEquals(0, mQuotaController.getEjLimitAdditionInstallerMs()); +        assertEquals(0, mQuotaController.getEjLimitAdditionSpecialMs());          assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getEJLimitWindowSizeMs());          assertEquals(15 * MINUTE_IN_MILLIS, mQuotaController.getEJTopAppTimeChunkSizeMs());          assertEquals(15 * MINUTE_IN_MILLIS, mQuotaController.getEJRewardTopAppMs()); @@ -3957,9 +3971,16 @@ public class QuotaControllerTest {      }      @Test -    public void testGetRemainingEJExecutionTimeLocked_SpecialApp() { -        doReturn(new String[]{SOURCE_PACKAGE}).when(mPackageManagerInternal) -                .getKnownPackageNames(eq(PackageManagerInternal.PACKAGE_VERIFIER), anyInt()); +    public void testGetRemainingEJExecutionTimeLocked_Installer() { +        PackageInfo pi = new PackageInfo(); +        pi.packageName = SOURCE_PACKAGE; +        pi.requestedPermissions = new String[]{Manifest.permission.INSTALL_PACKAGES}; +        pi.requestedPermissionsFlags = new int[]{PackageInfo.REQUESTED_PERMISSION_GRANTED}; +        pi.applicationInfo = new ApplicationInfo(); +        pi.applicationInfo.uid = mSourceUid; +        doReturn(List.of(pi)).when(mPackageManager).getInstalledPackagesAsUser(anyInt(), anyInt()); +        doReturn(PackageManager.PERMISSION_GRANTED).when(mContext).checkPermission( +                eq(Manifest.permission.INSTALL_PACKAGES), anyInt(), eq(mSourceUid));          mQuotaController.onSystemServicesReady();          final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); @@ -3980,7 +4001,7 @@ public class QuotaControllerTest {              setStandbyBucket(i);              assertEquals("Got wrong remaining EJ execution time for bucket #" + i,                      i == NEVER_INDEX ? 0 -                            : (limits[i] + mQuotaController.getEjLimitSpecialAdditionMs() +                            : (limits[i] + mQuotaController.getEjLimitAdditionInstallerMs()                                      - 5 * MINUTE_IN_MILLIS),                      mQuotaController.getRemainingEJExecutionTimeLocked(                              SOURCE_USER_ID, SOURCE_PACKAGE)); diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java index a6d146e7ef71..3cbc22654292 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java @@ -151,7 +151,8 @@ public class AuthSessionTest {                      eq(userId),                      eq(mSensorReceiver),                      eq(TEST_PACKAGE), -                    eq(sensor.getCookie())); +                    eq(sensor.getCookie()), +                    anyBoolean() /* allowBackgroundAuthentication */);          }          final int cookie1 = session.mPreAuthInfo.eligibleSensors.get(0).getCookie(); diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java index 0c95e05342c8..abc873766de1 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java @@ -456,7 +456,8 @@ public class BiometricServiceTest {                  anyInt() /* userId */,                  any(IBiometricSensorReceiver.class),                  anyString() /* opPackageName */, -                cookieCaptor.capture() /* cookie */); +                cookieCaptor.capture() /* cookie */, +                anyBoolean() /* allowBackgroundAuthentication */);          // onReadyForAuthentication, mCurrentAuthSession state OK          mBiometricService.mImpl.onReadyForAuthentication(cookieCaptor.getValue()); diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java index bc86d1d39b1c..429517251f67 100644 --- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java @@ -93,7 +93,9 @@ public class DisplayManagerServiceTest {      private static final long SHORT_DEFAULT_DISPLAY_TIMEOUT_MILLIS = 10;      private static final String VIRTUAL_DISPLAY_NAME = "Test Virtual Display";      private static final String PACKAGE_NAME = "com.android.frameworks.servicestests"; - +    private static final long ALL_DISPLAY_EVENTS = DisplayManager.EVENT_FLAG_DISPLAY_ADDED +                    | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED +                    | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED;      @Rule      public TestRule compatChangeRule = new PlatformCompatChangeRule(); @@ -355,29 +357,13 @@ public class DisplayManagerServiceTest {          // Find the display id of the added FakeDisplayDevice          DisplayManagerService.BinderService bs = displayManager.new BinderService(); -        final int[] displayIds = bs.getDisplayIds(); -        assertTrue(displayIds.length > 0); -        int displayId = Display.INVALID_DISPLAY; -        for (int i = 0; i < displayIds.length; i++) { -            DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayIds[i]); -            if (displayDeviceInfo.equals(ddi)) { -                displayId = displayIds[i]; -                break; -            } -        } -        assertFalse(displayId == Display.INVALID_DISPLAY); - +        int displayId = getDisplayIdForDisplayDevice(displayManager, bs, displayDevice);          // Setup override DisplayInfo          DisplayInfo overrideInfo = bs.getDisplayInfo(displayId);          displayManager.setDisplayInfoOverrideFromWindowManagerInternal(displayId, overrideInfo); -        Handler handler = displayManager.getDisplayHandler(); -        handler.runWithScissors(() -> { -        }, 0 /* now */); - -        // register display listener callback -        FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback(displayId); -        bs.registerCallback(callback); +        FakeDisplayManagerCallback callback = registerDisplayListenerCallback( +                displayManager, bs, displayDevice);          // Simulate DisplayDevice change          DisplayDeviceInfo displayDeviceInfo2 = new DisplayDeviceInfo(); @@ -387,9 +373,9 @@ public class DisplayManagerServiceTest {          displayManager.getDisplayDeviceRepository()                  .onDisplayDeviceEvent(displayDevice, DisplayAdapter.DISPLAY_DEVICE_EVENT_CHANGED); -        handler.runWithScissors(() -> { -        }, 0 /* now */); -        assertTrue(callback.mCalled); +        Handler handler = displayManager.getDisplayHandler(); +        waitForIdleHandler(handler); +        assertTrue(callback.mDisplayChangedCalled);      }      /** @@ -400,7 +386,7 @@ public class DisplayManagerServiceTest {          DisplayManagerService displayManager =                  new DisplayManagerService(mContext, mShortMockedInjector);          Handler handler = displayManager.getDisplayHandler(); -        handler.runWithScissors(() -> {}, 0 /* now */); +        waitForIdleHandler(handler);          try {              displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY); @@ -616,7 +602,7 @@ public class DisplayManagerServiceTest {      }      /** -     * Tests that there should be a display change notification if the frame rate overrides +     * Tests that there is a display change notification if the frame rate override       * list is updated.       */      @Test @@ -637,7 +623,7 @@ public class DisplayManagerServiceTest {                  new DisplayEventReceiver.FrameRateOverride[]{                          new DisplayEventReceiver.FrameRateOverride(myUid, 30f),                  }); -        assertTrue(callback.mCalled); +        assertTrue(callback.mDisplayChangedCalled);          callback.clear();          updateFrameRateOverride(displayManager, displayDevice, @@ -645,7 +631,7 @@ public class DisplayManagerServiceTest {                          new DisplayEventReceiver.FrameRateOverride(myUid, 30f),                          new DisplayEventReceiver.FrameRateOverride(1234, 30f),                  }); -        assertFalse(callback.mCalled); +        assertFalse(callback.mDisplayChangedCalled);          updateFrameRateOverride(displayManager, displayDevice,                  new DisplayEventReceiver.FrameRateOverride[]{ @@ -653,7 +639,7 @@ public class DisplayManagerServiceTest {                          new DisplayEventReceiver.FrameRateOverride(1234, 30f),                          new DisplayEventReceiver.FrameRateOverride(5678, 30f),                  }); -        assertTrue(callback.mCalled); +        assertTrue(callback.mDisplayChangedCalled);          callback.clear();          updateFrameRateOverride(displayManager, displayDevice, @@ -661,14 +647,14 @@ public class DisplayManagerServiceTest {                          new DisplayEventReceiver.FrameRateOverride(1234, 30f),                          new DisplayEventReceiver.FrameRateOverride(5678, 30f),                  }); -        assertTrue(callback.mCalled); +        assertTrue(callback.mDisplayChangedCalled);          callback.clear();          updateFrameRateOverride(displayManager, displayDevice,                  new DisplayEventReceiver.FrameRateOverride[]{                          new DisplayEventReceiver.FrameRateOverride(5678, 30f),                  }); -        assertFalse(callback.mCalled); +        assertFalse(callback.mDisplayChangedCalled);      }      /** @@ -760,6 +746,136 @@ public class DisplayManagerServiceTest {                  /*compatChangeEnabled*/  true);      } +    /** +     * Tests that EVENT_DISPLAY_ADDED is sent when a display is added. +     */ +    @Test +    public void testShouldNotifyDisplayAdded_WhenNewDisplayDeviceIsAdded() { +        DisplayManagerService displayManager = +                new DisplayManagerService(mContext, mShortMockedInjector); +        DisplayManagerService.BinderService displayManagerBinderService = +                displayManager.new BinderService(); + +        Handler handler = displayManager.getDisplayHandler(); +        waitForIdleHandler(handler); + +        // register display listener callback +        FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback(); +        displayManagerBinderService.registerCallbackWithEventMask(callback, ALL_DISPLAY_EVENTS); + +        waitForIdleHandler(handler); + +        createFakeDisplayDevice(displayManager, new float[]{60f}); + +        waitForIdleHandler(handler); + +        assertFalse(callback.mDisplayChangedCalled); +        assertFalse(callback.mDisplayRemovedCalled); +        assertTrue(callback.mDisplayAddedCalled); +    } + +    /** +     * Tests that EVENT_DISPLAY_ADDED is not sent when a display is added and the +     * client has a callback which is not subscribed to this event type. +     */ +    @Test +    public void testShouldNotNotifyDisplayAdded_WhenClientIsNotSubscribed() { +        DisplayManagerService displayManager = +                new DisplayManagerService(mContext, mShortMockedInjector); +        DisplayManagerService.BinderService displayManagerBinderService = +                displayManager.new BinderService(); + +        Handler handler = displayManager.getDisplayHandler(); +        waitForIdleHandler(handler); + +        // register display listener callback +        FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback(); +        long allEventsExceptDisplayAdded = ALL_DISPLAY_EVENTS +                & ~DisplayManager.EVENT_FLAG_DISPLAY_ADDED; +        displayManagerBinderService.registerCallbackWithEventMask(callback, +                allEventsExceptDisplayAdded); + +        waitForIdleHandler(handler); + +        createFakeDisplayDevice(displayManager, new float[]{60f}); + +        waitForIdleHandler(handler); + +        assertFalse(callback.mDisplayChangedCalled); +        assertFalse(callback.mDisplayRemovedCalled); +        assertFalse(callback.mDisplayAddedCalled); +    } + +    /** +     * Tests that EVENT_DISPLAY_REMOVED is sent when a display is removed. +     */ +    @Test +    public void testShouldNotifyDisplayRemoved_WhenDisplayDeviceIsRemoved() { +        DisplayManagerService displayManager = +                new DisplayManagerService(mContext, mShortMockedInjector); +        DisplayManagerService.BinderService displayManagerBinderService = +                displayManager.new BinderService(); + +        Handler handler = displayManager.getDisplayHandler(); +        waitForIdleHandler(handler); + +        FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager, +                new float[]{60f}); + +        waitForIdleHandler(handler); + +        FakeDisplayManagerCallback callback = registerDisplayListenerCallback( +                displayManager, displayManagerBinderService, displayDevice); + +        waitForIdleHandler(handler); + +        displayManager.getDisplayDeviceRepository() +                .onDisplayDeviceEvent(displayDevice, DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED); + +        waitForIdleHandler(handler); + +        assertFalse(callback.mDisplayChangedCalled); +        assertTrue(callback.mDisplayRemovedCalled); +        assertFalse(callback.mDisplayAddedCalled); +    } + +    /** +     * Tests that EVENT_DISPLAY_REMOVED is not sent when a display is added and the +     * client has a callback which is not subscribed to this event type. +     */ +    @Test +    public void testShouldNotNotifyDisplayRemoved_WhenClientIsNotSubscribed() { +        DisplayManagerService displayManager = +                new DisplayManagerService(mContext, mShortMockedInjector); +        DisplayManagerService.BinderService displayManagerBinderService = +                displayManager.new BinderService(); + +        Handler handler = displayManager.getDisplayHandler(); +        waitForIdleHandler(handler); + +        FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager, +                new float[]{60f}); + +        waitForIdleHandler(handler); + +        FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback(); +        long allEventsExceptDisplayRemoved = ALL_DISPLAY_EVENTS +                & ~DisplayManager.EVENT_FLAG_DISPLAY_REMOVED; +        displayManagerBinderService.registerCallbackWithEventMask(callback, +                allEventsExceptDisplayRemoved); + +        waitForIdleHandler(handler); + +        displayManager.getDisplayDeviceRepository() +                .onDisplayDeviceEvent(displayDevice, DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED); + +        waitForIdleHandler(handler); + +        assertFalse(callback.mDisplayChangedCalled); +        assertFalse(callback.mDisplayRemovedCalled); +        assertFalse(callback.mDisplayAddedCalled); +    } +      private void testDisplayInfoFrameRateOverrideModeCompat(boolean compatChangeEnabled)              throws Exception {          DisplayManagerService displayManager = @@ -879,8 +995,7 @@ public class DisplayManagerServiceTest {          displayManager.getDisplayDeviceRepository()                  .onDisplayDeviceEvent(displayDevice, DisplayAdapter.DISPLAY_DEVICE_EVENT_CHANGED);          Handler handler = displayManager.getDisplayHandler(); -        handler.runWithScissors(() -> { -        }, 0 /* now */); +        waitForIdleHandler(handler);      }      private void updateFrameRateOverride(DisplayManagerService displayManager, @@ -906,18 +1021,15 @@ public class DisplayManagerServiceTest {              DisplayManagerService.BinderService displayManagerBinderService,              FakeDisplayDevice displayDevice) {          // Find the display id of the added FakeDisplayDevice -        DisplayDeviceInfo displayDeviceInfo = displayDevice.getDisplayDeviceInfoLocked(); -          int displayId = getDisplayIdForDisplayDevice(displayManager, displayManagerBinderService,                  displayDevice);          Handler handler = displayManager.getDisplayHandler(); -        handler.runWithScissors(() -> { -        }, 0 /* now */); +        waitForIdleHandler(handler);          // register display listener callback          FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback(displayId); -        displayManagerBinderService.registerCallback(callback); +        displayManagerBinderService.registerCallbackWithEventMask(callback, ALL_DISPLAY_EVENTS);          return callback;      } @@ -951,6 +1063,10 @@ public class DisplayManagerServiceTest {          // Would prefer to call displayManager.onStart() directly here but it performs binderService          // registration which triggers security exceptions when running from a test.          handler.sendEmptyMessage(MSG_REGISTER_DEFAULT_DISPLAY_ADAPTERS); +        waitForIdleHandler(handler); +    } + +    private void waitForIdleHandler(Handler handler) {          waitForIdleHandler(handler, Duration.ofSeconds(1));      } @@ -971,21 +1087,41 @@ public class DisplayManagerServiceTest {      private class FakeDisplayManagerCallback extends IDisplayManagerCallback.Stub {          int mDisplayId; -        boolean mCalled = false; +        boolean mDisplayAddedCalled = false; +        boolean mDisplayChangedCalled = false; +        boolean mDisplayRemovedCalled = false;          FakeDisplayManagerCallback(int displayId) {              mDisplayId = displayId;          } +        FakeDisplayManagerCallback() { +            mDisplayId = -1; +        } +          @Override          public void onDisplayEvent(int displayId, int event) { -            if (displayId == mDisplayId && event == DisplayManagerGlobal.EVENT_DISPLAY_CHANGED) { -                mCalled = true; +            if (mDisplayId != -1 && displayId != mDisplayId) { +                return; +            } + +            if (event == DisplayManagerGlobal.EVENT_DISPLAY_ADDED) { +                mDisplayAddedCalled = true; +            } + +            if (event == DisplayManagerGlobal.EVENT_DISPLAY_CHANGED) { +                mDisplayChangedCalled = true; +            } + +            if (event == DisplayManagerGlobal.EVENT_DISPLAY_REMOVED) { +                mDisplayRemovedCalled = true;              }          }          public void clear() { -            mCalled = false; +            mDisplayAddedCalled = false; +            mDisplayChangedCalled = false; +            mDisplayRemovedCalled = false;          }      } diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java index 55cd772ad7e0..94e67d16acab 100644 --- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java +++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java @@ -23,15 +23,14 @@ import static org.junit.Assert.assertTrue;  import android.content.om.OverlayIdentifier;  import android.content.om.OverlayInfo; -import android.util.ArraySet;  import androidx.test.runner.AndroidJUnit4;  import org.junit.Test;  import org.junit.runner.RunWith; -import java.util.Arrays; -import java.util.function.BiConsumer; +import java.util.Set; +import java.util.function.Consumer;  @RunWith(AndroidJUnit4.class)  public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceImplTestsBase { @@ -45,51 +44,47 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI      private static final OverlayIdentifier IDENTIFIER2 = new OverlayIdentifier(OVERLAY2);      @Test -    public void testUpdateOverlaysForUser() { +    public void alwaysInitializeAllPackages() {          final OverlayManagerServiceImpl impl = getImpl();          final String otherTarget = "some.other.target";          addPackage(target(TARGET), USER);          addPackage(target(otherTarget), USER);          addPackage(overlay(OVERLAY, TARGET), USER); -        // do nothing, expect no change -        final ArraySet<PackageAndUser> a = impl.updateOverlaysForUser(USER); -        assertEquals(3, a.size()); -        assertTrue(a.containsAll(Arrays.asList( -                new PackageAndUser(TARGET, USER), -                new PackageAndUser(otherTarget, USER), -                new PackageAndUser(OVERLAY, USER)))); - -        final ArraySet<PackageAndUser> b = impl.updateOverlaysForUser(USER); -        assertEquals(3, b.size()); -        assertTrue(b.containsAll(Arrays.asList( -                new PackageAndUser(TARGET, USER), -                new PackageAndUser(otherTarget, USER), -                new PackageAndUser(OVERLAY, USER)))); +        final Set<PackageAndUser> allPackages = +                Set.of(new PackageAndUser(TARGET, USER), +                        new PackageAndUser(otherTarget, USER), +                        new PackageAndUser(OVERLAY, USER)); + +        assertEquals(allPackages, impl.updateOverlaysForUser(USER)); +        assertEquals(allPackages, impl.updateOverlaysForUser(USER));      }      @Test -    public void testImmutableEnabledChange() throws Exception { +    public void testImmutableEnabledChange() {          final OverlayManagerServiceImpl impl = getImpl(); -        installPackage(target(TARGET), USER); -        installPackage(overlay(OVERLAY, TARGET), USER); +        addPackage(target(TARGET), USER); +        addPackage(overlay(OVERLAY, TARGET), USER); -        configureSystemOverlay(OVERLAY, false /* mutable */, false /* enabled */, 0 /* priority */); -        impl.updateOverlaysForUser(USER); +        final Set<PackageAndUser> allPackages = +                Set.of(new PackageAndUser(TARGET, USER), new PackageAndUser(OVERLAY, USER)); + +        configureSystemOverlay(OVERLAY, ConfigState.IMMUTABLE_DISABLED, 0 /* priority */); +        assertEquals(allPackages, impl.updateOverlaysForUser(USER));          final OverlayInfo o1 = impl.getOverlayInfo(IDENTIFIER, USER);          assertNotNull(o1);          assertFalse(o1.isEnabled());          assertFalse(o1.isMutable); -        configureSystemOverlay(OVERLAY, false /* mutable */, true /* enabled */, 0 /* priority */); -        impl.updateOverlaysForUser(USER); +        configureSystemOverlay(OVERLAY, ConfigState.IMMUTABLE_ENABLED, 0 /* priority */); +        assertEquals(allPackages, impl.updateOverlaysForUser(USER));          final OverlayInfo o2 = impl.getOverlayInfo(IDENTIFIER, USER);          assertNotNull(o2);          assertTrue(o2.isEnabled());          assertFalse(o2.isMutable); -        configureSystemOverlay(OVERLAY, false /* mutable */, false /* enabled */, 0 /* priority */); -        impl.updateOverlaysForUser(USER); +        configureSystemOverlay(OVERLAY, ConfigState.IMMUTABLE_DISABLED, 0 /* priority */); +        assertEquals(allPackages, impl.updateOverlaysForUser(USER));          final OverlayInfo o3 = impl.getOverlayInfo(IDENTIFIER, USER);          assertNotNull(o3);          assertFalse(o3.isEnabled()); @@ -97,27 +92,30 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI      }      @Test -    public void testMutableEnabledChangeHasNoEffect() throws Exception { +    public void testMutableEnabledChangeHasNoEffect() {          final OverlayManagerServiceImpl impl = getImpl(); -        installPackage(target(TARGET), USER); -        installPackage(overlay(OVERLAY, TARGET), USER); -        configureSystemOverlay(OVERLAY, true /* mutable */, false /* enabled */, 0 /* priority */); +        addPackage(target(TARGET), USER); +        addPackage(overlay(OVERLAY, TARGET), USER); +        configureSystemOverlay(OVERLAY, ConfigState.MUTABLE_DISABLED, 0 /* priority */); + +        final Set<PackageAndUser> allPackages = +                Set.of(new PackageAndUser(TARGET, USER), new PackageAndUser(OVERLAY, USER)); -        impl.updateOverlaysForUser(USER); +        assertEquals(allPackages, impl.updateOverlaysForUser(USER));          final OverlayInfo o1 = impl.getOverlayInfo(IDENTIFIER, USER);          assertNotNull(o1);          assertFalse(o1.isEnabled());          assertTrue(o1.isMutable); -        configureSystemOverlay(OVERLAY, true /* mutable */, true /* enabled */, 0 /* priority */); -        impl.updateOverlaysForUser(USER); +        configureSystemOverlay(OVERLAY, ConfigState.MUTABLE_ENABLED, 0 /* priority */); +        assertEquals(allPackages, impl.updateOverlaysForUser(USER));          final OverlayInfo o2 = impl.getOverlayInfo(IDENTIFIER, USER);          assertNotNull(o2);          assertFalse(o2.isEnabled());          assertTrue(o2.isMutable); -        configureSystemOverlay(OVERLAY, true /* mutable */, false /* enabled */, 0 /* priority */); -        impl.updateOverlaysForUser(USER); +        configureSystemOverlay(OVERLAY, ConfigState.MUTABLE_DISABLED, 0 /* priority */); +        assertEquals(allPackages, impl.updateOverlaysForUser(USER));          final OverlayInfo o3 = impl.getOverlayInfo(IDENTIFIER, USER);          assertNotNull(o3);          assertFalse(o3.isEnabled()); @@ -125,59 +123,68 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI      }      @Test -    public void testMutableEnabledToImmutableEnabled() throws Exception { +    public void testMutableEnabledToImmutableEnabled() {          final OverlayManagerServiceImpl impl = getImpl(); -        installPackage(target(TARGET), USER); -        installPackage(overlay(OVERLAY, TARGET), USER); +        addPackage(target(TARGET), USER); +        addPackage(overlay(OVERLAY, TARGET), USER); -        final BiConsumer<Boolean, Boolean> setOverlay = (mutable, enabled) -> { -            configureSystemOverlay(OVERLAY, mutable, enabled, 0 /* priority */); -            impl.updateOverlaysForUser(USER); +        final Set<PackageAndUser> allPackages = +                Set.of(new PackageAndUser(TARGET, USER), new PackageAndUser(OVERLAY, USER)); + +        final Consumer<ConfigState> setOverlay = (state -> { +            configureSystemOverlay(OVERLAY, state, 0 /* priority */); +            assertEquals(allPackages, impl.updateOverlaysForUser(USER));              final OverlayInfo o = impl.getOverlayInfo(IDENTIFIER, USER);              assertNotNull(o); -            assertEquals(enabled, o.isEnabled()); -            assertEquals(mutable, o.isMutable); -        }; +            assertEquals(o.isEnabled(), state == ConfigState.IMMUTABLE_ENABLED +                    || state == ConfigState.MUTABLE_ENABLED); +            assertEquals(o.isMutable, state == ConfigState.MUTABLE_DISABLED +                    || state == ConfigState.MUTABLE_ENABLED); +        });          // Immutable/enabled -> mutable/enabled -        setOverlay.accept(false /* mutable */, true /* enabled */); -        setOverlay.accept(true /* mutable */, true /* enabled */); +        setOverlay.accept(ConfigState.IMMUTABLE_ENABLED); +        setOverlay.accept(ConfigState.MUTABLE_ENABLED);          // Mutable/enabled -> immutable/enabled -        setOverlay.accept(false /* mutable */, true /* enabled */); +        setOverlay.accept(ConfigState.IMMUTABLE_ENABLED);          // Immutable/enabled -> mutable/disabled -        setOverlay.accept(true /* mutable */, false /* enabled */); +        setOverlay.accept(ConfigState.MUTABLE_DISABLED);          // Mutable/disabled -> immutable/enabled -        setOverlay.accept(false /* mutable */, true /* enabled */); +        setOverlay.accept(ConfigState.IMMUTABLE_ENABLED);          // Immutable/enabled -> immutable/disabled -        setOverlay.accept(false /* mutable */, false /* enabled */); +        setOverlay.accept(ConfigState.IMMUTABLE_DISABLED);          // Immutable/disabled -> mutable/enabled -        setOverlay.accept(true /* mutable */, true /* enabled */); +        setOverlay.accept(ConfigState.MUTABLE_ENABLED);          // Mutable/enabled -> immutable/disabled -        setOverlay.accept(false /* mutable */, false /* enabled */); +        setOverlay.accept(ConfigState.IMMUTABLE_DISABLED);          // Immutable/disabled -> mutable/disabled -        setOverlay.accept(true /* mutable */, false /* enabled */); +        setOverlay.accept(ConfigState.MUTABLE_DISABLED);          // Mutable/disabled -> immutable/disabled -        setOverlay.accept(false /* mutable */, false /* enabled */); +        setOverlay.accept(ConfigState.IMMUTABLE_DISABLED);      }      @Test      public void testMutablePriorityChange() throws Exception {          final OverlayManagerServiceImpl impl = getImpl(); -        installPackage(target(TARGET), USER); -        installPackage(overlay(OVERLAY, TARGET), USER); -        installPackage(overlay(OVERLAY2, TARGET), USER); -        configureSystemOverlay(OVERLAY, true /* mutable */, false /* enabled */, 0 /* priority */); -        configureSystemOverlay(OVERLAY2, true /* mutable */, false /* enabled */, 1 /* priority */); -        impl.updateOverlaysForUser(USER); +        addPackage(target(TARGET), USER); +        addPackage(overlay(OVERLAY, TARGET), USER); +        addPackage(overlay(OVERLAY2, TARGET), USER); +        configureSystemOverlay(OVERLAY, ConfigState.MUTABLE_DISABLED, 0 /* priority */); +        configureSystemOverlay(OVERLAY2, ConfigState.MUTABLE_DISABLED, 1 /* priority */); +        final Set<PackageAndUser> allPackages = +                Set.of(new PackageAndUser(TARGET, USER), new PackageAndUser(OVERLAY, USER), +                        new PackageAndUser(OVERLAY2, USER)); + +        assertEquals(allPackages, impl.updateOverlaysForUser(USER));          final OverlayInfo o1 = impl.getOverlayInfo(IDENTIFIER, USER);          assertNotNull(o1);          assertEquals(0, o1.priority); @@ -193,10 +200,9 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI          impl.setEnabled(IDENTIFIER, true, USER);          // Reorder the overlays -        configureSystemOverlay(OVERLAY, true /* mutable */, false /* enabled */, 1 /* priority */); -        configureSystemOverlay(OVERLAY2, true /* mutable */, false /* enabled */, 0 /* priority */); -        impl.updateOverlaysForUser(USER); - +        configureSystemOverlay(OVERLAY, ConfigState.MUTABLE_DISABLED, 1 /* priority */); +        configureSystemOverlay(OVERLAY2, ConfigState.MUTABLE_DISABLED, 0 /* priority */); +        assertEquals(allPackages, impl.updateOverlaysForUser(USER));          final OverlayInfo o3 = impl.getOverlayInfo(IDENTIFIER, USER);          assertNotNull(o3);          assertEquals(1, o3.priority); @@ -211,13 +217,17 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI      @Test      public void testImmutablePriorityChange() throws Exception {          final OverlayManagerServiceImpl impl = getImpl(); -        installPackage(target(TARGET), USER); -        installPackage(overlay(OVERLAY, TARGET), USER); -        installPackage(overlay(OVERLAY2, TARGET), USER); -        configureSystemOverlay(OVERLAY, false /* mutable */, true /* enabled */, 0 /* priority */); -        configureSystemOverlay(OVERLAY2, false /* mutable */, true /* enabled */, 1 /* priority */); -        impl.updateOverlaysForUser(USER); +        addPackage(target(TARGET), USER); +        addPackage(overlay(OVERLAY, TARGET), USER); +        addPackage(overlay(OVERLAY2, TARGET), USER); +        configureSystemOverlay(OVERLAY, ConfigState.IMMUTABLE_ENABLED, 0 /* priority */); +        configureSystemOverlay(OVERLAY2, ConfigState.IMMUTABLE_ENABLED, 1 /* priority */); +        final Set<PackageAndUser> allPackages = +                Set.of(new PackageAndUser(TARGET, USER), new PackageAndUser(OVERLAY, USER), +                        new PackageAndUser(OVERLAY2, USER)); + +        assertEquals(allPackages, impl.updateOverlaysForUser(USER));          final OverlayInfo o1 = impl.getOverlayInfo(IDENTIFIER, USER);          assertNotNull(o1);          assertEquals(0, o1.priority); @@ -229,10 +239,9 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI          assertTrue(o2.isEnabled());          // Reorder the overlays -        configureSystemOverlay(OVERLAY, false /* mutable */, true /* enabled */, 1 /* priority */); -        configureSystemOverlay(OVERLAY2, false /* mutable */, true /* enabled */, 0 /* priority */); -        impl.updateOverlaysForUser(USER); - +        configureSystemOverlay(OVERLAY, ConfigState.IMMUTABLE_ENABLED, 1 /* priority */); +        configureSystemOverlay(OVERLAY2, ConfigState.IMMUTABLE_ENABLED, 0 /* priority */); +        assertEquals(allPackages, impl.updateOverlaysForUser(USER));          final OverlayInfo o3 = impl.getOverlayInfo(IDENTIFIER, USER);          assertNotNull(o3);          assertEquals(1, o3.priority); diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java index 45f82a36c8ed..f69141db0872 100644 --- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java +++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java @@ -65,7 +65,8 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes      @Test      public void testGetOverlayInfo() throws Exception { -        installPackage(overlay(OVERLAY, TARGET), USER); +        installAndAssert(overlay(OVERLAY, TARGET), USER, +                Set.of(new PackageAndUser(OVERLAY, USER), new PackageAndUser(TARGET, USER)));          final OverlayManagerServiceImpl impl = getImpl();          final OverlayInfo oi = impl.getOverlayInfo(IDENTIFIER, USER); @@ -77,9 +78,12 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes      @Test      public void testGetOverlayInfosForTarget() throws Exception { -        installPackage(overlay(OVERLAY, TARGET), USER); -        installPackage(overlay(OVERLAY2, TARGET), USER); -        installPackage(overlay(OVERLAY3, TARGET), USER2); +        installAndAssert(overlay(OVERLAY, TARGET), USER, +                Set.of(new PackageAndUser(OVERLAY, USER), new PackageAndUser(TARGET, USER))); +        installAndAssert(overlay(OVERLAY2, TARGET), USER, +                Set.of(new PackageAndUser(OVERLAY2, USER), new PackageAndUser(TARGET, USER))); +        installAndAssert(overlay(OVERLAY3, TARGET), USER2, +                Set.of(new PackageAndUser(OVERLAY3, USER2), new PackageAndUser(TARGET, USER2)));          final OverlayManagerServiceImpl impl = getImpl();          final List<OverlayInfo> ois = impl.getOverlayInfosForTarget(TARGET, USER); @@ -102,10 +106,14 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes      @Test      public void testGetOverlayInfosForUser() throws Exception { -        installPackage(target(TARGET), USER); -        installPackage(overlay(OVERLAY, TARGET), USER); -        installPackage(overlay(OVERLAY2, TARGET), USER); -        installPackage(overlay(OVERLAY3, TARGET2), USER); +        installAndAssert(target(TARGET), USER, +                Set.of(new PackageAndUser(TARGET, USER))); +        installAndAssert(overlay(OVERLAY, TARGET), USER, +                Set.of(new PackageAndUser(OVERLAY, USER), new PackageAndUser(TARGET, USER))); +        installAndAssert(overlay(OVERLAY2, TARGET), USER, +                Set.of(new PackageAndUser(OVERLAY2, USER), new PackageAndUser(TARGET, USER))); +        installAndAssert(overlay(OVERLAY3, TARGET2), USER, +                Set.of(new PackageAndUser(OVERLAY3, USER), new PackageAndUser(TARGET2, USER)));          final OverlayManagerServiceImpl impl = getImpl();          final Map<String, List<OverlayInfo>> everything = impl.getOverlaysForUser(USER); @@ -129,9 +137,12 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes      @Test      public void testPriority() throws Exception { -        installPackage(overlay(OVERLAY, TARGET), USER); -        installPackage(overlay(OVERLAY2, TARGET), USER); -        installPackage(overlay(OVERLAY3, TARGET), USER); +        installAndAssert(overlay(OVERLAY, TARGET), USER, +                Set.of(new PackageAndUser(OVERLAY, USER), new PackageAndUser(TARGET, USER))); +        installAndAssert(overlay(OVERLAY2, TARGET), USER, +                Set.of(new PackageAndUser(OVERLAY2, USER), new PackageAndUser(TARGET, USER))); +        installAndAssert(overlay(OVERLAY3, TARGET), USER, +                Set.of(new PackageAndUser(OVERLAY3, USER), new PackageAndUser(TARGET, USER)));          final OverlayManagerServiceImpl impl = getImpl();          final OverlayInfo o1 = impl.getOverlayInfo(IDENTIFIER, USER); @@ -158,11 +169,12 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes          final OverlayManagerServiceImpl impl = getImpl();          assertNull(impl.getOverlayInfo(IDENTIFIER, USER)); -        installPackage(overlay(OVERLAY, TARGET), USER); +        installAndAssert(overlay(OVERLAY, TARGET), USER, +                Set.of(new PackageAndUser(OVERLAY, USER), new PackageAndUser(TARGET, USER)));          assertState(STATE_MISSING_TARGET, IDENTIFIER, USER); -        final FakeDeviceState.PackageBuilder target = target(TARGET); -        installPackage(target, USER); +        installAndAssert(target(TARGET), USER, +                Set.of(new PackageAndUser(TARGET, USER)));          assertState(STATE_DISABLED, IDENTIFIER, USER);          assertEquals(impl.setEnabled(IDENTIFIER, true, USER), @@ -170,32 +182,35 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes          assertState(STATE_ENABLED, IDENTIFIER, USER);          // target upgrades do not change the state of the overlay -        upgradePackage(target, USER); +        upgradeAndAssert(target(TARGET), USER, +                Set.of(new PackageAndUser(TARGET, USER)), +                Set.of(new PackageAndUser(TARGET, USER)));          assertState(STATE_ENABLED, IDENTIFIER, USER); -        uninstallPackage(TARGET, USER); +        uninstallAndAssert(TARGET, USER, +                Set.of(new PackageAndUser(TARGET, USER)));          assertState(STATE_MISSING_TARGET, IDENTIFIER, USER); -        installPackage(target, USER); +        installAndAssert(target(TARGET), USER, +                Set.of(new PackageAndUser(TARGET, USER)));          assertState(STATE_ENABLED, IDENTIFIER, USER);      }      @Test      public void testOnOverlayPackageUpgraded() throws Exception { -        final FakeDeviceState.PackageBuilder target = target(TARGET); -        final FakeDeviceState.PackageBuilder overlay = overlay(OVERLAY, TARGET); -        installPackage(target, USER); -        installPackage(overlay, USER); -        upgradePackage(overlay, USER); +        installAndAssert(target(TARGET), USER, +                Set.of(new PackageAndUser(TARGET, USER))); +        installAndAssert(overlay(OVERLAY, TARGET), USER, +                Set.of(new PackageAndUser(OVERLAY, USER), new PackageAndUser(TARGET, USER))); +        upgradeAndAssert(overlay(OVERLAY, TARGET), USER, +                Set.of(new PackageAndUser(TARGET, USER)), +                Set.of(new PackageAndUser(TARGET, USER)));          // upgrade to a version where the overlay has changed its target -        final FakeDeviceState.PackageBuilder overlay2 = overlay(OVERLAY, "some.other.target"); -        final Pair<Set<PackageAndUser>, Set<PackageAndUser>> pair = upgradePackage(overlay2, USER); -        assertEquals(pair.first, Set.of(new PackageAndUser(TARGET, USER))); -        assertEquals( +        upgradeAndAssert(overlay(OVERLAY, TARGET2), USER, +                Set.of(new PackageAndUser(TARGET, USER)),                  Set.of(new PackageAndUser(TARGET, USER), -                        new PackageAndUser("some.other.target", USER)), -                pair.second); +                        new PackageAndUser(TARGET2, USER)));      }      @Test @@ -206,13 +221,15 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes          // request succeeded, and there was a change that needs to be          // propagated to the rest of the system -        installPackage(target(TARGET), USER); -        installPackage(overlay(OVERLAY, TARGET), USER); -        assertEquals(impl.setEnabled(IDENTIFIER, true, USER), +        installAndAssert(target(TARGET), USER,                  Set.of(new PackageAndUser(TARGET, USER))); +        installAndAssert(overlay(OVERLAY, TARGET), USER, +                Set.of(new PackageAndUser(OVERLAY, USER), new PackageAndUser(TARGET, USER))); +        assertEquals(Set.of(new PackageAndUser(TARGET, USER)), +                impl.setEnabled(IDENTIFIER, true, USER));          // request succeeded, but nothing changed -        assertTrue(impl.setEnabled(IDENTIFIER, true, USER).isEmpty()); +        assertEquals(Set.of(), impl.setEnabled(IDENTIFIER, true, USER));      }      @Test @@ -221,16 +238,18 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes          reinitializeImpl();          addPackage(target(CONFIG_SIGNATURE_REFERENCE_PKG).setCertificate(CERT_CONFIG_OK), USER); -        installPackage(target(TARGET), USER); -        installPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_OK), USER); +        installAndAssert(target(TARGET), USER, +                Set.of(new PackageAndUser(TARGET, USER))); +        installAndAssert(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_OK), USER, +                Set.of(new PackageAndUser(OVERLAY, USER), new PackageAndUser(TARGET, USER)));          final FakeIdmapDaemon idmapd = getIdmapd();          final FakeDeviceState state = getState(); -        String overlayPath = state.select(OVERLAY, USER).apkPath; +        final String overlayPath = state.select(OVERLAY, USER).apkPath;          assertTrue(idmapd.idmapExists(overlayPath, USER)); -        FakeIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath); -        assertTrue((CONFIG_SIGNATURE & idmap.policies) == CONFIG_SIGNATURE); +        final FakeIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath); +        assertEquals(CONFIG_SIGNATURE, CONFIG_SIGNATURE & idmap.policies);      }      @Test @@ -239,45 +258,51 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes          reinitializeImpl();          addPackage(target(CONFIG_SIGNATURE_REFERENCE_PKG).setCertificate(CERT_CONFIG_OK), USER); -        installPackage(target(TARGET), USER); -        installPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER); +        installAndAssert(target(TARGET), USER, +                Set.of(new PackageAndUser(TARGET, USER))); +        installAndAssert(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER, +                Set.of(new PackageAndUser(OVERLAY, USER), new PackageAndUser(TARGET, USER)));          final FakeIdmapDaemon idmapd = getIdmapd();          final FakeDeviceState state = getState(); -        String overlayPath = state.select(OVERLAY, USER).apkPath; +        final String overlayPath = state.select(OVERLAY, USER).apkPath;          assertTrue(idmapd.idmapExists(overlayPath, USER)); -        FakeIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath); -        assertTrue((CONFIG_SIGNATURE & idmap.policies) == 0); +        final FakeIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath); +        assertEquals(0, CONFIG_SIGNATURE & idmap.policies);      }      @Test      public void testConfigSignaturePolicyNoConfig() throws Exception {          addPackage(target(CONFIG_SIGNATURE_REFERENCE_PKG).setCertificate(CERT_CONFIG_OK), USER); -        installPackage(target(TARGET), USER); -        installPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER); +        installAndAssert(target(TARGET), USER, +                Set.of(new PackageAndUser(TARGET, USER))); +        installAndAssert(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER, +                Set.of(new PackageAndUser(OVERLAY, USER), new PackageAndUser(TARGET, USER)));          final FakeIdmapDaemon idmapd = getIdmapd();          final FakeDeviceState state = getState(); -        String overlayPath = state.select(OVERLAY, USER).apkPath; +        final String overlayPath = state.select(OVERLAY, USER).apkPath;          assertTrue(idmapd.idmapExists(overlayPath, USER)); -        FakeIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath); -        assertTrue((CONFIG_SIGNATURE & idmap.policies) == 0); +        final FakeIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath); +        assertEquals(0, CONFIG_SIGNATURE & idmap.policies);      }      @Test      public void testConfigSignaturePolicyNoRefPkg() throws Exception { -        installPackage(target(TARGET), USER); -        installPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER); +        installAndAssert(target(TARGET), USER, +                Set.of(new PackageAndUser(TARGET, USER))); +        installAndAssert(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER, +                Set.of(new PackageAndUser(OVERLAY, USER), new PackageAndUser(TARGET, USER)));          final FakeIdmapDaemon idmapd = getIdmapd();          final FakeDeviceState state = getState(); -        String overlayPath = state.select(OVERLAY, USER).apkPath; +        final String overlayPath = state.select(OVERLAY, USER).apkPath;          assertTrue(idmapd.idmapExists(overlayPath, USER)); -        FakeIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath); -        assertTrue((CONFIG_SIGNATURE & idmap.policies) == 0); +        final FakeIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath); +        assertEquals(0, CONFIG_SIGNATURE & idmap.policies);      }      @Test @@ -286,8 +311,10 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes          reinitializeImpl();          addPackage(app(CONFIG_SIGNATURE_REFERENCE_PKG).setCertificate(CERT_CONFIG_OK), USER); -        installPackage(target(TARGET), USER); -        installPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER); +        installAndAssert(target(TARGET), USER, +                Set.of(new PackageAndUser(TARGET, USER))); +        installAndAssert(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER, +                Set.of(new PackageAndUser(OVERLAY, USER), new PackageAndUser(TARGET, USER)));          final FakeIdmapDaemon idmapd = getIdmapd();          final FakeDeviceState state = getState(); @@ -295,6 +322,6 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes          assertTrue(idmapd.idmapExists(overlayPath, USER));          FakeIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath); -        assertTrue((CONFIG_SIGNATURE & idmap.policies) == 0); +        assertEquals(0, CONFIG_SIGNATURE & idmap.policies);      }  } diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java index 16e03290b1e4..29ff9f4c282c 100644 --- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java +++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java @@ -139,8 +139,19 @@ class OverlayManagerServiceImplTestsBase {          mState.add(pkg, userId);      } -    void configureSystemOverlay(String packageName, boolean mutable, boolean enabled, +    enum ConfigState { +        IMMUTABLE_DISABLED, +        IMMUTABLE_ENABLED, +        MUTABLE_DISABLED, +        MUTABLE_ENABLED +    } + +    void configureSystemOverlay(@NonNull String packageName, @NonNull ConfigState state,              int priority) { +        final boolean mutable = state == ConfigState.MUTABLE_DISABLED +                || state == ConfigState.MUTABLE_ENABLED; +        final boolean enabled = state == ConfigState.IMMUTABLE_ENABLED +                || state == ConfigState.MUTABLE_ENABLED;          when(mOverlayConfig.getPriority(packageName)).thenReturn(priority);          when(mOverlayConfig.isEnabled(packageName)).thenReturn(enabled);          when(mOverlayConfig.isMutable(packageName)).thenReturn(mutable); @@ -154,13 +165,14 @@ class OverlayManagerServiceImplTestsBase {       *       * @throws IllegalStateException if the package is currently installed       */ -    Set<PackageAndUser> installPackage(FakeDeviceState.PackageBuilder pkg, int userId) +    void installAndAssert(@NonNull FakeDeviceState.PackageBuilder pkg, int userId, +            @NonNull Set<PackageAndUser> onAddedUpdatedPackages)              throws OperationFailedException {          if (mState.select(pkg.packageName, userId) != null) {              throw new IllegalStateException("package " + pkg.packageName + " already installed");          }          mState.add(pkg, userId); -        return CollectionUtils.emptyIfNull(mImpl.onPackageAdded(pkg.packageName, userId)); +        assertEquals(onAddedUpdatedPackages, mImpl.onPackageAdded(pkg.packageName, userId));      }      /** @@ -172,25 +184,20 @@ class OverlayManagerServiceImplTestsBase {       * {@link android.content.Intent#ACTION_PACKAGE_ADDED} broadcast with the       * {@link android.content.Intent#EXTRA_REPLACING} extra.       * -     * @return the two Optional<PackageAndUser> objects from starting and finishing the upgrade -     *       * @throws IllegalStateException if the package is not currently installed       */ -    Pair<Set<PackageAndUser>, Set<PackageAndUser>> upgradePackage( -            FakeDeviceState.PackageBuilder pkg, int userId) throws OperationFailedException { +    void upgradeAndAssert(FakeDeviceState.PackageBuilder pkg, int userId, +            @NonNull Set<PackageAndUser> onReplacingUpdatedPackages, +            @NonNull Set<PackageAndUser> onReplacedUpdatedPackages) +            throws OperationFailedException {          final FakeDeviceState.Package replacedPackage = mState.select(pkg.packageName, userId);          if (replacedPackage == null) {              throw new IllegalStateException("package " + pkg.packageName + " not installed");          } -        final Set<PackageAndUser> updatedPackages1 = -                CollectionUtils.emptyIfNull(mImpl.onPackageReplacing(pkg.packageName, userId)); - +        assertEquals(onReplacingUpdatedPackages, mImpl.onPackageReplacing(pkg.packageName, userId));          mState.add(pkg, userId); -        final Set<PackageAndUser> updatedPackages2 = -                CollectionUtils.emptyIfNull(mImpl.onPackageReplaced(pkg.packageName, userId)); - -        return Pair.create(updatedPackages1, updatedPackages2); +        assertEquals(onReplacedUpdatedPackages, mImpl.onPackageReplaced(pkg.packageName, userId));      }      /** @@ -201,13 +208,14 @@ class OverlayManagerServiceImplTestsBase {       *       * @throws IllegalStateException if the package is not currently installed       */ -    Set<PackageAndUser> uninstallPackage(String packageName, int userId) { +    void uninstallAndAssert(@NonNull String packageName, int userId, +            @NonNull Set<PackageAndUser> onRemovedUpdatedPackages) {          final FakeDeviceState.Package pkg = mState.select(packageName, userId);          if (pkg == null) { -            throw new IllegalStateException("package " + packageName+ " not installed"); +            throw new IllegalStateException("package " + packageName + " not installed");          }          mState.remove(pkg.packageName); -        return CollectionUtils.emptyIfNull(mImpl.onPackageRemoved(packageName, userId)); +        assertEquals(onRemovedUpdatedPackages, mImpl.onPackageRemoved(pkg.packageName, userId));      }      /** Represents the state of packages installed on a fake device. */ diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/ArtStatsLogUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/ArtStatsLogUtilsTest.java index e605d755183f..13d75a77507f 100644 --- a/services/tests/servicestests/src/com/android/server/pm/dex/ArtStatsLogUtilsTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/dex/ArtStatsLogUtilsTest.java @@ -245,14 +245,6 @@ public final class ArtStatsLogUtilsTest {                  UID,                  COMPILATION_REASON,                  COMPILER_FILTER, -                ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_DEX_CODE_BYTES, -                DEX_CONTENT.length, -                dexMetadataType); -        inorder.verify(mockLogger).write( -                SESSION_ID, -                UID, -                COMPILATION_REASON, -                COMPILER_FILTER,                  ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_TOTAL_TIME,                  COMPILE_TIME,                  dexMetadataType); diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java index 624c3de650aa..86b162087f61 100644 --- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java +++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java @@ -1390,6 +1390,21 @@ public class AppStandbyControllerTests {      }      @Test +    public void testRestrictApp_MainReason() throws Exception { +        mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE, +                REASON_MAIN_DEFAULT); +        mInjector.mElapsedRealtime += 4 * RESTRICTED_THRESHOLD; + +        mController.restrictApp(PACKAGE_1, USER_ID, REASON_MAIN_PREDICTED, 0); +        // Call should be ignored. +        assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1)); + +        mController.restrictApp(PACKAGE_1, USER_ID, REASON_MAIN_FORCED_BY_USER, 0); +        // Call should go through +        assertEquals(STANDBY_BUCKET_RESTRICTED, getStandbyBucket(mController, PACKAGE_1)); +    } + +    @Test      public void testAddActiveDeviceAdmin() throws Exception {          assertActiveAdmins(USER_ID, (String[]) null);          assertActiveAdmins(USER_ID2, (String[]) null); diff --git a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java index 6c722499da4b..bb9e24fa6813 100644 --- a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java +++ b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java @@ -198,11 +198,6 @@ public class StubTransaction extends SurfaceControl.Transaction {      }      @Override -    public SurfaceControl.Transaction setEarlyWakeup() { -        return this; -    } - -    @Override      public SurfaceControl.Transaction setMetadata(SurfaceControl sc, int key, int data) {          return this;      }  |