diff options
324 files changed, 6363 insertions, 5259 deletions
diff --git a/Android.bp b/Android.bp index 586350df36b1..b3dc98b2fa06 100644 --- a/Android.bp +++ b/Android.bp @@ -380,9 +380,6 @@ filegroup { // etc. ":framework-javastream-protos", ":statslog-framework-java-gen", // FrameworkStatsLog.java - - // telephony annotations - ":framework-telephony-annotations", ], } @@ -1270,23 +1267,6 @@ filegroup { } // Avoid including Parcelable classes as we don't want to have two copies of -// Parcelable cross the process. This is used by framework-telephony (frameworks/base/telephony). -filegroup { - name: "framework-telephony-shared-srcs", - srcs: [ - "core/java/android/util/IndentingPrintWriter.java", - "core/java/android/util/RecurrenceRule.java", - "core/java/com/android/internal/os/SomeArgs.java", - "core/java/com/android/internal/util/BitwiseInputStream.java", - "core/java/com/android/internal/util/BitwiseOutputStream.java", - "core/java/com/android/internal/util/FunctionalUtils.java", - "core/java/com/android/internal/util/HexDump.java", - "core/java/com/android/internal/util/IndentingPrintWriter.java", - "core/java/com/android/internal/util/Preconditions.java", - ], -} - -// Avoid including Parcelable classes as we don't want to have two copies of // Parcelable cross the process. filegroup { name: "framework-cellbroadcast-shared-srcs", @@ -1314,7 +1294,7 @@ filegroup { // into wifi-service java_library { name: "framework-wifi-util-lib", - sdk_version: "module_current", + sdk_version: "module_30", srcs: [ "core/java/android/content/pm/BaseParceledListSlice.java", "core/java/android/content/pm/ParceledListSlice.java", @@ -1383,73 +1363,6 @@ build = [ "ApiDocs.bp", ] -// TODO(b/147699819): move to frameworks/base/telephony/ folder -droidstubs { - name: "framework-telephony-stubs-srcs", - srcs: [ - ":framework-telephony-sources", - ":framework_native_aidl", - ":framework-javastream-protos", - ], - aidl: { - local_include_dirs: [ - "core/java", - "telecomm/java" - ], - }, - libs: [ - "framework-annotations-lib", - "android.hardware.radio-V1.6-java", - ], - check_api: { - current: { - // TODO(b/147699819): remove telephony prefix when moved - api_file: "telephony/api/system-current.txt", - removed_api_file: "telephony/api/system-removed.txt", - }, - }, - // TODO: make telephony inherit the shared stubs and remove this - args: "--show-annotation android.annotation.SystemApi\\(" + - "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS" + - "\\) " + - "--error UnhiddenSystemApi " + - "--hide BroadcastBehavior " + - "--hide DeprecationMismatch " + - "--hide HiddenSuperclass " + - "--hide HiddenTypedefConstant " + - "--hide HiddenTypeParameter " + - "--hide MissingPermission " + - "--hide RequiresPermission " + - "--hide SdkConstant " + - "--hide Todo " + - "--hide Typo " + - "--hide UnavailableSymbol ", - filter_packages: ["android.telephony"], - sdk_version: "system_current", -} - -java_library { - name: "framework-telephony-stubs", - srcs: [":framework-telephony-stubs-srcs"], - // TODO(b/147699819): move public aidls to a separate folder and potentially remove - // below aidl exports. - aidl: { - export_include_dirs: ["telephony/java"], - }, - sdk_version: "module_current", -} - -filegroup { - // TODO (b/147690217): move to frameworks/base/telephony/common. - name: "framework-telephony-annotations", - srcs: ["telephony/java/android/telephony/Annotation.java"], -} - -filegroup { - name: "framework-telephony-jarjar-rules", - srcs: ["telephony/framework-telephony-jarjar-rules.txt"], -} - // protolog start filegroup { name: "protolog-common-src", 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 6c14233dba13..34e82b0ce45e 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java @@ -339,6 +339,11 @@ public class JobSchedulerService extends com.android.server.SystemService public void onPropertiesChanged(DeviceConfig.Properties properties) { boolean apiQuotaScheduleUpdated = false; boolean concurrencyUpdated = false; + for (int controller = 0; controller < mControllers.size(); controller++) { + final StateController sc = mControllers.get(controller); + sc.prepareForUpdatedConstantsLocked(); + } + synchronized (mLock) { for (String name : properties.getKeyset()) { if (name == null) { @@ -384,6 +389,11 @@ public class JobSchedulerService extends com.android.server.SystemService && !concurrencyUpdated) { mConstants.updateConcurrencyConstantsLocked(); concurrencyUpdated = true; + } else { + for (int ctrlr = 0; ctrlr < mControllers.size(); ctrlr++) { + final StateController sc = mControllers.get(ctrlr); + sc.processConstantLocked(properties, name); + } } break; } diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java index c7cc2f03b062..00dbb8235d29 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java @@ -1388,6 +1388,11 @@ public final class JobStatus { } if (isReady()) { sb.append(" READY"); + } else { + sb.append(" satisfied:0x").append(Integer.toHexString(satisfiedConstraints)); + sb.append(" unsatisfied:0x").append(Integer.toHexString( + (satisfiedConstraints & mRequiredConstraintsOfInterest) + ^ mRequiredConstraintsOfInterest)); } sb.append("}"); return sb.toString(); 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 c06e19cbf687..b7ace70f0cd4 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java @@ -37,12 +37,9 @@ import android.app.AlarmManager; import android.app.AppGlobals; import android.app.IUidObserver; import android.content.BroadcastReceiver; -import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.database.ContentObserver; -import android.net.Uri; import android.os.BatteryManager; import android.os.BatteryManagerInternal; import android.os.Handler; @@ -50,10 +47,9 @@ import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.os.UserHandle; -import android.provider.Settings; +import android.provider.DeviceConfig; import android.util.ArraySet; import android.util.IndentingPrintWriter; -import android.util.KeyValueListParser; import android.util.Log; import android.util.Pair; import android.util.Slog; @@ -494,7 +490,7 @@ public final class QuotaController extends StateController { mChargeTracker.startTracking(); mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); - mQcConstants = new QcConstants(mHandler); + mQcConstants = new QcConstants(); final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED); mContext.registerReceiverAsUser(mPackageAddedReceiver, UserHandle.ALL, filter, null, null); @@ -513,11 +509,6 @@ public final class QuotaController extends StateController { } @Override - public void onSystemServicesReady() { - mQcConstants.start(mContext.getContentResolver()); - } - - @Override public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) { final int userId = jobStatus.getSourceUserId(); final String pkgName = jobStatus.getSourcePackageName(); @@ -2028,38 +2019,109 @@ public final class QuotaController extends StateController { } } + @Override + public void prepareForUpdatedConstantsLocked() { + mQcConstants.mShouldReevaluateConstraints = false; + mQcConstants.mRateLimitingConstantsUpdated = false; + mQcConstants.mExecutionPeriodConstantsUpdated = false; + } + + @Override + public void processConstantLocked(DeviceConfig.Properties properties, String key) { + mQcConstants.processConstantLocked(properties, key); + } + + @Override + public void onConstantsUpdatedLocked() { + if (mQcConstants.mShouldReevaluateConstraints) { + // Update job bookkeeping out of band. + JobSchedulerBackgroundThread.getHandler().post(() -> { + synchronized (mLock) { + invalidateAllExecutionStatsLocked(); + maybeUpdateAllConstraintsLocked(); + } + }); + } + } + @VisibleForTesting - class QcConstants extends ContentObserver { - private ContentResolver mResolver; - private final KeyValueListParser mParser = new KeyValueListParser(','); - - private static final String KEY_ALLOWED_TIME_PER_PERIOD_MS = "allowed_time_per_period_ms"; - private static final String KEY_IN_QUOTA_BUFFER_MS = "in_quota_buffer_ms"; - private static final String KEY_WINDOW_SIZE_ACTIVE_MS = "window_size_active_ms"; - private static final String KEY_WINDOW_SIZE_WORKING_MS = "window_size_working_ms"; - private static final String KEY_WINDOW_SIZE_FREQUENT_MS = "window_size_frequent_ms"; - private static final String KEY_WINDOW_SIZE_RARE_MS = "window_size_rare_ms"; - private static final String KEY_WINDOW_SIZE_RESTRICTED_MS = "window_size_restricted_ms"; - private static final String KEY_MAX_EXECUTION_TIME_MS = "max_execution_time_ms"; - private static final String KEY_MAX_JOB_COUNT_ACTIVE = "max_job_count_active"; - private static final String KEY_MAX_JOB_COUNT_WORKING = "max_job_count_working"; - private static final String KEY_MAX_JOB_COUNT_FREQUENT = "max_job_count_frequent"; - private static final String KEY_MAX_JOB_COUNT_RARE = "max_job_count_rare"; - private static final String KEY_MAX_JOB_COUNT_RESTRICTED = "max_job_count_restricted"; - private static final String KEY_RATE_LIMITING_WINDOW_MS = "rate_limiting_window_ms"; - private static final String KEY_MAX_JOB_COUNT_PER_RATE_LIMITING_WINDOW = - "max_job_count_per_rate_limiting_window"; - private static final String KEY_MAX_SESSION_COUNT_ACTIVE = "max_session_count_active"; - private static final String KEY_MAX_SESSION_COUNT_WORKING = "max_session_count_working"; - private static final String KEY_MAX_SESSION_COUNT_FREQUENT = "max_session_count_frequent"; - private static final String KEY_MAX_SESSION_COUNT_RARE = "max_session_count_rare"; - private static final String KEY_MAX_SESSION_COUNT_RESTRICTED = - "max_session_count_restricted"; - private static final String KEY_MAX_SESSION_COUNT_PER_RATE_LIMITING_WINDOW = - "max_session_count_per_rate_limiting_window"; - private static final String KEY_TIMING_SESSION_COALESCING_DURATION_MS = - "timing_session_coalescing_duration_ms"; - private static final String KEY_MIN_QUOTA_CHECK_DELAY_MS = "min_quota_check_delay_ms"; + class QcConstants { + private boolean mShouldReevaluateConstraints = false; + private boolean mRateLimitingConstantsUpdated = false; + private boolean mExecutionPeriodConstantsUpdated = false; + + /** Prefix to use with all constant keys in order to "sub-namespace" the keys. */ + private static final String QC_CONSTANT_PREFIX = "qc_"; + + @VisibleForTesting + static final String KEY_ALLOWED_TIME_PER_PERIOD_MS = + QC_CONSTANT_PREFIX + "allowed_time_per_period_ms"; + @VisibleForTesting + static final String KEY_IN_QUOTA_BUFFER_MS = + QC_CONSTANT_PREFIX + "in_quota_buffer_ms"; + @VisibleForTesting + static final String KEY_WINDOW_SIZE_ACTIVE_MS = + QC_CONSTANT_PREFIX + "window_size_active_ms"; + @VisibleForTesting + static final String KEY_WINDOW_SIZE_WORKING_MS = + QC_CONSTANT_PREFIX + "window_size_working_ms"; + @VisibleForTesting + static final String KEY_WINDOW_SIZE_FREQUENT_MS = + QC_CONSTANT_PREFIX + "window_size_frequent_ms"; + @VisibleForTesting + static final String KEY_WINDOW_SIZE_RARE_MS = + QC_CONSTANT_PREFIX + "window_size_rare_ms"; + @VisibleForTesting + static final String KEY_WINDOW_SIZE_RESTRICTED_MS = + QC_CONSTANT_PREFIX + "window_size_restricted_ms"; + @VisibleForTesting + static final String KEY_MAX_EXECUTION_TIME_MS = + QC_CONSTANT_PREFIX + "max_execution_time_ms"; + @VisibleForTesting + static final String KEY_MAX_JOB_COUNT_ACTIVE = + QC_CONSTANT_PREFIX + "max_job_count_active"; + @VisibleForTesting + static final String KEY_MAX_JOB_COUNT_WORKING = + QC_CONSTANT_PREFIX + "max_job_count_working"; + @VisibleForTesting + static final String KEY_MAX_JOB_COUNT_FREQUENT = + QC_CONSTANT_PREFIX + "max_job_count_frequent"; + @VisibleForTesting + static final String KEY_MAX_JOB_COUNT_RARE = + QC_CONSTANT_PREFIX + "max_job_count_rare"; + @VisibleForTesting + static final String KEY_MAX_JOB_COUNT_RESTRICTED = + QC_CONSTANT_PREFIX + "max_job_count_restricted"; + @VisibleForTesting + static final String KEY_RATE_LIMITING_WINDOW_MS = + QC_CONSTANT_PREFIX + "rate_limiting_window_ms"; + @VisibleForTesting + static final String KEY_MAX_JOB_COUNT_PER_RATE_LIMITING_WINDOW = + QC_CONSTANT_PREFIX + "max_job_count_per_rate_limiting_window"; + @VisibleForTesting + static final String KEY_MAX_SESSION_COUNT_ACTIVE = + QC_CONSTANT_PREFIX + "max_session_count_active"; + @VisibleForTesting + static final String KEY_MAX_SESSION_COUNT_WORKING = + QC_CONSTANT_PREFIX + "max_session_count_working"; + @VisibleForTesting + static final String KEY_MAX_SESSION_COUNT_FREQUENT = + QC_CONSTANT_PREFIX + "max_session_count_frequent"; + @VisibleForTesting + static final String KEY_MAX_SESSION_COUNT_RARE = + QC_CONSTANT_PREFIX + "max_session_count_rare"; + @VisibleForTesting + static final String KEY_MAX_SESSION_COUNT_RESTRICTED = + QC_CONSTANT_PREFIX + "max_session_count_restricted"; + @VisibleForTesting + static final String KEY_MAX_SESSION_COUNT_PER_RATE_LIMITING_WINDOW = + QC_CONSTANT_PREFIX + "max_session_count_per_rate_limiting_window"; + @VisibleForTesting + static final String KEY_TIMING_SESSION_COALESCING_DURATION_MS = + QC_CONSTANT_PREFIX + "timing_session_coalescing_duration_ms"; + @VisibleForTesting + static final String KEY_MIN_QUOTA_CHECK_DELAY_MS = + QC_CONSTANT_PREFIX + "min_quota_check_delay_ms"; private static final long DEFAULT_ALLOWED_TIME_PER_PERIOD_MS = 10 * 60 * 1000L; // 10 minutes @@ -2260,238 +2322,273 @@ public final class QuotaController extends StateController { /** The minimum value that {@link #RATE_LIMITING_WINDOW_MS} can have. */ private static final long MIN_RATE_LIMITING_WINDOW_MS = 30 * SECOND_IN_MILLIS; - QcConstants(Handler handler) { - super(handler); - } + public void processConstantLocked(@NonNull DeviceConfig.Properties properties, + @NonNull String key) { + switch (key) { + case KEY_ALLOWED_TIME_PER_PERIOD_MS: + case KEY_IN_QUOTA_BUFFER_MS: + case KEY_MAX_EXECUTION_TIME_MS: + case KEY_WINDOW_SIZE_ACTIVE_MS: + case KEY_WINDOW_SIZE_WORKING_MS: + case KEY_WINDOW_SIZE_FREQUENT_MS: + case KEY_WINDOW_SIZE_RARE_MS: + case KEY_WINDOW_SIZE_RESTRICTED_MS: + updateExecutionPeriodConstantsLocked(); + break; - private void start(ContentResolver resolver) { - mResolver = resolver; - mResolver.registerContentObserver(Settings.Global.getUriFor( - Settings.Global.JOB_SCHEDULER_QUOTA_CONTROLLER_CONSTANTS), false, this); - onChange(true, null); - } + case KEY_RATE_LIMITING_WINDOW_MS: + case KEY_MAX_JOB_COUNT_PER_RATE_LIMITING_WINDOW: + case KEY_MAX_SESSION_COUNT_PER_RATE_LIMITING_WINDOW: + updateRateLimitingConstantsLocked(); + break; - @Override - public void onChange(boolean selfChange, Uri uri) { - final String constants = Settings.Global.getString( - mResolver, Settings.Global.JOB_SCHEDULER_QUOTA_CONTROLLER_CONSTANTS); - - try { - mParser.setString(constants); - } catch (Exception e) { - // Failed to parse the settings string, log this and move on with defaults. - Slog.e(TAG, "Bad jobscheduler quota controller settings", e); - } - - ALLOWED_TIME_PER_PERIOD_MS = mParser.getDurationMillis( - KEY_ALLOWED_TIME_PER_PERIOD_MS, DEFAULT_ALLOWED_TIME_PER_PERIOD_MS); - IN_QUOTA_BUFFER_MS = mParser.getDurationMillis( - KEY_IN_QUOTA_BUFFER_MS, DEFAULT_IN_QUOTA_BUFFER_MS); - WINDOW_SIZE_ACTIVE_MS = mParser.getDurationMillis( - KEY_WINDOW_SIZE_ACTIVE_MS, DEFAULT_WINDOW_SIZE_ACTIVE_MS); - WINDOW_SIZE_WORKING_MS = mParser.getDurationMillis( - KEY_WINDOW_SIZE_WORKING_MS, DEFAULT_WINDOW_SIZE_WORKING_MS); - WINDOW_SIZE_FREQUENT_MS = mParser.getDurationMillis( - KEY_WINDOW_SIZE_FREQUENT_MS, DEFAULT_WINDOW_SIZE_FREQUENT_MS); - WINDOW_SIZE_RARE_MS = mParser.getDurationMillis( - KEY_WINDOW_SIZE_RARE_MS, DEFAULT_WINDOW_SIZE_RARE_MS); - WINDOW_SIZE_RESTRICTED_MS = mParser.getDurationMillis( - KEY_WINDOW_SIZE_RESTRICTED_MS, DEFAULT_WINDOW_SIZE_RESTRICTED_MS); - MAX_EXECUTION_TIME_MS = mParser.getDurationMillis( - KEY_MAX_EXECUTION_TIME_MS, DEFAULT_MAX_EXECUTION_TIME_MS); - MAX_JOB_COUNT_ACTIVE = mParser.getInt( - KEY_MAX_JOB_COUNT_ACTIVE, DEFAULT_MAX_JOB_COUNT_ACTIVE); - MAX_JOB_COUNT_WORKING = mParser.getInt( - KEY_MAX_JOB_COUNT_WORKING, DEFAULT_MAX_JOB_COUNT_WORKING); - MAX_JOB_COUNT_FREQUENT = mParser.getInt( - KEY_MAX_JOB_COUNT_FREQUENT, DEFAULT_MAX_JOB_COUNT_FREQUENT); - MAX_JOB_COUNT_RARE = mParser.getInt( - KEY_MAX_JOB_COUNT_RARE, DEFAULT_MAX_JOB_COUNT_RARE); - MAX_JOB_COUNT_RESTRICTED = mParser.getInt( - KEY_MAX_JOB_COUNT_RESTRICTED, DEFAULT_MAX_JOB_COUNT_RESTRICTED); - RATE_LIMITING_WINDOW_MS = mParser.getLong( - KEY_RATE_LIMITING_WINDOW_MS, DEFAULT_RATE_LIMITING_WINDOW_MS); - MAX_JOB_COUNT_PER_RATE_LIMITING_WINDOW = mParser.getInt( - KEY_MAX_JOB_COUNT_PER_RATE_LIMITING_WINDOW, - DEFAULT_MAX_JOB_COUNT_PER_RATE_LIMITING_WINDOW); - MAX_SESSION_COUNT_ACTIVE = mParser.getInt( - KEY_MAX_SESSION_COUNT_ACTIVE, DEFAULT_MAX_SESSION_COUNT_ACTIVE); - MAX_SESSION_COUNT_WORKING = mParser.getInt( - KEY_MAX_SESSION_COUNT_WORKING, DEFAULT_MAX_SESSION_COUNT_WORKING); - MAX_SESSION_COUNT_FREQUENT = mParser.getInt( - KEY_MAX_SESSION_COUNT_FREQUENT, DEFAULT_MAX_SESSION_COUNT_FREQUENT); - MAX_SESSION_COUNT_RARE = mParser.getInt( - KEY_MAX_SESSION_COUNT_RARE, DEFAULT_MAX_SESSION_COUNT_RARE); - MAX_SESSION_COUNT_RESTRICTED = mParser.getInt( - KEY_MAX_SESSION_COUNT_RESTRICTED, DEFAULT_MAX_SESSION_COUNT_RESTRICTED); - MAX_SESSION_COUNT_PER_RATE_LIMITING_WINDOW = mParser.getInt( - KEY_MAX_SESSION_COUNT_PER_RATE_LIMITING_WINDOW, - DEFAULT_MAX_SESSION_COUNT_PER_RATE_LIMITING_WINDOW); - TIMING_SESSION_COALESCING_DURATION_MS = mParser.getLong( - KEY_TIMING_SESSION_COALESCING_DURATION_MS, - DEFAULT_TIMING_SESSION_COALESCING_DURATION_MS); - MIN_QUOTA_CHECK_DELAY_MS = mParser.getDurationMillis(KEY_MIN_QUOTA_CHECK_DELAY_MS, - DEFAULT_MIN_QUOTA_CHECK_DELAY_MS); - - updateConstants(); + case KEY_MAX_JOB_COUNT_ACTIVE: + MAX_JOB_COUNT_ACTIVE = properties.getInt(key, DEFAULT_MAX_JOB_COUNT_ACTIVE); + int newActiveMaxJobCount = Math.max(MIN_BUCKET_JOB_COUNT, MAX_JOB_COUNT_ACTIVE); + if (mMaxBucketJobCounts[ACTIVE_INDEX] != newActiveMaxJobCount) { + mMaxBucketJobCounts[ACTIVE_INDEX] = newActiveMaxJobCount; + mShouldReevaluateConstraints = true; + } + break; + case KEY_MAX_JOB_COUNT_WORKING: + MAX_JOB_COUNT_WORKING = properties.getInt(key, DEFAULT_MAX_JOB_COUNT_WORKING); + int newWorkingMaxJobCount = Math.max(MIN_BUCKET_JOB_COUNT, + MAX_JOB_COUNT_WORKING); + if (mMaxBucketJobCounts[WORKING_INDEX] != newWorkingMaxJobCount) { + mMaxBucketJobCounts[WORKING_INDEX] = newWorkingMaxJobCount; + mShouldReevaluateConstraints = true; + } + break; + case KEY_MAX_JOB_COUNT_FREQUENT: + MAX_JOB_COUNT_FREQUENT = properties.getInt(key, DEFAULT_MAX_JOB_COUNT_FREQUENT); + int newFrequentMaxJobCount = Math.max(MIN_BUCKET_JOB_COUNT, + MAX_JOB_COUNT_FREQUENT); + if (mMaxBucketJobCounts[FREQUENT_INDEX] != newFrequentMaxJobCount) { + mMaxBucketJobCounts[FREQUENT_INDEX] = newFrequentMaxJobCount; + mShouldReevaluateConstraints = true; + } + break; + case KEY_MAX_JOB_COUNT_RARE: + MAX_JOB_COUNT_RARE = properties.getInt(key, DEFAULT_MAX_JOB_COUNT_RARE); + int newRareMaxJobCount = Math.max(MIN_BUCKET_JOB_COUNT, MAX_JOB_COUNT_RARE); + if (mMaxBucketJobCounts[RARE_INDEX] != newRareMaxJobCount) { + mMaxBucketJobCounts[RARE_INDEX] = newRareMaxJobCount; + mShouldReevaluateConstraints = true; + } + break; + case KEY_MAX_JOB_COUNT_RESTRICTED: + MAX_JOB_COUNT_RESTRICTED = + properties.getInt(key, DEFAULT_MAX_JOB_COUNT_RESTRICTED); + int newRestrictedMaxJobCount = + Math.max(MIN_BUCKET_JOB_COUNT, MAX_JOB_COUNT_RESTRICTED); + if (mMaxBucketJobCounts[RESTRICTED_INDEX] != newRestrictedMaxJobCount) { + mMaxBucketJobCounts[RESTRICTED_INDEX] = newRestrictedMaxJobCount; + mShouldReevaluateConstraints = true; + } + break; + case KEY_MAX_SESSION_COUNT_ACTIVE: + MAX_SESSION_COUNT_ACTIVE = + properties.getInt(key, DEFAULT_MAX_SESSION_COUNT_ACTIVE); + int newActiveMaxSessionCount = + Math.max(MIN_BUCKET_SESSION_COUNT, MAX_SESSION_COUNT_ACTIVE); + if (mMaxBucketSessionCounts[ACTIVE_INDEX] != newActiveMaxSessionCount) { + mMaxBucketSessionCounts[ACTIVE_INDEX] = newActiveMaxSessionCount; + mShouldReevaluateConstraints = true; + } + break; + case KEY_MAX_SESSION_COUNT_WORKING: + MAX_SESSION_COUNT_WORKING = + properties.getInt(key, DEFAULT_MAX_SESSION_COUNT_WORKING); + int newWorkingMaxSessionCount = + Math.max(MIN_BUCKET_SESSION_COUNT, MAX_SESSION_COUNT_WORKING); + if (mMaxBucketSessionCounts[WORKING_INDEX] != newWorkingMaxSessionCount) { + mMaxBucketSessionCounts[WORKING_INDEX] = newWorkingMaxSessionCount; + mShouldReevaluateConstraints = true; + } + break; + case KEY_MAX_SESSION_COUNT_FREQUENT: + MAX_SESSION_COUNT_FREQUENT = + properties.getInt(key, DEFAULT_MAX_SESSION_COUNT_FREQUENT); + int newFrequentMaxSessionCount = + Math.max(MIN_BUCKET_SESSION_COUNT, MAX_SESSION_COUNT_FREQUENT); + if (mMaxBucketSessionCounts[FREQUENT_INDEX] != newFrequentMaxSessionCount) { + mMaxBucketSessionCounts[FREQUENT_INDEX] = newFrequentMaxSessionCount; + mShouldReevaluateConstraints = true; + } + break; + case KEY_MAX_SESSION_COUNT_RARE: + MAX_SESSION_COUNT_RARE = properties.getInt(key, DEFAULT_MAX_SESSION_COUNT_RARE); + int newRareMaxSessionCount = + Math.max(MIN_BUCKET_SESSION_COUNT, MAX_SESSION_COUNT_RARE); + if (mMaxBucketSessionCounts[RARE_INDEX] != newRareMaxSessionCount) { + mMaxBucketSessionCounts[RARE_INDEX] = newRareMaxSessionCount; + mShouldReevaluateConstraints = true; + } + break; + case KEY_MAX_SESSION_COUNT_RESTRICTED: + MAX_SESSION_COUNT_RESTRICTED = + properties.getInt(key, DEFAULT_MAX_SESSION_COUNT_RESTRICTED); + int newRestrictedMaxSessionCount = Math.max(0, MAX_SESSION_COUNT_RESTRICTED); + if (mMaxBucketSessionCounts[RESTRICTED_INDEX] != newRestrictedMaxSessionCount) { + mMaxBucketSessionCounts[RESTRICTED_INDEX] = newRestrictedMaxSessionCount; + mShouldReevaluateConstraints = true; + } + break; + case KEY_TIMING_SESSION_COALESCING_DURATION_MS: + TIMING_SESSION_COALESCING_DURATION_MS = + properties.getLong(key, DEFAULT_TIMING_SESSION_COALESCING_DURATION_MS); + long newSessionCoalescingDurationMs = Math.min(15 * MINUTE_IN_MILLIS, + Math.max(0, TIMING_SESSION_COALESCING_DURATION_MS)); + if (mTimingSessionCoalescingDurationMs != newSessionCoalescingDurationMs) { + mTimingSessionCoalescingDurationMs = newSessionCoalescingDurationMs; + mShouldReevaluateConstraints = true; + } + break; + case KEY_MIN_QUOTA_CHECK_DELAY_MS: + MIN_QUOTA_CHECK_DELAY_MS = + properties.getLong(key, DEFAULT_MIN_QUOTA_CHECK_DELAY_MS); + // We don't need to re-evaluate execution stats or constraint status for this. + // Limit the delay to the range [0, 15] minutes. + mInQuotaAlarmListener.setMinQuotaCheckDelayMs( + Math.min(15 * MINUTE_IN_MILLIS, Math.max(0, MIN_QUOTA_CHECK_DELAY_MS))); + break; + } } - @VisibleForTesting - void updateConstants() { - synchronized (mLock) { - boolean changed = false; - - long newMaxExecutionTimeMs = Math.max(MIN_MAX_EXECUTION_TIME_MS, - Math.min(MAX_PERIOD_MS, MAX_EXECUTION_TIME_MS)); - if (mMaxExecutionTimeMs != newMaxExecutionTimeMs) { - mMaxExecutionTimeMs = newMaxExecutionTimeMs; - mMaxExecutionTimeIntoQuotaMs = mMaxExecutionTimeMs - mQuotaBufferMs; - changed = true; - } - long newAllowedTimeMs = Math.min(mMaxExecutionTimeMs, - Math.max(MINUTE_IN_MILLIS, ALLOWED_TIME_PER_PERIOD_MS)); - if (mAllowedTimePerPeriodMs != newAllowedTimeMs) { - mAllowedTimePerPeriodMs = newAllowedTimeMs; - mAllowedTimeIntoQuotaMs = mAllowedTimePerPeriodMs - mQuotaBufferMs; - changed = true; - } - // Make sure quota buffer is non-negative, not greater than allowed time per period, - // and no more than 5 minutes. - long newQuotaBufferMs = Math.max(0, Math.min(mAllowedTimePerPeriodMs, - Math.min(5 * MINUTE_IN_MILLIS, IN_QUOTA_BUFFER_MS))); - if (mQuotaBufferMs != newQuotaBufferMs) { - mQuotaBufferMs = newQuotaBufferMs; - mAllowedTimeIntoQuotaMs = mAllowedTimePerPeriodMs - mQuotaBufferMs; - mMaxExecutionTimeIntoQuotaMs = mMaxExecutionTimeMs - mQuotaBufferMs; - changed = true; - } - long newActivePeriodMs = Math.max(mAllowedTimePerPeriodMs, - Math.min(MAX_PERIOD_MS, WINDOW_SIZE_ACTIVE_MS)); - if (mBucketPeriodsMs[ACTIVE_INDEX] != newActivePeriodMs) { - mBucketPeriodsMs[ACTIVE_INDEX] = newActivePeriodMs; - changed = true; - } - long newWorkingPeriodMs = Math.max(mAllowedTimePerPeriodMs, - Math.min(MAX_PERIOD_MS, WINDOW_SIZE_WORKING_MS)); - if (mBucketPeriodsMs[WORKING_INDEX] != newWorkingPeriodMs) { - mBucketPeriodsMs[WORKING_INDEX] = newWorkingPeriodMs; - changed = true; - } - long newFrequentPeriodMs = Math.max(mAllowedTimePerPeriodMs, - Math.min(MAX_PERIOD_MS, WINDOW_SIZE_FREQUENT_MS)); - if (mBucketPeriodsMs[FREQUENT_INDEX] != newFrequentPeriodMs) { - mBucketPeriodsMs[FREQUENT_INDEX] = newFrequentPeriodMs; - changed = true; - } - long newRarePeriodMs = Math.max(mAllowedTimePerPeriodMs, - Math.min(MAX_PERIOD_MS, WINDOW_SIZE_RARE_MS)); - if (mBucketPeriodsMs[RARE_INDEX] != newRarePeriodMs) { - mBucketPeriodsMs[RARE_INDEX] = newRarePeriodMs; - changed = true; - } - // Fit in the range [allowed time (10 mins), 1 week]. - long newRestrictedPeriodMs = Math.max(mAllowedTimePerPeriodMs, - Math.min(7 * 24 * 60 * MINUTE_IN_MILLIS, WINDOW_SIZE_RESTRICTED_MS)); - if (mBucketPeriodsMs[RESTRICTED_INDEX] != newRestrictedPeriodMs) { - mBucketPeriodsMs[RESTRICTED_INDEX] = newRestrictedPeriodMs; - changed = true; - } - long newRateLimitingWindowMs = Math.min(MAX_PERIOD_MS, - Math.max(MIN_RATE_LIMITING_WINDOW_MS, RATE_LIMITING_WINDOW_MS)); - if (mRateLimitingWindowMs != newRateLimitingWindowMs) { - mRateLimitingWindowMs = newRateLimitingWindowMs; - changed = true; - } - int newMaxJobCountPerRateLimitingWindow = Math.max( - MIN_MAX_JOB_COUNT_PER_RATE_LIMITING_WINDOW, - MAX_JOB_COUNT_PER_RATE_LIMITING_WINDOW); - if (mMaxJobCountPerRateLimitingWindow != newMaxJobCountPerRateLimitingWindow) { - mMaxJobCountPerRateLimitingWindow = newMaxJobCountPerRateLimitingWindow; - changed = true; - } - int newActiveMaxJobCount = Math.max(MIN_BUCKET_JOB_COUNT, MAX_JOB_COUNT_ACTIVE); - if (mMaxBucketJobCounts[ACTIVE_INDEX] != newActiveMaxJobCount) { - mMaxBucketJobCounts[ACTIVE_INDEX] = newActiveMaxJobCount; - changed = true; - } - int newWorkingMaxJobCount = Math.max(MIN_BUCKET_JOB_COUNT, MAX_JOB_COUNT_WORKING); - if (mMaxBucketJobCounts[WORKING_INDEX] != newWorkingMaxJobCount) { - mMaxBucketJobCounts[WORKING_INDEX] = newWorkingMaxJobCount; - changed = true; - } - int newFrequentMaxJobCount = Math.max(MIN_BUCKET_JOB_COUNT, MAX_JOB_COUNT_FREQUENT); - if (mMaxBucketJobCounts[FREQUENT_INDEX] != newFrequentMaxJobCount) { - mMaxBucketJobCounts[FREQUENT_INDEX] = newFrequentMaxJobCount; - changed = true; - } - int newRareMaxJobCount = Math.max(MIN_BUCKET_JOB_COUNT, MAX_JOB_COUNT_RARE); - if (mMaxBucketJobCounts[RARE_INDEX] != newRareMaxJobCount) { - mMaxBucketJobCounts[RARE_INDEX] = newRareMaxJobCount; - changed = true; - } - int newRestrictedMaxJobCount = Math.max(MIN_BUCKET_JOB_COUNT, - MAX_JOB_COUNT_RESTRICTED); - if (mMaxBucketJobCounts[RESTRICTED_INDEX] != newRestrictedMaxJobCount) { - mMaxBucketJobCounts[RESTRICTED_INDEX] = newRestrictedMaxJobCount; - changed = true; - } - int newMaxSessionCountPerRateLimitPeriod = Math.max( - MIN_MAX_SESSION_COUNT_PER_RATE_LIMITING_WINDOW, - MAX_SESSION_COUNT_PER_RATE_LIMITING_WINDOW); - if (mMaxSessionCountPerRateLimitingWindow != newMaxSessionCountPerRateLimitPeriod) { - mMaxSessionCountPerRateLimitingWindow = newMaxSessionCountPerRateLimitPeriod; - changed = true; - } - int newActiveMaxSessionCount = - Math.max(MIN_BUCKET_SESSION_COUNT, MAX_SESSION_COUNT_ACTIVE); - if (mMaxBucketSessionCounts[ACTIVE_INDEX] != newActiveMaxSessionCount) { - mMaxBucketSessionCounts[ACTIVE_INDEX] = newActiveMaxSessionCount; - changed = true; - } - int newWorkingMaxSessionCount = - Math.max(MIN_BUCKET_SESSION_COUNT, MAX_SESSION_COUNT_WORKING); - if (mMaxBucketSessionCounts[WORKING_INDEX] != newWorkingMaxSessionCount) { - mMaxBucketSessionCounts[WORKING_INDEX] = newWorkingMaxSessionCount; - changed = true; - } - int newFrequentMaxSessionCount = - Math.max(MIN_BUCKET_SESSION_COUNT, MAX_SESSION_COUNT_FREQUENT); - if (mMaxBucketSessionCounts[FREQUENT_INDEX] != newFrequentMaxSessionCount) { - mMaxBucketSessionCounts[FREQUENT_INDEX] = newFrequentMaxSessionCount; - changed = true; - } - int newRareMaxSessionCount = - Math.max(MIN_BUCKET_SESSION_COUNT, MAX_SESSION_COUNT_RARE); - if (mMaxBucketSessionCounts[RARE_INDEX] != newRareMaxSessionCount) { - mMaxBucketSessionCounts[RARE_INDEX] = newRareMaxSessionCount; - changed = true; - } - int newRestrictedMaxSessionCount = Math.max(0, MAX_SESSION_COUNT_RESTRICTED); - if (mMaxBucketSessionCounts[RESTRICTED_INDEX] != newRestrictedMaxSessionCount) { - mMaxBucketSessionCounts[RESTRICTED_INDEX] = newRestrictedMaxSessionCount; - changed = true; - } - long newSessionCoalescingDurationMs = Math.min(15 * MINUTE_IN_MILLIS, - Math.max(0, TIMING_SESSION_COALESCING_DURATION_MS)); - if (mTimingSessionCoalescingDurationMs != newSessionCoalescingDurationMs) { - mTimingSessionCoalescingDurationMs = newSessionCoalescingDurationMs; - changed = true; - } - // Don't set changed to true for this one since we don't need to re-evaluate - // execution stats or constraint status. Limit the delay to the range [0, 15] - // minutes. - mInQuotaAlarmListener.setMinQuotaCheckDelayMs( - Math.min(15 * MINUTE_IN_MILLIS, Math.max(0, MIN_QUOTA_CHECK_DELAY_MS))); + private void updateExecutionPeriodConstantsLocked() { + if (mExecutionPeriodConstantsUpdated) { + return; + } + mExecutionPeriodConstantsUpdated = true; + + // Query the values as an atomic set. + final DeviceConfig.Properties properties = DeviceConfig.getProperties( + DeviceConfig.NAMESPACE_JOB_SCHEDULER, + KEY_ALLOWED_TIME_PER_PERIOD_MS, KEY_IN_QUOTA_BUFFER_MS, + KEY_MAX_EXECUTION_TIME_MS, KEY_WINDOW_SIZE_ACTIVE_MS, + KEY_WINDOW_SIZE_WORKING_MS, + KEY_WINDOW_SIZE_FREQUENT_MS, KEY_WINDOW_SIZE_RARE_MS, + KEY_WINDOW_SIZE_RESTRICTED_MS); + ALLOWED_TIME_PER_PERIOD_MS = + properties.getLong(KEY_ALLOWED_TIME_PER_PERIOD_MS, + DEFAULT_ALLOWED_TIME_PER_PERIOD_MS); + IN_QUOTA_BUFFER_MS = properties.getLong(KEY_IN_QUOTA_BUFFER_MS, + DEFAULT_IN_QUOTA_BUFFER_MS); + MAX_EXECUTION_TIME_MS = properties.getLong(KEY_MAX_EXECUTION_TIME_MS, + DEFAULT_MAX_EXECUTION_TIME_MS); + WINDOW_SIZE_ACTIVE_MS = properties.getLong(KEY_WINDOW_SIZE_ACTIVE_MS, + DEFAULT_WINDOW_SIZE_ACTIVE_MS); + WINDOW_SIZE_WORKING_MS = + properties.getLong(KEY_WINDOW_SIZE_WORKING_MS, DEFAULT_WINDOW_SIZE_WORKING_MS); + WINDOW_SIZE_FREQUENT_MS = + properties.getLong(KEY_WINDOW_SIZE_FREQUENT_MS, + DEFAULT_WINDOW_SIZE_FREQUENT_MS); + WINDOW_SIZE_RARE_MS = properties.getLong(KEY_WINDOW_SIZE_RARE_MS, + DEFAULT_WINDOW_SIZE_RARE_MS); + WINDOW_SIZE_RESTRICTED_MS = + properties.getLong(KEY_WINDOW_SIZE_RESTRICTED_MS, + DEFAULT_WINDOW_SIZE_RESTRICTED_MS); + + long newMaxExecutionTimeMs = Math.max(MIN_MAX_EXECUTION_TIME_MS, + Math.min(MAX_PERIOD_MS, MAX_EXECUTION_TIME_MS)); + if (mMaxExecutionTimeMs != newMaxExecutionTimeMs) { + mMaxExecutionTimeMs = newMaxExecutionTimeMs; + mMaxExecutionTimeIntoQuotaMs = mMaxExecutionTimeMs - mQuotaBufferMs; + mShouldReevaluateConstraints = true; + } + long newAllowedTimeMs = Math.min(mMaxExecutionTimeMs, + Math.max(MINUTE_IN_MILLIS, ALLOWED_TIME_PER_PERIOD_MS)); + if (mAllowedTimePerPeriodMs != newAllowedTimeMs) { + mAllowedTimePerPeriodMs = newAllowedTimeMs; + mAllowedTimeIntoQuotaMs = mAllowedTimePerPeriodMs - mQuotaBufferMs; + mShouldReevaluateConstraints = true; + } + // Make sure quota buffer is non-negative, not greater than allowed time per period, + // and no more than 5 minutes. + long newQuotaBufferMs = Math.max(0, Math.min(mAllowedTimePerPeriodMs, + Math.min(5 * MINUTE_IN_MILLIS, IN_QUOTA_BUFFER_MS))); + if (mQuotaBufferMs != newQuotaBufferMs) { + mQuotaBufferMs = newQuotaBufferMs; + mAllowedTimeIntoQuotaMs = mAllowedTimePerPeriodMs - mQuotaBufferMs; + mMaxExecutionTimeIntoQuotaMs = mMaxExecutionTimeMs - mQuotaBufferMs; + mShouldReevaluateConstraints = true; + } + long newActivePeriodMs = Math.max(mAllowedTimePerPeriodMs, + Math.min(MAX_PERIOD_MS, WINDOW_SIZE_ACTIVE_MS)); + if (mBucketPeriodsMs[ACTIVE_INDEX] != newActivePeriodMs) { + mBucketPeriodsMs[ACTIVE_INDEX] = newActivePeriodMs; + mShouldReevaluateConstraints = true; + } + long newWorkingPeriodMs = Math.max(mAllowedTimePerPeriodMs, + Math.min(MAX_PERIOD_MS, WINDOW_SIZE_WORKING_MS)); + if (mBucketPeriodsMs[WORKING_INDEX] != newWorkingPeriodMs) { + mBucketPeriodsMs[WORKING_INDEX] = newWorkingPeriodMs; + mShouldReevaluateConstraints = true; + } + long newFrequentPeriodMs = Math.max(mAllowedTimePerPeriodMs, + Math.min(MAX_PERIOD_MS, WINDOW_SIZE_FREQUENT_MS)); + if (mBucketPeriodsMs[FREQUENT_INDEX] != newFrequentPeriodMs) { + mBucketPeriodsMs[FREQUENT_INDEX] = newFrequentPeriodMs; + mShouldReevaluateConstraints = true; + } + long newRarePeriodMs = Math.max(mAllowedTimePerPeriodMs, + Math.min(MAX_PERIOD_MS, WINDOW_SIZE_RARE_MS)); + if (mBucketPeriodsMs[RARE_INDEX] != newRarePeriodMs) { + mBucketPeriodsMs[RARE_INDEX] = newRarePeriodMs; + mShouldReevaluateConstraints = true; + } + // Fit in the range [allowed time (10 mins), 1 week]. + long newRestrictedPeriodMs = Math.max(mAllowedTimePerPeriodMs, + Math.min(7 * 24 * 60 * MINUTE_IN_MILLIS, WINDOW_SIZE_RESTRICTED_MS)); + if (mBucketPeriodsMs[RESTRICTED_INDEX] != newRestrictedPeriodMs) { + mBucketPeriodsMs[RESTRICTED_INDEX] = newRestrictedPeriodMs; + mShouldReevaluateConstraints = true; + } + } + + private void updateRateLimitingConstantsLocked() { + if (mRateLimitingConstantsUpdated) { + return; + } + mRateLimitingConstantsUpdated = true; - if (changed) { - // Update job bookkeeping out of band. - JobSchedulerBackgroundThread.getHandler().post(() -> { - synchronized (mLock) { - invalidateAllExecutionStatsLocked(); - maybeUpdateAllConstraintsLocked(); - } - }); - } + // Query the values as an atomic set. + final DeviceConfig.Properties properties = DeviceConfig.getProperties( + DeviceConfig.NAMESPACE_JOB_SCHEDULER, + KEY_RATE_LIMITING_WINDOW_MS, KEY_MAX_JOB_COUNT_PER_RATE_LIMITING_WINDOW, + KEY_MAX_SESSION_COUNT_PER_RATE_LIMITING_WINDOW); + + RATE_LIMITING_WINDOW_MS = + properties.getLong(KEY_RATE_LIMITING_WINDOW_MS, + DEFAULT_RATE_LIMITING_WINDOW_MS); + + MAX_JOB_COUNT_PER_RATE_LIMITING_WINDOW = + properties.getInt(KEY_MAX_JOB_COUNT_PER_RATE_LIMITING_WINDOW, + DEFAULT_MAX_JOB_COUNT_PER_RATE_LIMITING_WINDOW); + + MAX_SESSION_COUNT_PER_RATE_LIMITING_WINDOW = + properties.getInt(KEY_MAX_SESSION_COUNT_PER_RATE_LIMITING_WINDOW, + DEFAULT_MAX_SESSION_COUNT_PER_RATE_LIMITING_WINDOW); + + long newRateLimitingWindowMs = Math.min(MAX_PERIOD_MS, + Math.max(MIN_RATE_LIMITING_WINDOW_MS, RATE_LIMITING_WINDOW_MS)); + if (mRateLimitingWindowMs != newRateLimitingWindowMs) { + mRateLimitingWindowMs = newRateLimitingWindowMs; + mShouldReevaluateConstraints = true; + } + int newMaxJobCountPerRateLimitingWindow = Math.max( + MIN_MAX_JOB_COUNT_PER_RATE_LIMITING_WINDOW, + MAX_JOB_COUNT_PER_RATE_LIMITING_WINDOW); + if (mMaxJobCountPerRateLimitingWindow != newMaxJobCountPerRateLimitingWindow) { + mMaxJobCountPerRateLimitingWindow = newMaxJobCountPerRateLimitingWindow; + mShouldReevaluateConstraints = true; + } + int newMaxSessionCountPerRateLimitPeriod = Math.max( + MIN_MAX_SESSION_COUNT_PER_RATE_LIMITING_WINDOW, + MAX_SESSION_COUNT_PER_RATE_LIMITING_WINDOW); + if (mMaxSessionCountPerRateLimitingWindow != newMaxSessionCountPerRateLimitPeriod) { + mMaxSessionCountPerRateLimitingWindow = newMaxSessionCountPerRateLimitPeriod; + mShouldReevaluateConstraints = true; } } @@ -2634,6 +2731,11 @@ public final class QuotaController extends StateController { } @VisibleForTesting + long getMinQuotaCheckDelayMs() { + return mInQuotaAlarmListener.mMinQuotaCheckDelayMs; + } + + @VisibleForTesting long getRateLimitingWindowMs() { return mRateLimitingWindowMs; } 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 71c759931f57..56b30907b2a1 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 @@ -18,7 +18,9 @@ package com.android.server.job.controllers; import static com.android.server.job.JobSchedulerService.DEBUG; +import android.annotation.NonNull; import android.content.Context; +import android.provider.DeviceConfig; import android.util.IndentingPrintWriter; import android.util.Slog; import android.util.proto.ProtoOutputStream; @@ -84,6 +86,13 @@ public abstract class StateController { public void rescheduleForFailureLocked(JobStatus newJob, JobStatus failureToReschedule) { } + /** Notice that updated configuration constants are about to be read. */ + public void prepareForUpdatedConstantsLocked() {} + + /** Process the specified constant and update internal constants if relevant. */ + public void processConstantLocked(@NonNull DeviceConfig.Properties properties, + @NonNull String key) {} + /** * Called when the JobScheduler.Constants are updated. */ diff --git a/api/current.txt b/api/current.txt index b35940449f9e..26d77ef4318e 100644 --- a/api/current.txt +++ b/api/current.txt @@ -28810,6 +28810,7 @@ package android.media.session { public final class MediaController { ctor public MediaController(@NonNull android.content.Context, @NonNull android.media.session.MediaSession.Token); method public void adjustVolume(int, int); + method @Deprecated public boolean controlsSameSession(@Nullable android.media.session.MediaController); method public boolean dispatchMediaButtonEvent(@NonNull android.view.KeyEvent); method @Nullable public android.os.Bundle getExtras(); method public long getFlags(); @@ -46509,6 +46510,7 @@ package android.telecom { method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVoiceMailNumber(android.telecom.PhoneAccountHandle); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handleMmi(String); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handleMmi(String, android.telecom.PhoneAccountHandle); + method public boolean hasCompanionInCallServiceAccess(); method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isInCall(); method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isInManagedCall(); method public boolean isIncomingCallPermitted(android.telecom.PhoneAccountHandle); @@ -53778,7 +53780,6 @@ package android.view { } public interface OnReceiveContentCallback<T extends android.view.View> { - method @NonNull public java.util.Set<java.lang.String> getSupportedMimeTypes(@NonNull T); method public boolean onReceiveContent(@NonNull T, @NonNull android.view.OnReceiveContentCallback.Payload); } @@ -54356,7 +54357,7 @@ package android.view { method @IdRes public int getNextFocusRightId(); method @IdRes public int getNextFocusUpId(); method public android.view.View.OnFocusChangeListener getOnFocusChangeListener(); - method @Nullable public android.view.OnReceiveContentCallback<? extends android.view.View> getOnReceiveContentCallback(); + method @Nullable public String[] getOnReceiveContentMimeTypes(); method @ColorInt public int getOutlineAmbientShadowColor(); method public android.view.ViewOutlineProvider getOutlineProvider(); method @ColorInt public int getOutlineSpotShadowColor(); @@ -54551,6 +54552,7 @@ package android.view { method public void onProvideContentCaptureStructure(@NonNull android.view.ViewStructure, int); method public void onProvideStructure(android.view.ViewStructure); method public void onProvideVirtualStructure(android.view.ViewStructure); + method public boolean onReceiveContent(@NonNull android.view.OnReceiveContentCallback.Payload); method public android.view.PointerIcon onResolvePointerIcon(android.view.MotionEvent, int); method @CallSuper protected void onRestoreInstanceState(android.os.Parcelable); method public void onRtlPropertiesChanged(int); @@ -54708,7 +54710,7 @@ package android.view { method public void setOnHoverListener(android.view.View.OnHoverListener); method public void setOnKeyListener(android.view.View.OnKeyListener); method public void setOnLongClickListener(@Nullable android.view.View.OnLongClickListener); - method public void setOnReceiveContentCallback(@Nullable android.view.OnReceiveContentCallback<? extends android.view.View>); + method public void setOnReceiveContentCallback(@Nullable String[], @Nullable android.view.OnReceiveContentCallback); method public void setOnScrollChangeListener(android.view.View.OnScrollChangeListener); method @Deprecated public void setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener); method public void setOnTouchListener(android.view.View.OnTouchListener); @@ -61538,7 +61540,6 @@ package android.widget { method public int getMinWidth(); method public final android.text.method.MovementMethod getMovementMethod(); method public int getOffsetForPosition(float, float); - method @Nullable public android.view.OnReceiveContentCallback<android.widget.TextView> getOnReceiveContentCallback(); method public android.text.TextPaint getPaint(); method public int getPaintFlags(); method public String getPrivateImeOptions(); @@ -61727,7 +61728,6 @@ package android.widget { public class TextViewOnReceiveContentCallback implements android.view.OnReceiveContentCallback<android.widget.TextView> { ctor public TextViewOnReceiveContentCallback(); - method @NonNull public java.util.Set<java.lang.String> getSupportedMimeTypes(@NonNull android.widget.TextView); method public boolean onReceiveContent(@NonNull android.widget.TextView, @NonNull android.view.OnReceiveContentCallback.Payload); } diff --git a/api/system-current.txt b/api/system-current.txt index f30f756ae3f6..be20d5e8d5c8 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -109,7 +109,8 @@ package android { field public static final String LOCK_DEVICE = "android.permission.LOCK_DEVICE"; field public static final String LOOP_RADIO = "android.permission.LOOP_RADIO"; field public static final String MANAGE_ACCESSIBILITY = "android.permission.MANAGE_ACCESSIBILITY"; - field public static final String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS"; + field @Deprecated public static final String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS"; + field public static final String MANAGE_ACTIVITY_TASKS = "android.permission.MANAGE_ACTIVITY_TASKS"; field public static final String MANAGE_APP_OPS_RESTRICTIONS = "android.permission.MANAGE_APP_OPS_RESTRICTIONS"; field public static final String MANAGE_APP_PREDICTIONS = "android.permission.MANAGE_APP_PREDICTIONS"; field public static final String MANAGE_APP_TOKENS = "android.permission.MANAGE_APP_TOKENS"; @@ -918,6 +919,7 @@ package android.app.admin { field public static final int PROVISIONING_TRIGGER_QR_CODE = 2; // 0x2 field public static final int PROVISIONING_TRIGGER_UNSPECIFIED = 0; // 0x0 field public static final int STATE_USER_PROFILE_COMPLETE = 4; // 0x4 + field public static final int STATE_USER_PROFILE_FINALIZED = 5; // 0x5 field public static final int STATE_USER_SETUP_COMPLETE = 2; // 0x2 field public static final int STATE_USER_SETUP_FINALIZED = 3; // 0x3 field public static final int STATE_USER_SETUP_INCOMPLETE = 1; // 0x1 @@ -2200,6 +2202,7 @@ package android.content.pm { method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.SUSPEND_APPS) public String[] setPackagesSuspended(@Nullable String[], boolean, @Nullable android.os.PersistableBundle, @Nullable android.os.PersistableBundle, @Nullable String); method @Nullable @RequiresPermission(android.Manifest.permission.SUSPEND_APPS) public String[] setPackagesSuspended(@Nullable String[], boolean, @Nullable android.os.PersistableBundle, @Nullable android.os.PersistableBundle, @Nullable android.content.pm.SuspendDialogInfo); method @RequiresPermission(value=android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE, conditional=true) public void setSyntheticAppDetailsActivityEnabled(@NonNull String, boolean); + method public void setSystemAppState(@NonNull String, int); method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public abstract void setUpdateAvailable(@NonNull String, boolean); method @RequiresPermission(android.Manifest.permission.SET_PREFERRED_APPLICATIONS) public abstract boolean updateIntentVerificationStatusAsUser(@NonNull String, int, int); method @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS}) public abstract void updatePermissionFlags(@NonNull String, @NonNull String, @android.content.pm.PackageManager.PermissionFlags int, @android.content.pm.PackageManager.PermissionFlags int, @NonNull android.os.UserHandle); @@ -2278,11 +2281,16 @@ package android.content.pm { field @Deprecated public static final int MASK_PERMISSION_FLAGS = 255; // 0xff field public static final int MATCH_ANY_USER = 4194304; // 0x400000 field public static final int MATCH_FACTORY_ONLY = 2097152; // 0x200000 + field public static final int MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS = 536870912; // 0x20000000 field public static final int MATCH_INSTANT = 8388608; // 0x800000 field public static final int MODULE_APEX_NAME = 1; // 0x1 field public static final int RESTRICTION_HIDE_FROM_SUGGESTIONS = 1; // 0x1 field public static final int RESTRICTION_HIDE_NOTIFICATIONS = 2; // 0x2 field public static final int RESTRICTION_NONE = 0; // 0x0 + field public static final int SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN = 0; // 0x0 + field public static final int SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_VISIBLE = 1; // 0x1 + field public static final int SYSTEM_APP_STATE_INSTALLED = 2; // 0x2 + field public static final int SYSTEM_APP_STATE_UNINSTALLED = 3; // 0x3 } public abstract static class PackageManager.DexModuleRegisterCallback { @@ -6695,6 +6703,7 @@ package android.net { method @NonNull public int[] getTransportTypes(); method public boolean satisfiedByNetworkCapabilities(@Nullable android.net.NetworkCapabilities); field public static final int NET_CAPABILITY_OEM_PAID = 22; // 0x16 + field public static final int NET_CAPABILITY_OEM_PRIVATE = 26; // 0x1a field public static final int NET_CAPABILITY_PARTIAL_CONNECTIVITY = 24; // 0x18 } @@ -7491,8 +7500,10 @@ package android.net.wifi { public final class SoftApConfiguration implements android.os.Parcelable { method @NonNull public java.util.List<android.net.MacAddress> getAllowedClientList(); method public int getBand(); + method @NonNull public int[] getBands(); method @NonNull public java.util.List<android.net.MacAddress> getBlockedClientList(); method public int getChannel(); + method @NonNull public android.util.SparseIntArray getChannels(); method public int getMacRandomizationSetting(); method public int getMaxNumberOfClients(); method public long getShutdownTimeoutMillis(); @@ -7514,9 +7525,11 @@ package android.net.wifi { method @NonNull public android.net.wifi.SoftApConfiguration.Builder setAllowedClientList(@NonNull java.util.List<android.net.MacAddress>); method @NonNull public android.net.wifi.SoftApConfiguration.Builder setAutoShutdownEnabled(boolean); method @NonNull public android.net.wifi.SoftApConfiguration.Builder setBand(int); + method @NonNull public android.net.wifi.SoftApConfiguration.Builder setBands(@NonNull int[]); method @NonNull public android.net.wifi.SoftApConfiguration.Builder setBlockedClientList(@NonNull java.util.List<android.net.MacAddress>); method @NonNull public android.net.wifi.SoftApConfiguration.Builder setBssid(@Nullable android.net.MacAddress); method @NonNull public android.net.wifi.SoftApConfiguration.Builder setChannel(int, int); + method @NonNull public android.net.wifi.SoftApConfiguration.Builder setChannels(@NonNull android.util.SparseIntArray); method @NonNull public android.net.wifi.SoftApConfiguration.Builder setClientControlByUserEnabled(boolean); method @NonNull public android.net.wifi.SoftApConfiguration.Builder setHiddenSsid(boolean); method @NonNull public android.net.wifi.SoftApConfiguration.Builder setMacRandomizationSetting(int); @@ -10025,6 +10038,7 @@ package android.service.autofill { public static final class Dataset.Builder { ctor public Dataset.Builder(@NonNull android.service.autofill.InlinePresentation); + method @NonNull public android.service.autofill.Dataset.Builder setContent(@NonNull android.view.autofill.AutofillId, @Nullable android.content.ClipData); method @NonNull public android.service.autofill.Dataset.Builder setFieldInlinePresentation(@NonNull android.view.autofill.AutofillId, @Nullable android.view.autofill.AutofillValue, @Nullable java.util.regex.Pattern, @NonNull android.service.autofill.InlinePresentation); } diff --git a/api/test-current.txt b/api/test-current.txt index edf860665fb6..4d844abac138 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -12,7 +12,8 @@ package android { field public static final String CONFIGURE_DISPLAY_BRIGHTNESS = "android.permission.CONFIGURE_DISPLAY_BRIGHTNESS"; field public static final String CONTROL_DEVICE_LIGHTS = "android.permission.CONTROL_DEVICE_LIGHTS"; field public static final String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES"; - field public static final String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS"; + field @Deprecated public static final String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS"; + field public static final String MANAGE_ACTIVITY_TASKS = "android.permission.MANAGE_ACTIVITY_TASKS"; field public static final String MANAGE_CRATES = "android.permission.MANAGE_CRATES"; field public static final String MANAGE_NOTIFICATION_LISTENERS = "android.permission.MANAGE_NOTIFICATION_LISTENERS"; field public static final String MANAGE_ROLLBACKS = "android.permission.MANAGE_ROLLBACKS"; @@ -84,7 +85,7 @@ package android.app { method @RequiresPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER) public void addHomeVisibilityListener(@NonNull java.util.concurrent.Executor, @NonNull android.app.HomeVisibilityListener); method public void alwaysShowUnsupportedCompileSdkWarning(android.content.ComponentName); method public long getTotalRam(); - method @RequiresPermission(android.Manifest.permission.INJECT_EVENTS) public void holdLock(int); + method public void holdLock(android.os.IBinder, int); method public static boolean isHighEndGfx(); method @RequiresPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER) public void removeHomeVisibilityListener(@NonNull android.app.HomeVisibilityListener); method @RequiresPermission(android.Manifest.permission.RESET_APP_ERRORS) public void resetAppErrors(); @@ -128,19 +129,19 @@ package android.app { } public class ActivityTaskManager { - method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void clearLaunchParamsForPackages(java.util.List<java.lang.String>); + method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void clearLaunchParamsForPackages(java.util.List<java.lang.String>); method public static boolean currentUiModeSupportsErrorDialogs(@NonNull android.content.Context); - method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void moveTaskToRootTask(int, int, boolean); - method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public boolean moveTopActivityToPinnedRootTask(int, @NonNull android.graphics.Rect); - method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void removeRootTasksInWindowingModes(@NonNull int[]); - method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void removeRootTasksWithActivityTypes(@NonNull int[]); - method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void requestPictureInPictureMode(@NonNull android.os.IBinder); - method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void resizePrimarySplitScreen(@NonNull android.graphics.Rect, @NonNull android.graphics.Rect); - method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void resizeTask(int, android.graphics.Rect); - method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public boolean setTaskWindowingMode(int, int, boolean) throws java.lang.SecurityException; - method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public boolean setTaskWindowingModeSplitScreenPrimary(int, int, boolean, boolean, android.graphics.Rect, boolean) throws java.lang.SecurityException; - method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void startSystemLockTaskMode(int); - method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void stopSystemLockTaskMode(); + method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void moveTaskToRootTask(int, int, boolean); + method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public boolean moveTopActivityToPinnedRootTask(int, @NonNull android.graphics.Rect); + method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void removeRootTasksInWindowingModes(@NonNull int[]); + method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void removeRootTasksWithActivityTypes(@NonNull int[]); + method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void requestPictureInPictureMode(@NonNull android.os.IBinder); + method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void resizePrimarySplitScreen(@NonNull android.graphics.Rect, @NonNull android.graphics.Rect); + method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void resizeTask(int, android.graphics.Rect); + method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public boolean setTaskWindowingMode(int, int, boolean) throws java.lang.SecurityException; + method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public boolean setTaskWindowingModeSplitScreenPrimary(int, int, boolean, boolean, android.graphics.Rect, boolean) throws java.lang.SecurityException; + method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void startSystemLockTaskMode(int); + method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void stopSystemLockTaskMode(); method public static boolean supportsMultiWindow(android.content.Context); method public static boolean supportsSplitScreenMultiWindow(android.content.Context); field public static final int DEFAULT_MINIMAL_SPLIT_SCREEN_DISPLAY_SIZE_DP = 440; // 0x1b8 @@ -534,6 +535,7 @@ package android.content.pm { public abstract class PackageManager { method @Nullable public String getContentCaptureServicePackageName(); method @Nullable public String getDefaultTextClassifierPackageName(); + method @RequiresPermission(android.Manifest.permission.INJECT_EVENTS) public android.os.IBinder getHoldLockToken(); method public abstract int getInstallReason(@NonNull String, @NonNull android.os.UserHandle); method @NonNull public abstract java.util.List<android.content.pm.ApplicationInfo> getInstalledApplicationsAsUser(int, int); method @Nullable public abstract String[] getNamesForUids(int[]); @@ -542,7 +544,7 @@ package android.content.pm { method @NonNull public abstract String getSharedSystemSharedLibraryPackageName(); method @Nullable public String getSystemTextClassifierPackageName(); method @Nullable public String getWellbeingPackageName(); - method @RequiresPermission(android.Manifest.permission.INJECT_EVENTS) public void holdLock(int); + method public void holdLock(android.os.IBinder, int); field public static final String FEATURE_ADOPTABLE_STORAGE = "android.software.adoptable_storage"; field public static final String FEATURE_FILE_BASED_ENCRYPTION = "android.software.file_based_encryption"; field public static final int FLAG_PERMISSION_REVOKE_WHEN_REQUESTED = 128; // 0x80 @@ -1554,6 +1556,19 @@ package android.service.autofill { method @Nullable public android.util.SparseArray<android.service.autofill.InternalOnClickAction> getActions(); } + public final class Dataset implements android.os.Parcelable { + method @Nullable public android.content.IntentSender getAuthentication(); + method @Nullable public android.content.ClipData getFieldContent(); + method @Nullable public java.util.ArrayList<android.view.autofill.AutofillId> getFieldIds(); + method @Nullable public java.util.ArrayList<android.view.autofill.AutofillValue> getFieldValues(); + method @Nullable public String getId(); + method public boolean isEmpty(); + } + + public static final class Dataset.Builder { + method @NonNull public android.service.autofill.Dataset.Builder setContent(@NonNull android.view.autofill.AutofillId, @Nullable android.content.ClipData); + } + public final class DateTransformation extends android.service.autofill.InternalTransformation implements android.os.Parcelable android.service.autofill.Transformation { method public void apply(@NonNull android.service.autofill.ValueFinder, @NonNull android.widget.RemoteViews, int) throws java.lang.Exception; } @@ -2036,7 +2051,7 @@ package android.view { } public interface WindowManager extends android.view.ViewManager { - method @RequiresPermission(android.Manifest.permission.INJECT_EVENTS) public default void holdLock(int); + method public default void holdLock(android.os.IBinder, int); method public default void setShouldShowIme(int, boolean); method public default void setShouldShowSystemDecors(int, boolean); method public default void setShouldShowWithInsecureKeyguard(int, boolean); @@ -2352,7 +2367,7 @@ package android.window { ctor public DisplayAreaOrganizer(); method public void onDisplayAreaAppeared(@NonNull android.window.DisplayAreaInfo, @NonNull android.view.SurfaceControl); method public void onDisplayAreaVanished(@NonNull android.window.DisplayAreaInfo); - method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void registerOrganizer(int); + method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void registerOrganizer(int); field public static final int FEATURE_DEFAULT_TASK_CONTAINER = 1; // 0x1 field public static final int FEATURE_ONE_HANDED = 3; // 0x3 field public static final int FEATURE_ROOT = 0; // 0x0 @@ -2375,19 +2390,19 @@ package android.window { public class TaskOrganizer extends android.window.WindowOrganizer { ctor public TaskOrganizer(); - method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void createRootTask(int, int, @Nullable android.os.IBinder); - method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public boolean deleteRootTask(@NonNull android.window.WindowContainerToken); - method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public java.util.List<android.app.ActivityManager.RunningTaskInfo> getChildTasks(@NonNull android.window.WindowContainerToken, @NonNull int[]); - method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public android.window.WindowContainerToken getImeTarget(int); - method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public java.util.List<android.app.ActivityManager.RunningTaskInfo> getRootTasks(int, @NonNull int[]); + method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void createRootTask(int, int, @Nullable android.os.IBinder); + method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public boolean deleteRootTask(@NonNull android.window.WindowContainerToken); + method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public java.util.List<android.app.ActivityManager.RunningTaskInfo> getChildTasks(@NonNull android.window.WindowContainerToken, @NonNull int[]); + method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public android.window.WindowContainerToken getImeTarget(int); + method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public java.util.List<android.app.ActivityManager.RunningTaskInfo> getRootTasks(int, @NonNull int[]); method @BinderThread public void onBackPressedOnTaskRoot(@NonNull android.app.ActivityManager.RunningTaskInfo); method @BinderThread public void onTaskAppeared(@NonNull android.app.ActivityManager.RunningTaskInfo, @NonNull android.view.SurfaceControl); method @BinderThread public void onTaskInfoChanged(@NonNull android.app.ActivityManager.RunningTaskInfo); method @BinderThread public void onTaskVanished(@NonNull android.app.ActivityManager.RunningTaskInfo); - method @CallSuper @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public java.util.List<android.window.TaskAppearedInfo> registerOrganizer(); - method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void setInterceptBackPressedOnTaskRoot(@NonNull android.window.WindowContainerToken, boolean); - method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void setLaunchRoot(int, @NonNull android.window.WindowContainerToken); - method @CallSuper @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void unregisterOrganizer(); + method @CallSuper @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public java.util.List<android.window.TaskAppearedInfo> registerOrganizer(); + method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void setInterceptBackPressedOnTaskRoot(@NonNull android.window.WindowContainerToken, boolean); + method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void setLaunchRoot(int, @NonNull android.window.WindowContainerToken); + method @CallSuper @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void unregisterOrganizer(); } public final class WindowContainerToken implements android.os.Parcelable { @@ -2422,8 +2437,8 @@ package android.window { public class WindowOrganizer { ctor public WindowOrganizer(); - method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public int applySyncTransaction(@NonNull android.window.WindowContainerTransaction, @NonNull android.window.WindowContainerTransactionCallback); - method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void applyTransaction(@NonNull android.window.WindowContainerTransaction); + method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public int applySyncTransaction(@NonNull android.window.WindowContainerTransaction, @NonNull android.window.WindowContainerTransactionCallback); + method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void applyTransaction(@NonNull android.window.WindowContainerTransaction); } } diff --git a/api/test-lint-baseline.txt b/api/test-lint-baseline.txt index 0440d1a95065..c0b40931f1e6 100644 --- a/api/test-lint-baseline.txt +++ b/api/test-lint-baseline.txt @@ -539,6 +539,8 @@ InternalField: android.telephony.ims.ImsConferenceState#mParticipants: KotlinOperator: android.os.WorkSource#get(int): +KotlinOperator: android.util.SparseArrayMap#get(int, K): + KotlinOperator: android.util.SparseArrayMap#get(int, String): @@ -594,17 +596,17 @@ MinMaxConstant: android.view.autofill.AutofillManager#MAX_TEMP_AUGMENTED_SERVICE MissingGetterMatchingBuilder: android.app.ActivityView.Builder#setAttributeSet(android.util.AttributeSet): - android.app.ActivityView does not declare a `getAttributeSet()` method matching method android.app.ActivityView.Builder.setAttributeSet(android.util.AttributeSet) + MissingGetterMatchingBuilder: android.app.ActivityView.Builder#setDefaultStyle(int): - android.app.ActivityView does not declare a `getDefaultStyle()` method matching method android.app.ActivityView.Builder.setDefaultStyle(int) + MissingGetterMatchingBuilder: android.app.ActivityView.Builder#setDisableSurfaceViewBackgroundLayer(boolean): - android.app.ActivityView does not declare a `isDisableSurfaceViewBackgroundLayer()` method matching method android.app.ActivityView.Builder.setDisableSurfaceViewBackgroundLayer(boolean) + MissingGetterMatchingBuilder: android.app.ActivityView.Builder#setSingleInstance(boolean): - android.app.ActivityView does not declare a `isSingleInstance()` method matching method android.app.ActivityView.Builder.setSingleInstance(boolean) + MissingGetterMatchingBuilder: android.app.ActivityView.Builder#setUsePublicVirtualDisplay(boolean): - android.app.ActivityView does not declare a `isUsePublicVirtualDisplay()` method matching method android.app.ActivityView.Builder.setUsePublicVirtualDisplay(boolean) + MissingGetterMatchingBuilder: android.app.ActivityView.Builder#setUseTrustedDisplay(boolean): - android.app.ActivityView does not declare a `isUseTrustedDisplay()` method matching method android.app.ActivityView.Builder.setUseTrustedDisplay(boolean) + MissingGetterMatchingBuilder: android.app.AppOpsManager.HistoricalOpsRequest.Builder#setAttributionTag(String): MissingGetterMatchingBuilder: android.app.AppOpsManager.HistoricalOpsRequest.Builder#setFlags(int): @@ -751,6 +753,8 @@ MissingNullability: android.app.ActivityManager#forceStopPackage(String) paramet MissingNullability: android.app.ActivityManager#getPackageImportance(String) parameter #0: +MissingNullability: android.app.ActivityManager#holdLock(android.os.IBinder, int) parameter #0: + MissingNullability: android.app.ActivityManager#removeOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener) parameter #0: MissingNullability: android.app.ActivityManager#scheduleApplicationInfoChanged(java.util.List<java.lang.String>, int) parameter #0: @@ -935,8 +939,12 @@ MissingNullability: android.content.pm.LauncherApps#LauncherApps(android.content MissingNullability: android.content.pm.PackageInstaller.SessionParams#setGrantedRuntimePermissions(String[]) parameter #0: +MissingNullability: android.content.pm.PackageManager#getHoldLockToken(): + Missing nullability on method `BINDER` return MissingNullability: android.content.pm.PackageManager#getNamesForUids(int[]) parameter #0: +MissingNullability: android.content.pm.PackageManager#holdLock(android.os.IBinder, int) parameter #0: + MissingNullability: android.content.pm.ShortcutManager#ShortcutManager(android.content.Context) parameter #0: MissingNullability: android.content.res.AssetManager#getOverlayablesToString(String) parameter #0: @@ -2313,6 +2321,8 @@ MissingNullability: android.view.ViewDebug#startRenderingCommandsCapture(android MissingNullability: android.view.ViewDebug#startRenderingCommandsCapture(android.view.View, java.util.concurrent.Executor, java.util.function.Function<android.graphics.Picture,java.lang.Boolean>) parameter #2: +MissingNullability: android.view.WindowManager#holdLock(android.os.IBinder, int) parameter #0: + MissingNullability: android.view.WindowManager.LayoutParams#accessibilityTitle: MissingNullability: android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener#onAccessibilityServicesStateChanged(android.view.accessibility.AccessibilityManager) parameter #0: @@ -2893,6 +2903,10 @@ SetterReturnsThis: android.media.audiopolicy.AudioPolicy.Builder#setAudioPolicyS +StartWithLower: android.content.pm.PackageManager#BINDER(): + Method name must start with lowercase char: BINDER + + StaticFinalBuilder: android.content.integrity.RuleSet.Builder: StaticFinalBuilder: android.hardware.display.BrightnessConfiguration.Builder: diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 084959b5071a..a379847f21da 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -59,6 +59,7 @@ import "frameworks/base/core/proto/android/stats/mediaprovider/mediaprovider_enu import "frameworks/base/core/proto/android/stats/storage/storage_enums.proto"; import "frameworks/base/core/proto/android/stats/style/style_enums.proto"; import "frameworks/base/core/proto/android/stats/sysui/notification_enums.proto"; +import "frameworks/base/core/proto/android/stats/tls/enums.proto"; import "frameworks/base/core/proto/android/telecomm/enums.proto"; import "frameworks/base/core/proto/android/telephony/enums.proto"; import "frameworks/base/core/proto/android/view/enums.proto"; @@ -495,10 +496,12 @@ message Atom { HdmiCecMessageReported hdmi_cec_message_reported = 310 [(module) = "framework"]; AirplaneMode airplane_mode = 311 [(module) = "telephony"]; ModemRestart modem_restart = 312 [(module) = "telephony"]; - CarrierIdMismatchEvent carrier_id_mismatch_event = 313 [(module) = "telephony"]; - CarrierIdMatchingTable carrier_id_table_update = 314 [(module) = "telephony"]; + CarrierIdMismatchReported carrier_id_mismatch_reported = 313 [(module) = "telephony"]; + CarrierIdTableUpdated carrier_id_table_updated = 314 [(module) = "telephony"]; DataStallRecoveryReported data_stall_recovery_reported = 315 [(module) = "telephony"]; MediametricsMediaParserReported mediametrics_mediaparser_reported = 316; + TlsHandshakeReported tls_handshake_reported = 317 [(module) = "conscrypt"]; + TextClassifierApiUsageReported text_classifier_api_usage_reported = 318 [(module) = "textclassifier"]; // StatsdStats tracks platform atoms with ids upto 500. // Update StatsdStats::kMaxPushedAtomId when atom ids here approach that value. @@ -606,7 +609,7 @@ message Atom { 10085 [(module) = "mediaprovider"]; IncomingSms incoming_sms = 10086 [(module) = "telephony"]; OutgoingSms outgoing_sms = 10087 [(module) = "telephony"]; - CarrierIdMatchingTable carrier_id_table_version = 10088 [(module) = "telephony"]; + CarrierIdTableVersion carrier_id_table_version = 10088 [(module) = "telephony"]; DataCallSession data_call_session = 10089 [(module) = "telephony"]; CellularServiceState cellular_service_state = 10090 [(module) = "telephony"]; CellularDataServiceSwitch cellular_data_service_switch = 10091 [(module) = "telephony"]; @@ -10746,7 +10749,7 @@ message OutgoingSms { } /** - * Push information about usage of airplane mode. + * Logs information about usage of airplane mode. * * Logged from: * frameworks/opt/telephony/src/java/com/android/internal/telephony/metrics/AirplaneModeStats.java @@ -10765,7 +10768,7 @@ message AirplaneMode { } /** - * Push information about modem restarts. + * Logs information about modem restarts. * * Logged from: * frameworks/opt/telephony/src/java/com/android/internal/telephony/metrics/ModemRestartStats.java @@ -10783,7 +10786,7 @@ message ModemRestart { } /** - * Push the SIM card details when the carrier ID match is not complete. + * Logs the SIM card details when the carrier ID match is not complete. * * The atom is pushed when a SIM card is initialized and the MCC/MNC is not present in the * carrier ID table, or the SIM card contains a GID1 value that is not present in the carrier ID @@ -10792,7 +10795,7 @@ message ModemRestart { * Logged from: * frameworks/opt/telephony/src/java/com/android/internal/telephony/metrics/CarrierIdMatchStats.java */ -message CarrierIdMismatchEvent { +message CarrierIdMismatchReported { // Matched carrier ID. The value -1 is used if no match is found. optional int32 carrier_id = 1; @@ -10811,14 +10814,23 @@ message CarrierIdMismatchEvent { } /** - * Pulls/pushes the version of the carrier ID matching table. - * - * The atom is pushed when a new version is detected. + * Logs the version of the carrier ID matching table at first power up and when it is updated. * * Logged from: * frameworks/opt/telephony/src/java/com/android/internal/telephony/metrics/CarrierIdMatchStats.java */ -message CarrierIdMatchingTable { +message CarrierIdTableUpdated { + // Version of the CarrierId matching table. + optional int32 table_version = 1; +} + +/** + * Pulls the version of the carrier ID matching table. + * + * Logged from: + * frameworks/opt/telephony/src/java/com/android/internal/telephony/metrics/MetricsCollector.java + */ +message CarrierIdTableVersion { // Version of the CarrierId matching table. optional int32 table_version = 1; } @@ -11959,3 +11971,45 @@ message HdmiCecMessageReported { // The reason for the feature abort. optional android.stats.hdmi.FeatureAbortReason feature_abort_reason = 9; } + +/** + * Pushes TLS handshake counters from Conscrypt. + * Pulled from: + * external/conscrypt/common/src/main/java/org/conscrypt/ConscryptEngineSocket.java + * external/conscrypt/common/src/main/java/org/conscrypt/ConscryptFileDescriptorSocket.java + */ +message TlsHandshakeReported { + optional bool success = 1; + + optional android.stats.tls.Protocol protocol = 2; + + optional android.stats.tls.CipherSuite cipher_suite = 3; + + optional int32 handshake_duration_millis = 4; +} + +/** + * Logs when a TextClassifier API is invoked. + * + * See frameworks/base/core/java/android/view/textclassifier/TextClassifier.java + * Logged from: external/libtextclassifier/java/ + */ +message TextClassifierApiUsageReported { + enum ApiType { + UNKNOWN_API = 0; + SUGGEST_SELECTION = 1; + CLASSIFY_TEXT = 2; + GENERATE_LINKS = 3; + DETECT_LANGUAGES = 4; + SUGGEST_CONVERSATION_ACTIONS = 5; + } + optional ApiType api_type = 1; + + enum ResultType { + UNKNOWN_RESULT = 0; + SUCCESS = 1; + FAIL = 2; + } + optional ResultType result_type = 2; + optional int64 latency_millis = 3; +} diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 250f2f0b2dc9..a0ec3f1b076f 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -503,8 +503,7 @@ public class ActivityManager { @UnsupportedAppUsage public static final int PROCESS_STATE_TOP = 2; - /** @hide Process is bound to a TOP app. This is ranked below SERVICE_LOCATION so that - * it doesn't get the capability of location access while-in-use. */ + /** @hide Process is bound to a TOP app. */ public static final int PROCESS_STATE_BOUND_TOP = 3; /** @hide Process is hosting a foreground service. */ @@ -4812,13 +4811,14 @@ public class ActivityManager { /** * Holds the AM lock for the specified amount of milliseconds. * This is intended for use by the tests that need to imitate lock contention. + * The token should be obtained by + * {@link android.content.pm.PackageManager#getHoldLockToken()}. * @hide */ @TestApi - @RequiresPermission(android.Manifest.permission.INJECT_EVENTS) - public void holdLock(int durationMs) { + public void holdLock(IBinder token, int durationMs) { try { - getService().holdLock(durationMs); + getService().holdLock(token, durationMs); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/app/ActivityTaskManager.java b/core/java/android/app/ActivityTaskManager.java index 9edf81e8f651..c9b009becac4 100644 --- a/core/java/android/app/ActivityTaskManager.java +++ b/core/java/android/app/ActivityTaskManager.java @@ -173,7 +173,7 @@ public class ActivityTaskManager { * @param toTop If the task should be moved to the top once the windowing mode changes. * @return Whether the task was successfully put into the specified windowing mode. */ - @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public boolean setTaskWindowingMode(int taskId, int windowingMode, boolean toTop) throws SecurityException { try { @@ -200,7 +200,7 @@ public class ActivityTaskManager { * going into split-screen mode. * @return Whether the task was successfully put into splitscreen. */ - @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public boolean setTaskWindowingModeSplitScreenPrimary(int taskId, int createMode, boolean toTop, boolean animate, Rect initialBounds, boolean showRecents) throws SecurityException { try { @@ -214,7 +214,7 @@ public class ActivityTaskManager { * Removes root tasks in the windowing modes from the system if they are of activity type * ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED */ - @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void removeRootTasksInWindowingModes(@NonNull int[] windowingModes) { try { getService().removeRootTasksInWindowingModes(windowingModes); @@ -224,7 +224,7 @@ public class ActivityTaskManager { } /** Removes root tasks of the activity types from the system. */ - @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void removeRootTasksWithActivityTypes(@NonNull int[] activityTypes) { try { getService().removeRootTasksWithActivityTypes(activityTypes); @@ -315,7 +315,7 @@ public class ActivityTaskManager { * @param bounds Bounds to use for pinned root task. * @return True if the top activity of root task was successfully moved to the pinned root task. */ - @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public boolean moveTopActivityToPinnedRootTask(int rootTaskId, @NonNull Rect bounds) { try { return getService().moveTopActivityToPinnedRootTask(rootTaskId, bounds); @@ -328,7 +328,7 @@ public class ActivityTaskManager { * Start to enter lock task mode for given task by system(UI). * @param taskId Id of task to lock. */ - @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void startSystemLockTaskMode(int taskId) { try { getService().startSystemLockTaskMode(taskId); @@ -340,7 +340,7 @@ public class ActivityTaskManager { /** * Stop lock task mode by system(UI). */ - @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void stopSystemLockTaskMode() { try { getService().stopSystemLockTaskMode(); @@ -355,7 +355,7 @@ public class ActivityTaskManager { * @param rootTaskId Id of the rootTask for task moving. * @param toTop Whether the given task should shown to top of stack. */ - @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void moveTaskToRootTask(int taskId, int rootTaskId, boolean toTop) { try { getService().moveTaskToRootTask(taskId, rootTaskId, toTop); @@ -369,7 +369,7 @@ public class ActivityTaskManager { * @param taskId Id of task to resize. * @param bounds Bounds to resize task. */ - @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void resizeTask(int taskId, Rect bounds) { try { getService().resizeTask(taskId, bounds, RESIZE_MODE_SYSTEM); @@ -383,7 +383,7 @@ public class ActivityTaskManager { * @param rootTaskBounds Bounds to resize stack. * @param taskBounds Bounds to resize task. */ - @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void resizePrimarySplitScreen(@NonNull Rect rootTaskBounds, @NonNull Rect taskBounds) { try { getService().resizePrimarySplitScreen(rootTaskBounds, taskBounds, null, null, null); @@ -396,7 +396,7 @@ public class ActivityTaskManager { * Clears launch params for the given package. * @param packageNames the names of the packages of which the launch params are to be cleared */ - @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void clearLaunchParamsForPackages(List<String> packageNames) { try { getService().clearLaunchParamsForPackages(packageNames); @@ -410,7 +410,7 @@ public class ActivityTaskManager { * @hide */ @TestApi - @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void requestPictureInPictureMode(@NonNull IBinder token) { try { getService().requestPictureInPictureMode(token); diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index 357b26c3083d..c0e3019f4619 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -689,6 +689,8 @@ interface IActivityManager { /** * Holds the AM lock for the specified amount of milliseconds. * This is intended for use by the tests that need to imitate lock contention. + * The token should be obtained by + * {@link android.content.pm.PackageManager#getHoldLockToken()}. */ - void holdLock(in int durationMs); + void holdLock(in IBinder token, in int durationMs); } diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java index 1f81c44e54cb..37c4c92d0635 100644 --- a/core/java/android/app/PendingIntent.java +++ b/core/java/android/app/PendingIntent.java @@ -130,6 +130,7 @@ public final class PendingIntent implements Parcelable { FLAG_UPDATE_CURRENT, FLAG_IMMUTABLE, FLAG_MUTABLE, + FLAG_MUTABLE_UNAUDITED, Intent.FILL_IN_ACTION, Intent.FILL_IN_DATA, @@ -205,6 +206,13 @@ public final class PendingIntent implements Parcelable { public static final int FLAG_MUTABLE = 1<<25; /** + * @deprecated Use {@link #FLAG_IMMUTABLE} or {@link #FLAG_MUTABLE} instead. + * @hide + */ + @Deprecated + public static final int FLAG_MUTABLE_UNAUDITED = FLAG_MUTABLE; + + /** * Exception thrown when trying to send through a PendingIntent that * has been canceled or is otherwise no longer able to execute the request. */ diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index ad902a028f13..528e4f8ad398 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -525,7 +525,7 @@ public class DevicePolicyManager { * @hide */ public static final String ACTION_REMOTE_BUGREPORT_DISPATCH = - "android.intent.action.REMOTE_BUGREPORT_DISPATCH"; + "com.android.server.action.REMOTE_BUGREPORT_DISPATCH"; /** * Extra for shared bugreport's SHA-256 hash. @@ -1830,6 +1830,15 @@ public class DevicePolicyManager { public static final int STATE_USER_PROFILE_COMPLETE = 4; /** + * Management setup on a managed profile. + * <p>This is used as an intermediate state after {@link #STATE_USER_PROFILE_COMPLETE} once the + * work profile has been created. + * @hide + */ + @SystemApi + public static final int STATE_USER_PROFILE_FINALIZED = 5; + + /** * @hide */ @IntDef(prefix = { "STATE_USER_" }, value = { @@ -1837,7 +1846,8 @@ public class DevicePolicyManager { STATE_USER_SETUP_INCOMPLETE, STATE_USER_SETUP_COMPLETE, STATE_USER_SETUP_FINALIZED, - STATE_USER_PROFILE_COMPLETE + STATE_USER_PROFILE_COMPLETE, + STATE_USER_PROFILE_FINALIZED }) @Retention(RetentionPolicy.SOURCE) public @interface UserProvisioningState {} diff --git a/core/java/android/companion/AssociationRequest.java b/core/java/android/companion/AssociationRequest.java index c55f0ff7da93..01643bb4d2d6 100644 --- a/core/java/android/companion/AssociationRequest.java +++ b/core/java/android/companion/AssociationRequest.java @@ -46,6 +46,7 @@ public final class AssociationRequest implements Parcelable { private final boolean mSingleDevice; private final List<DeviceFilter<?>> mDeviceFilters; + private String mCallingPackage; private AssociationRequest( boolean singleDevice, @Nullable List<DeviceFilter<?>> deviceFilters) { @@ -57,6 +58,7 @@ public final class AssociationRequest implements Parcelable { this( in.readByte() != 0, in.readParcelableList(new ArrayList<>(), AssociationRequest.class.getClassLoader())); + setCallingPackage(in.readString()); } /** @hide */ @@ -72,32 +74,45 @@ public final class AssociationRequest implements Parcelable { return mDeviceFilters; } + /** @hide */ + public String getCallingPackage() { + return mCallingPackage; + } + + /** @hide */ + public void setCallingPackage(String pkg) { + mCallingPackage = pkg; + } + @Override public boolean equals(@Nullable Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; AssociationRequest that = (AssociationRequest) o; - return mSingleDevice == that.mSingleDevice && - Objects.equals(mDeviceFilters, that.mDeviceFilters); + return mSingleDevice == that.mSingleDevice + && Objects.equals(mDeviceFilters, that.mDeviceFilters) + && Objects.equals(mCallingPackage, that.mCallingPackage); } @Override public int hashCode() { - return Objects.hash(mSingleDevice, mDeviceFilters); + return Objects.hash(mSingleDevice, mDeviceFilters, mCallingPackage); } @Override public String toString() { - return "AssociationRequest{" + - "mSingleDevice=" + mSingleDevice + - ", mDeviceFilters=" + mDeviceFilters + - '}'; + return "AssociationRequest{" + + "mSingleDevice=" + mSingleDevice + + ", mDeviceFilters=" + mDeviceFilters + + ", mCallingPackage=" + mCallingPackage + + '}'; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeByte((byte) (mSingleDevice ? 1 : 0)); dest.writeParcelableList(mDeviceFilters, flags); + dest.writeString(mCallingPackage); } @Override diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java index 78eb8591a3e9..c4d98671a598 100644 --- a/core/java/android/content/ClipData.java +++ b/core/java/android/content/ClipData.java @@ -651,45 +651,57 @@ public class ClipData implements Parcelable { StringBuilder b = new StringBuilder(128); b.append("ClipData.Item { "); - toShortString(b); + toShortString(b, true); b.append(" }"); return b.toString(); } - /** @hide */ - public void toShortString(StringBuilder b) { + /** + * Appends this item to the given builder. + * @param redactContent If true, redacts common forms of PII; otherwise appends full + * details. + * @hide + */ + public void toShortString(StringBuilder b, boolean redactContent) { + boolean first = true; if (mHtmlText != null) { - b.append("H:"); - b.append(mHtmlText); - } else if (mText != null) { - b.append("T:"); - b.append(mText); - } else if (mUri != null) { - b.append("U:"); - b.append(mUri); - } else if (mIntent != null) { - b.append("I:"); - mIntent.toShortString(b, true, true, true, true); - } else { - b.append("NULL"); + first = false; + if (redactContent) { + b.append("H(").append(mHtmlText.length()).append(')'); + } else { + b.append("H:").append(mHtmlText); + } } - } - - /** @hide */ - public void toShortSummaryString(StringBuilder b) { - if (mHtmlText != null) { - b.append("HTML"); - } else if (mText != null) { - b.append("TEXT"); - } else if (mUri != null) { - b.append("U:"); - b.append(mUri); - } else if (mIntent != null) { + if (mText != null) { + if (!first) { + b.append(' '); + } + first = false; + if (redactContent) { + b.append("T(").append(mText.length()).append(')'); + } else { + b.append("T:").append(mText); + } + } + if (mUri != null) { + if (!first) { + b.append(' '); + } + first = false; + if (redactContent) { + b.append("U(").append(mUri.getScheme()).append(')'); + } else { + b.append("U:").append(mUri); + } + } + if (mIntent != null) { + if (!first) { + b.append(' '); + } + first = false; b.append("I:"); - mIntent.toShortString(b, true, true, true, true); - } else { - b.append("NULL"); + mIntent.toShortString(b, redactContent, true, true, true); } } @@ -1040,17 +1052,21 @@ public class ClipData implements Parcelable { StringBuilder b = new StringBuilder(128); b.append("ClipData { "); - toShortString(b); + toShortString(b, true); b.append(" }"); return b.toString(); } - /** @hide */ - public void toShortString(StringBuilder b) { + /** + * Appends this clip to the given builder. + * @param redactContent If true, redacts common forms of PII; otherwise appends full details. + * @hide + */ + public void toShortString(StringBuilder b, boolean redactContent) { boolean first; if (mClipDescription != null) { - first = !mClipDescription.toShortString(b); + first = !mClipDescription.toShortString(b, redactContent); } else { first = true; } @@ -1064,26 +1080,21 @@ public class ClipData implements Parcelable { b.append('x'); b.append(mIcon.getHeight()); } - for (int i=0; i<mItems.size(); i++) { + if (mItems.size() != 1) { if (!first) { b.append(' '); } first = false; - b.append('{'); - mItems.get(i).toShortString(b); - b.append('}'); + b.append(mItems.size()).append(" items:"); } - } - - /** @hide */ - public void toShortStringShortItems(StringBuilder b, boolean first) { - if (mItems.size() > 0) { + for (int i = 0; i < mItems.size(); i++) { if (!first) { b.append(' '); } - for (int i=0; i<mItems.size(); i++) { - b.append("{...}"); - } + first = false; + b.append('{'); + mItems.get(i).toShortString(b, redactContent); + b.append('}'); } } diff --git a/core/java/android/content/ClipDescription.java b/core/java/android/content/ClipDescription.java index dedfce6f6b96..73becb1c0f1c 100644 --- a/core/java/android/content/ClipDescription.java +++ b/core/java/android/content/ClipDescription.java @@ -16,6 +16,7 @@ package android.content; +import android.annotation.NonNull; import android.os.Parcel; import android.os.Parcelable; import android.os.PersistableBundle; @@ -64,12 +65,29 @@ public class ClipDescription implements Parcelable { public static final String MIMETYPE_TEXT_INTENT = "text/vnd.android.intent"; /** - * The MIME type for an activity. + * The MIME type for an activity. The ClipData must include intents with required extras + * {@link #EXTRA_PENDING_INTENT} and {@link Intent#EXTRA_USER}, and an optional + * {@link #EXTRA_ACTIVITY_OPTIONS}. * @hide */ public static final String MIMETYPE_APPLICATION_ACTIVITY = "application/vnd.android.activity"; /** + * The MIME type for a shortcut. The ClipData must include intents with required extras + * {@link #EXTRA_PENDING_INTENT} and {@link Intent#EXTRA_USER}, and an optional + * {@link #EXTRA_ACTIVITY_OPTIONS}. + * @hide + */ + public static final String MIMETYPE_APPLICATION_SHORTCUT = "application/vnd.android.shortcut"; + + /** + * The MIME type for a task. The ClipData must include an intent with a required extra + * {@link Intent#EXTRA_TASK_ID} of the task to launch. + * @hide + */ + public static final String MIMETYPE_APPLICATION_TASK = "application/vnd.android.task"; + + /** * The MIME type for data whose type is otherwise unknown. * <p> * Per RFC 2046, the "application" media type is to be used for discrete @@ -200,6 +218,24 @@ public class ClipDescription implements Parcelable { } /** + * Check whether the clip description contains any of the given MIME types. + * + * @param targetMimeTypes The target MIME types. May use patterns. + * @return Returns true if at least one of the MIME types in the clip description matches at + * least one of the target MIME types, else false. + * + * @hide + */ + public boolean hasMimeType(@NonNull String[] targetMimeTypes) { + for (String targetMimeType : targetMimeTypes) { + if (hasMimeType(targetMimeType)) { + return true; + } + } + return false; + } + + /** * Filter the clip description MIME types by the given MIME type. Returns * all MIME types in the clip that match the given MIME type. * @@ -294,30 +330,45 @@ public class ClipDescription implements Parcelable { StringBuilder b = new StringBuilder(128); b.append("ClipDescription { "); - toShortString(b); + toShortString(b, true); b.append(" }"); return b.toString(); } - /** @hide */ - public boolean toShortString(StringBuilder b) { + /** + * Appends this description to the given builder. + * @param redactContent If true, redacts common forms of PII; otherwise appends full details. + * @hide + */ + public boolean toShortString(StringBuilder b, boolean redactContent) { boolean first = !toShortStringTypesOnly(b); if (mLabel != null) { if (!first) { b.append(' '); } first = false; - b.append('"'); - b.append(mLabel); - b.append('"'); + if (redactContent) { + b.append("hasLabel(").append(mLabel.length()).append(')'); + } else { + b.append('"').append(mLabel).append('"'); + } } if (mExtras != null) { if (!first) { b.append(' '); } first = false; - b.append(mExtras.toString()); + if (redactContent) { + if (mExtras.isParcelled()) { + // We don't want this toString function to trigger un-parcelling. + b.append("hasExtras"); + } else { + b.append("hasExtras(").append(mExtras.size()).append(')'); + } + } else { + b.append(mExtras.toString()); + } } if (mTimeStamp > 0) { if (!first) { diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 9216a0871870..ef92dd182554 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -10485,17 +10485,6 @@ public class Intent implements Parcelable, Cloneable { } /** @hide */ - public String toInsecureStringWithClip() { - StringBuilder b = new StringBuilder(128); - - b.append("Intent { "); - toShortString(b, false, true, true, true); - b.append(" }"); - - return b.toString(); - } - - /** @hide */ public String toShortString(boolean secure, boolean comp, boolean extras, boolean clip) { StringBuilder b = new StringBuilder(128); toShortString(b, secure, comp, extras, clip); @@ -10581,16 +10570,7 @@ public class Intent implements Parcelable, Cloneable { b.append(' '); } b.append("clip={"); - if (clip) { - mClipData.toShortString(b); - } else { - if (mClipData.getDescription() != null) { - first = !mClipData.getDescription().toShortStringTypesOnly(b); - } else { - first = true; - } - mClipData.toShortStringShortItems(b, first); - } + mClipData.toShortString(b, !clip || secure); first = false; b.append('}'); } @@ -10668,11 +10648,7 @@ public class Intent implements Parcelable, Cloneable { } if (mClipData != null) { StringBuilder b = new StringBuilder(); - if (clip) { - mClipData.toShortString(b); - } else { - mClipData.toShortStringShortItems(b, false); - } + mClipData.toShortString(b, !clip || secure); proto.write(IntentProto.CLIP_DATA, b.toString()); } if (extras && mExtras != null) { diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl index d9ecf46069cd..d688614f6caa 100644 --- a/core/java/android/content/pm/ILauncherApps.aidl +++ b/core/java/android/content/pm/ILauncherApps.aidl @@ -17,6 +17,7 @@ package android.content.pm; import android.app.IApplicationThread; +import android.app.PendingIntent; import android.content.ComponentName; import android.content.Intent; import android.content.IntentSender; @@ -55,6 +56,8 @@ interface ILauncherApps { void startActivityAsUser(in IApplicationThread caller, String callingPackage, String callingFeatureId, in ComponentName component, in Rect sourceBounds, in Bundle opts, in UserHandle user); + PendingIntent getActivityLaunchIntent(in ComponentName component, in Bundle opts, + in UserHandle user); void showAppDetailsAsUser(in IApplicationThread caller, String callingPackage, String callingFeatureId, in ComponentName component, in Rect sourceBounds, in Bundle opts, in UserHandle user); diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index c32d34457889..106021e81ddc 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -794,5 +794,7 @@ interface IPackageManager { void grantImplicitAccess(int queryingUid, String visibleAuthority); - void holdLock(in int durationMs); + IBinder getHoldLockToken(); + + void holdLock(in IBinder token, in int durationMs); } diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java index b7af397cd36a..2909d66d72ff 100644 --- a/core/java/android/content/pm/LauncherApps.java +++ b/core/java/android/content/pm/LauncherApps.java @@ -17,6 +17,7 @@ package android.content.pm; import static android.Manifest.permission; +import static android.app.PendingIntent.FLAG_IMMUTABLE; import android.annotation.CallbackExecutor; import android.annotation.IntDef; @@ -716,6 +717,29 @@ public class LauncherApps { } /** + * Returns a PendingIntent that would start the same activity started from + * {@link #startMainActivity(ComponentName, UserHandle, Rect, Bundle)}. + * + * @param component The ComponentName of the activity to launch + * @param startActivityOptions Options to pass to startActivity + * @param user The UserHandle of the profile + * @hide + */ + @Nullable + public PendingIntent getMainActivityLaunchIntent(@NonNull ComponentName component, + @Nullable Bundle startActivityOptions, @NonNull UserHandle user) { + logErrorForInvalidProfileAccess(user); + if (DEBUG) { + Log.i(TAG, "GetMainActivityLaunchIntent " + component + " " + user); + } + try { + return mService.getActivityLaunchIntent(component, startActivityOptions, user); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + + /** * Returns the activity info for a given intent and user handle, if it resolves. Otherwise it * returns null. * diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 3fb9a9e924e7..a1ac87c78aa2 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -63,6 +63,7 @@ import android.net.wifi.WifiManager; import android.os.Build; import android.os.Bundle; import android.os.Handler; +import android.os.IBinder; import android.os.PersistableBundle; import android.os.RemoteException; import android.os.UserHandle; @@ -566,9 +567,11 @@ public abstract class PackageManager { public static final int MATCH_DEBUG_TRIAGED_MISSING = MATCH_DIRECT_BOOT_AUTO; /** - * Internal {@link PackageInfo} flag used to indicate that a package is a hidden system app. + * {@link PackageInfo} flag: include system apps that are in the uninstalled state and have + * been set to be hidden until installed via {@link #setSystemAppState}. * @hide */ + @SystemApi public static final int MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS = 0x20000000; /** @@ -3767,27 +3770,34 @@ public abstract class PackageManager { public @interface SystemAppState {} /** - * Constant for noting system app state as hidden before installation + * Constant for use with {@link #setSystemAppState} to mark a system app as hidden until + * installation. * @hide */ + @SystemApi public static final int SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN = 0; /** - * Constant for noting system app state as visible before installation + * Constant for use with {@link #setSystemAppState} to mark a system app as not hidden until + * installation. * @hide */ + @SystemApi public static final int SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_VISIBLE = 1; /** - * Constant for noting system app state as installed + * Constant for use with {@link #setSystemAppState} to change a system app's state to installed. * @hide */ + @SystemApi public static final int SYSTEM_APP_STATE_INSTALLED = 2; /** - * Constant for noting system app state as not installed + * Constant for use with {@link #setSystemAppState} to change a system app's state to + * uninstalled. * @hide */ + @SystemApi public static final int SYSTEM_APP_STATE_UNINSTALLED = 3; /** @@ -7091,11 +7101,18 @@ public abstract class PackageManager { @NonNull UserHandle userHandle); /** - * Sets system app state + * Sets the state of a system app. + * + * This method can be used to change a system app's hidden-until-installed state (via + * {@link #SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN} and + * {@link #SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_VISIBLE} or its installation state (via + * {@link #SYSTEM_APP_STATE_INSTALLED} and {@link #SYSTEM_APP_STATE_UNINSTALLED}. + * * @param packageName Package name of the app. * @param state State of the app. * @hide */ + @SystemApi public void setSystemAppState(@NonNull String packageName, @SystemAppState int state) { throw new RuntimeException("Not implemented. Must override in a subclass"); } @@ -8462,15 +8479,30 @@ public abstract class PackageManager { } /** + * Returns the token to be used by the subsequent calls to holdLock(). + * @hide + */ + @RequiresPermission(android.Manifest.permission.INJECT_EVENTS) + @TestApi + public IBinder getHoldLockToken() { + try { + return ActivityThread.getPackageManager().getHoldLockToken(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Holds the PM lock for the specified amount of milliseconds. * Intended for use by the tests that need to imitate lock contention. + * The token should be obtained by + * {@link android.content.pm.PackageManager#getHoldLockToken()}. * @hide */ @TestApi - @RequiresPermission(android.Manifest.permission.INJECT_EVENTS) - public void holdLock(int durationMs) { + public void holdLock(IBinder token, int durationMs) { try { - ActivityThread.getPackageManager().holdLock(durationMs); + ActivityThread.getPackageManager().holdLock(token, durationMs); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java index 7ed803f78260..5855de1109bd 100644 --- a/core/java/android/content/pm/ShortcutInfo.java +++ b/core/java/android/content/pm/ShortcutInfo.java @@ -1212,8 +1212,12 @@ public final class ShortcutInfo implements Parcelable { } /** - * Sets categories for a shortcut. Launcher apps may use this information to - * categorize shortcuts. + * Sets categories for a shortcut. + * <ul> + * <li>Launcher apps may use this information to categorize shortcuts + * <li>Used to filter shortcuts that can handle share intents or actions + * and required for shortcuts that are meant to be used as share targets. + * </ul> * * @see #SHORTCUT_CATEGORY_CONVERSATION * @see ShortcutInfo#getCategories() diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java index 2efec3fa2ec1..62df92e656d6 100644 --- a/core/java/android/hardware/camera2/CameraCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraCharacteristics.java @@ -1180,7 +1180,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * <p>The list of extended scene modes for {@link CaptureRequest#CONTROL_EXTENDED_SCENE_MODE android.control.extendedSceneMode} that * are supported by this camera device, and each extended scene mode's capabilities such * as maximum streaming size, and supported zoom ratio ranges.</p> - * <p>For DISABLED mode, the camera behaves normally with no extended scene mdoe enabled.</p> + * <p>For DISABLED mode, the camera behaves normally with no extended scene mode enabled.</p> * <p>For BOKEH_STILL_CAPTURE mode, the maximum streaming dimension specifies the limit * under which bokeh is effective when capture intent is PREVIEW. Note that when capture * intent is PREVIEW, the bokeh effect may not be as high quality compared to STILL_CAPTURE @@ -3164,7 +3164,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * rectangle, and cropping to the rectangle given in {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.</p> * <p>E.g. to calculate position of a pixel, (x,y), in a processed YUV output image with the * dimensions in {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} given the position of a pixel, - * (x', y'), in the raw pixel array with dimensions give in + * (x', y'), in the raw pixel array with dimensions given in * {@link CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE android.sensor.info.pixelArraySize}:</p> * <ol> * <li>Choose a pixel (x', y') within the active array region of the raw buffer given in diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java index 68b9d5227746..d6cd3feafca7 100644 --- a/core/java/android/hardware/display/DisplayManager.java +++ b/core/java/android/hardware/display/DisplayManager.java @@ -326,6 +326,15 @@ public final class DisplayManager { @TestApi public static final int VIRTUAL_DISPLAY_FLAG_TRUSTED = 1 << 10; + /** + * Virtual display flags: Indicates that the display should not be a part of the default + * DisplayGroup and instead be part of a new DisplayGroup. + * + * @see #createVirtualDisplay + * @hide + */ + public static final int VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP = 1 << 11; + /** @hide */ public DisplayManager(Context context) { mContext = context; diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java index be33f4edb5d1..12ddc628f4bd 100644 --- a/core/java/android/net/NetworkCapabilities.java +++ b/core/java/android/net/NetworkCapabilities.java @@ -170,6 +170,7 @@ public final class NetworkCapabilities implements Parcelable { NET_CAPABILITY_MCX, NET_CAPABILITY_PARTIAL_CONNECTIVITY, NET_CAPABILITY_TEMPORARILY_NOT_METERED, + NET_CAPABILITY_OEM_PRIVATE, }) public @interface NetCapability { } @@ -345,8 +346,15 @@ public final class NetworkCapabilities implements Parcelable { */ public static final int NET_CAPABILITY_TEMPORARILY_NOT_METERED = 25; + /** + * Indicates that this network is private to the OEM and meant only for OEM use. + * @hide + */ + @SystemApi + public static final int NET_CAPABILITY_OEM_PRIVATE = 26; + private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS; - private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_TEMPORARILY_NOT_METERED; + private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_OEM_PRIVATE; /** * Network capabilities that are expected to be mutable, i.e., can change while a particular @@ -404,7 +412,8 @@ public final class NetworkCapabilities implements Parcelable { * {@see #maybeMarkCapabilitiesRestricted}. */ private static final long FORCE_RESTRICTED_CAPABILITIES = - (1 << NET_CAPABILITY_OEM_PAID); + (1 << NET_CAPABILITY_OEM_PAID) + | (1 << NET_CAPABILITY_OEM_PRIVATE); /** * Capabilities that suggest that a network is unrestricted. @@ -1910,6 +1919,7 @@ public final class NetworkCapabilities implements Parcelable { case NET_CAPABILITY_MCX: return "MCX"; case NET_CAPABILITY_PARTIAL_CONNECTIVITY: return "PARTIAL_CONNECTIVITY"; case NET_CAPABILITY_TEMPORARILY_NOT_METERED: return "TEMPORARILY_NOT_METERED"; + case NET_CAPABILITY_OEM_PRIVATE: return "OEM_PRIVATE"; default: return Integer.toString(capability); } } diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java index 8cdcd49cb2cc..13b30f43ff7a 100644 --- a/core/java/android/os/RecoverySystem.java +++ b/core/java/android/os/RecoverySystem.java @@ -908,7 +908,11 @@ public class RecoverySystem { Intent intent = new Intent(ACTION_EUICC_FACTORY_RESET); intent.setPackage(packageName); PendingIntent callbackIntent = PendingIntent.getBroadcastAsUser( - context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT, UserHandle.SYSTEM); + context, + 0, + intent, + PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT, + UserHandle.SYSTEM); IntentFilter filterConsent = new IntentFilter(); filterConsent.addAction(ACTION_EUICC_FACTORY_RESET); HandlerThread euiccHandlerThread = new HandlerThread("euiccWipeFinishReceiverThread"); @@ -1002,7 +1006,11 @@ public class RecoverySystem { Intent intent = new Intent(ACTION_EUICC_REMOVE_INVISIBLE_SUBSCRIPTIONS); intent.setPackage(PACKAGE_NAME_EUICC_DATA_MANAGEMENT_CALLBACK); PendingIntent callbackIntent = PendingIntent.getBroadcastAsUser( - context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT, UserHandle.SYSTEM); + context, + 0, + intent, + PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT, + UserHandle.SYSTEM); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(ACTION_EUICC_REMOVE_INVISIBLE_SUBSCRIPTIONS); HandlerThread euiccHandlerThread = diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index b0e76e3ea851..93d6cae82bfe 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -67,7 +67,7 @@ import java.util.Set; /** * Manages users and user details on a multi-user system. There are two major categories of - * users: fully customizable users with their own login, and managed profiles that share a workspace + * users: fully customizable users with their own login, and profiles that share a workspace * with a related user. * <p> * Users are different from accounts, which are managed by @@ -2298,7 +2298,7 @@ public class UserManager { * private app data storage is available. * <p>Requires {@code android.permission.MANAGE_USERS} or * {@code android.permission.INTERACT_ACROSS_USERS}, otherwise specified {@link UserHandle user} - * must be the calling user or a managed profile associated with it. + * must be the calling user or a profile associated with it. * * @param user to retrieve the unlocked state for. * @see Intent#ACTION_USER_UNLOCKED @@ -2496,7 +2496,7 @@ public class UserManager { * * <p>Requires {@code android.permission.MANAGE_USERS} or * {@code android.permission.INTERACT_ACROSS_USERS}, otherwise specified {@link UserHandle user} - * must be the calling user or a managed profile associated with it. + * must be the calling user or a profile associated with it. */ @RequiresPermission(anyOf = { android.Manifest.permission.MANAGE_USERS, @@ -2620,7 +2620,7 @@ public class UserManager { * * <p>Requires {@code android.permission.MANAGE_USERS} or * {@code android.permission.INTERACT_ACROSS_USERS}, otherwise specified {@link UserHandle user} - * must be the calling user or a managed profile associated with it. + * must be the calling user or a profile associated with it. * * @hide */ @@ -3429,6 +3429,7 @@ public class UserManager { * Returns list of the profiles of userId including userId itself. * Note that this returns both enabled and not enabled profiles. See * {@link #getEnabledProfiles(int)} if you need only the enabled ones. + * <p>Note that this includes all profile types (not including Restricted profiles). * * <p>Requires {@link android.Manifest.permission#MANAGE_USERS}. * {@link android.Manifest.permission#CREATE_USERS} suffices if userId is the calling user. @@ -3481,6 +3482,7 @@ public class UserManager { /** * Returns list of the profiles of userId including userId itself. * Note that this returns only enabled. + * <p>Note that this includes all profile types (not including Restricted profiles). * * <p>Requires {@link android.Manifest.permission#MANAGE_USERS}. * {@link android.Manifest.permission#CREATE_USERS} suffices if userId is the calling user. @@ -3502,6 +3504,7 @@ public class UserManager { /** * Returns a list of UserHandles for profiles associated with the user that the calling process * is running on, including the user itself. + * <p>Note that this includes all profile types (not including Restricted profiles). * * @return A non-empty list of UserHandles associated with the calling user. */ @@ -3517,6 +3520,7 @@ public class UserManager { /** * Returns a list of ids for enabled profiles associated with the context user including the * user itself. + * <p>Note that this includes all profile types (not including Restricted profiles). * * @return A non-empty list of UserHandles associated with the calling user. * @hide @@ -3532,6 +3536,7 @@ public class UserManager { /** * Returns a list of ids for all profiles associated with the context user including the user * itself. + * <p>Note that this includes all profile types (not including Restricted profiles). * * @return A non-empty list of UserHandles associated with the calling user. * @hide @@ -3547,6 +3552,7 @@ public class UserManager { /** * Returns a list of ids for profiles associated with the context user including the user * itself. + * <p>Note that this includes all profile types (not including Restricted profiles). * * @param enabledOnly whether to return only {@link UserInfo#isEnabled() enabled} profiles * @return A non-empty list of UserHandles associated with the calling user. @@ -3566,6 +3572,7 @@ public class UserManager { /** * Returns a list of ids for profiles associated with the specified user including the user * itself. + * <p>Note that this includes all profile types (not including Restricted profiles). * * @param userId id of the user to return profiles for * @param enabledOnly whether return only {@link UserInfo#isEnabled() enabled} profiles @@ -4355,8 +4362,9 @@ public class UserManager { } /** - * Returns creation time of the user or of a managed profile associated with the calling user. - * @param userHandle user handle of the user or a managed profile associated with the + * Returns creation time of the given user. The given user must be the calling user or + * a profile associated with it. + * @param userHandle user handle of the calling user or a profile associated with the * calling user. * @return creation time in milliseconds since Epoch time. */ diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 60d1d477db53..32576c913fc2 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -9897,6 +9897,13 @@ public final class Settings { "hdmi_cec_switch_enabled"; /** + * HDMI CEC version to use. Defaults to v1.4b. + * @hide + */ + public static final String HDMI_CEC_VERSION = + "hdmi_cec_version"; + + /** * Whether TV will automatically turn on upon reception of the CEC command * <Text View On> or <Image View On>. (0 = false, 1 = true) * @@ -11888,21 +11895,6 @@ public final class Settings { public static final String POWER_MANAGER_CONSTANTS = "power_manager_constants"; /** - * Job scheduler QuotaController specific settings. - * This is encoded as a key=value list, separated by commas. Ex: - * - * "max_job_count_working=5,max_job_count_rare=2" - * - * <p> - * Type: string - * - * @hide - * @see com.android.server.job.JobSchedulerService.Constants - */ - public static final String JOB_SCHEDULER_QUOTA_CONTROLLER_CONSTANTS = - "job_scheduler_quota_controller_constants"; - - /** * ShortcutManager specific settings. * This is encoded as a key=value list, separated by commas. Ex: * @@ -14540,6 +14532,15 @@ public final class Settings { public static final String SHOW_NEW_LOCKSCREEN = "show_new_lockscreen"; /** + * Whether to show new notification dismissal. + * Values are: + * 0: Disabled + * 1: Enabled + * @hide + */ + public static final String SHOW_NEW_NOTIF_DISMISS = "show_new_notif_dismiss"; + + /** * Block untrusted touches mode. * * Can be one of: diff --git a/core/java/android/security/keystore/recovery/RecoveryController.java b/core/java/android/security/keystore/recovery/RecoveryController.java index cc3e57859b64..d859b1c33c94 100644 --- a/core/java/android/security/keystore/recovery/RecoveryController.java +++ b/core/java/android/security/keystore/recovery/RecoveryController.java @@ -751,7 +751,7 @@ public class RecoveryController { InternalRecoveryServiceException wrapUnexpectedServiceSpecificException( ServiceSpecificException e) { if (e.errorCode == ERROR_SERVICE_INTERNAL_ERROR) { - return new InternalRecoveryServiceException(e.getMessage()); + return new InternalRecoveryServiceException(e.getMessage(), e); } // Should never happen. If it does, it's a bug, and we need to update how the method that diff --git a/core/java/android/service/autofill/Dataset.java b/core/java/android/service/autofill/Dataset.java index 18d79927388b..8ae1b6bf702d 100644 --- a/core/java/android/service/autofill/Dataset.java +++ b/core/java/android/service/autofill/Dataset.java @@ -20,7 +20,10 @@ import static android.view.autofill.Helper.sDebug; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SuppressLint; import android.annotation.SystemApi; +import android.annotation.TestApi; +import android.content.ClipData; import android.content.IntentSender; import android.os.Parcel; import android.os.Parcelable; @@ -97,7 +100,6 @@ import java.util.regex.Pattern; * with the lower case value of the view's text are shown. * <li>All other datasets are hidden. * </ol> - * */ public final class Dataset implements Parcelable { @@ -106,6 +108,7 @@ public final class Dataset implements Parcelable { private final ArrayList<RemoteViews> mFieldPresentations; private final ArrayList<InlinePresentation> mFieldInlinePresentations; private final ArrayList<DatasetFieldFilter> mFieldFilters; + @Nullable private final ClipData mFieldContent; private final RemoteViews mPresentation; @Nullable private final InlinePresentation mInlinePresentation; private final IntentSender mAuthentication; @@ -117,6 +120,7 @@ public final class Dataset implements Parcelable { mFieldPresentations = builder.mFieldPresentations; mFieldInlinePresentations = builder.mFieldInlinePresentations; mFieldFilters = builder.mFieldFilters; + mFieldContent = builder.mFieldContent; mPresentation = builder.mPresentation; mInlinePresentation = builder.mInlinePresentation; mAuthentication = builder.mAuthentication; @@ -124,11 +128,15 @@ public final class Dataset implements Parcelable { } /** @hide */ + @TestApi + @SuppressLint("ConcreteCollection") public @Nullable ArrayList<AutofillId> getFieldIds() { return mFieldIds; } /** @hide */ + @TestApi + @SuppressLint("ConcreteCollection") public @Nullable ArrayList<AutofillValue> getFieldValues() { return mFieldValues; } @@ -140,24 +148,37 @@ public final class Dataset implements Parcelable { } /** @hide */ - @Nullable - public InlinePresentation getFieldInlinePresentation(int index) { + public @Nullable InlinePresentation getFieldInlinePresentation(int index) { final InlinePresentation inlinePresentation = mFieldInlinePresentations.get(index); return inlinePresentation != null ? inlinePresentation : mInlinePresentation; } /** @hide */ - @Nullable - public DatasetFieldFilter getFilter(int index) { + public @Nullable DatasetFieldFilter getFilter(int index) { return mFieldFilters.get(index); } + /** + * Returns the content to be filled for a non-text suggestion. This is only applicable to + * augmented autofill. The target field for the content is available via {@link #getFieldIds()} + * (guaranteed to have a single field id set when the return value here is non-null). See + * {@link Builder#setContent(AutofillId, ClipData)} for more info. + * + * @hide + */ + @TestApi + public @Nullable ClipData getFieldContent() { + return mFieldContent; + } + /** @hide */ + @TestApi public @Nullable IntentSender getAuthentication() { return mAuthentication; } /** @hide */ + @TestApi public boolean isEmpty() { return mFieldIds == null || mFieldIds.isEmpty(); } @@ -179,6 +200,9 @@ public final class Dataset implements Parcelable { if (mFieldValues != null) { builder.append(", fieldValues=").append(mFieldValues); } + if (mFieldContent != null) { + builder.append(", fieldContent=").append(mFieldContent); + } if (mFieldPresentations != null) { builder.append(", fieldPresentations=").append(mFieldPresentations.size()); } @@ -207,7 +231,8 @@ public final class Dataset implements Parcelable { * * @hide */ - public String getId() { + @TestApi + public @Nullable String getId() { return mId; } @@ -221,6 +246,7 @@ public final class Dataset implements Parcelable { private ArrayList<RemoteViews> mFieldPresentations; private ArrayList<InlinePresentation> mFieldInlinePresentations; private ArrayList<DatasetFieldFilter> mFieldFilters; + @Nullable private ClipData mFieldContent; private RemoteViews mPresentation; @Nullable private InlinePresentation mInlinePresentation; private IntentSender mAuthentication; @@ -366,6 +392,36 @@ public final class Dataset implements Parcelable { } /** + * Sets the content for a field. + * + * <p>Only called by augmented autofill. + * + * <p>For a given field, either a {@link AutofillValue value} or content can be filled, but + * not both. Furthermore, when filling content, only a single field can be filled. + * + * @param id id returned by + * {@link android.app.assist.AssistStructure.ViewNode#getAutofillId()}. + * @param content content to be autofilled. Pass {@code null} if you do not have the content + * but the target view is a logical part of the dataset. For example, if the dataset needs + * authentication. + * + * @throws IllegalStateException if {@link #build()} was already called. + * + * @return this builder. + * + * @hide + */ + @TestApi + @SystemApi + @SuppressLint("MissingGetterMatchingBuilder") + public @NonNull Builder setContent(@NonNull AutofillId id, @Nullable ClipData content) { + throwIfDestroyed(); + setLifeTheUniverseAndEverything(id, null, null, null, null); + mFieldContent = content; + return this; + } + + /** * Sets the value of a field. * * <b>Note:</b> Prior to Android {@link android.os.Build.VERSION_CODES#P}, this method would @@ -659,6 +715,15 @@ public final class Dataset implements Parcelable { if (mFieldIds == null) { throw new IllegalStateException("at least one value must be set"); } + if (mFieldContent != null) { + if (mFieldIds.size() > 1) { + throw new IllegalStateException( + "when filling content, only one field can be filled"); + } + if (mFieldValues.get(0) != null) { + throw new IllegalStateException("cannot fill both content and values"); + } + } return new Dataset(this); } @@ -687,6 +752,7 @@ public final class Dataset implements Parcelable { parcel.writeTypedList(mFieldPresentations, flags); parcel.writeTypedList(mFieldInlinePresentations, flags); parcel.writeTypedList(mFieldFilters, flags); + parcel.writeParcelable(mFieldContent, flags); parcel.writeParcelable(mAuthentication, flags); parcel.writeString(mId); } @@ -694,18 +760,8 @@ public final class Dataset implements Parcelable { public static final @NonNull Creator<Dataset> CREATOR = new Creator<Dataset>() { @Override public Dataset createFromParcel(Parcel parcel) { - // Always go through the builder to ensure the data ingested by - // the system obeys the contract of the builder to avoid attacks - // using specially crafted parcels. final RemoteViews presentation = parcel.readParcelable(null); final InlinePresentation inlinePresentation = parcel.readParcelable(null); - final Builder builder = presentation != null - ? inlinePresentation == null - ? new Builder(presentation) - : new Builder(presentation).setInlinePresentation(inlinePresentation) - : inlinePresentation == null - ? new Builder() - : new Builder(inlinePresentation); final ArrayList<AutofillId> ids = parcel.createTypedArrayList(AutofillId.CREATOR); final ArrayList<AutofillValue> values = @@ -716,6 +772,21 @@ public final class Dataset implements Parcelable { parcel.createTypedArrayList(InlinePresentation.CREATOR); final ArrayList<DatasetFieldFilter> filters = parcel.createTypedArrayList(DatasetFieldFilter.CREATOR); + final ClipData fieldContent = parcel.readParcelable(null); + final IntentSender authentication = parcel.readParcelable(null); + final String datasetId = parcel.readString(); + + // Always go through the builder to ensure the data ingested by + // the system obeys the contract of the builder to avoid attacks + // using specially crafted parcels. + final Builder builder = (presentation != null) ? new Builder(presentation) + : new Builder(); + if (inlinePresentation != null) { + builder.setInlinePresentation(inlinePresentation); + } + if (fieldContent != null) { + builder.setContent(ids.get(0), fieldContent); + } final int inlinePresentationsSize = inlinePresentations.size(); for (int i = 0; i < ids.size(); i++) { final AutofillId id = ids.get(i); @@ -727,8 +798,8 @@ public final class Dataset implements Parcelable { builder.setLifeTheUniverseAndEverything(id, value, fieldPresentation, fieldInlinePresentation, filter); } - builder.setAuthentication(parcel.readParcelable(null)); - builder.setId(parcel.readString()); + builder.setAuthentication(authentication); + builder.setId(datasetId); return builder.build(); } diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java index a9ab33c0d1de..3c90a5c099cd 100644 --- a/core/java/android/service/notification/ZenModeConfig.java +++ b/core/java/android/service/notification/ZenModeConfig.java @@ -286,7 +286,7 @@ public class ZenModeConfig implements Parcelable { } StringBuilder buffer = new StringBuilder(automaticRules.size() * 28); - buffer.append('{'); + buffer.append("{\n"); for (int i = 0; i < automaticRules.size(); i++) { if (i > 0) { buffer.append(",\n"); @@ -1830,12 +1830,13 @@ public class ZenModeConfig implements Parcelable { public String toString() { return new StringBuilder(ZenRule.class.getSimpleName()).append('[') .append("id=").append(id) + .append(",state=").append(condition == null ? "STATE_FALSE" + : Condition.stateToString(condition.state)) .append(",enabled=").append(String.valueOf(enabled).toUpperCase()) .append(",snoozing=").append(snoozing) .append(",name=").append(name) .append(",zenMode=").append(Global.zenModeToString(zenMode)) .append(",conditionId=").append(conditionId) - .append(",condition=").append(condition) .append(",pkg=").append(pkg) .append(",component=").append(component) .append(",configActivity=").append(configurationActivity) @@ -1843,6 +1844,7 @@ public class ZenModeConfig implements Parcelable { .append(",enabler=").append(enabler) .append(",zenPolicy=").append(zenPolicy) .append(",modified=").append(modified) + .append(",condition=").append(condition) .append(']').toString(); } @@ -2010,6 +2012,10 @@ public class ZenModeConfig implements Parcelable { public Diff addLine(String item, Object from, Object to) { return addLine(item, from + "->" + to); } + + public boolean isEmpty() { + return lines.isEmpty(); + } } /** diff --git a/core/java/android/text/Editable.java b/core/java/android/text/Editable.java index 3396bceb75d0..a942f6ce2879 100644 --- a/core/java/android/text/Editable.java +++ b/core/java/android/text/Editable.java @@ -137,7 +137,7 @@ extends CharSequence, GetChars, Spannable, Appendable } /** - * Returns a new SpannedStringBuilder from the specified + * Returns a new SpannableStringBuilder from the specified * CharSequence. You can override this to provide * a different kind of Spanned. */ diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index 34e8221bc971..ab76e4aea993 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -262,6 +262,15 @@ public final class Display { public static final int FLAG_TRUSTED = 1 << 7; /** + * Flag: Indicates that the display should not be a part of the default DisplayGroup and + * instead be part of a new DisplayGroup. + * + * @hide + * @see #getFlags() + */ + public static final int FLAG_OWN_DISPLAY_GROUP = 1 << 8; + + /** * Display flag: Indicates that the contents of the display should not be scaled * to fit the physical screen dimensions. Used for development only to emulate * devices with smaller physicals screens while preserving density. diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 43a8992aa74e..d226f6048471 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -755,6 +755,8 @@ interface IWindowManager /** * Holds the WM lock for the specified amount of milliseconds. * Intended for use by the tests that need to imitate lock contention. + * The token should be obtained by + * {@link android.content.pm.PackageManager#getHoldLockToken()}. */ - void holdLock(in int durationMs); + void holdLock(in IBinder token, in int durationMs); } diff --git a/core/java/android/view/NotificationTopLineView.java b/core/java/android/view/NotificationTopLineView.java index 9443ccfc7553..24748222b3af 100644 --- a/core/java/android/view/NotificationTopLineView.java +++ b/core/java/android/view/NotificationTopLineView.java @@ -19,6 +19,7 @@ package android.view; import android.annotation.Nullable; import android.content.Context; import android.content.res.Resources; +import android.content.res.TypedArray; import android.graphics.Rect; import android.util.AttributeSet; import android.widget.RemoteViews; @@ -36,6 +37,7 @@ import java.util.List; */ @RemoteViews.RemoteView public class NotificationTopLineView extends ViewGroup { + private final int mGravityY; private final int mChildMinWidth; private final int mContentEndMargin; private View mAppName; @@ -48,6 +50,9 @@ public class NotificationTopLineView extends ViewGroup { private int mHeaderTextMarginEnd; private List<View> mIconsAtEnd; + private int mMaxAscent; + private int mMaxDescent; + public NotificationTopLineView(Context context) { this(context, null); } @@ -67,6 +72,20 @@ public class NotificationTopLineView extends ViewGroup { Resources res = getResources(); mChildMinWidth = res.getDimensionPixelSize(R.dimen.notification_header_shrink_min_width); mContentEndMargin = res.getDimensionPixelSize(R.dimen.notification_content_margin_end); + + // NOTE: Implementation only supports TOP, BOTTOM, and CENTER_VERTICAL gravities, + // with CENTER_VERTICAL being the default. + int[] attrIds = {android.R.attr.gravity}; + TypedArray ta = context.obtainStyledAttributes(attrs, attrIds, defStyleAttr, defStyleRes); + int gravity = ta.getInt(0, 0); + ta.recycle(); + if ((gravity & Gravity.BOTTOM) == Gravity.BOTTOM) { + mGravityY = Gravity.BOTTOM; + } else if ((gravity & Gravity.TOP) == Gravity.TOP) { + mGravityY = Gravity.TOP; + } else { + mGravityY = Gravity.CENTER_VERTICAL; + } } @Override @@ -84,12 +103,16 @@ public class NotificationTopLineView extends ViewGroup { protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { final int givenWidth = MeasureSpec.getSize(widthMeasureSpec); final int givenHeight = MeasureSpec.getSize(heightMeasureSpec); + final boolean wrapHeight = MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST; int wrapContentWidthSpec = MeasureSpec.makeMeasureSpec(givenWidth, MeasureSpec.AT_MOST); int wrapContentHeightSpec = MeasureSpec.makeMeasureSpec(givenHeight, MeasureSpec.AT_MOST); int totalWidth = getPaddingStart(); int iconWidth = getPaddingEnd(); + int maxChildHeight = -1; + mMaxAscent = -1; + mMaxDescent = -1; for (int i = 0; i < getChildCount(); i++) { final View child = getChildAt(i); if (child.getVisibility() == GONE) { @@ -108,6 +131,13 @@ public class NotificationTopLineView extends ViewGroup { } else { totalWidth += lp.leftMargin + lp.rightMargin + child.getMeasuredWidth(); } + int childBaseline = child.getBaseline(); + int childHeight = child.getMeasuredHeight(); + if (childBaseline != -1) { + mMaxAscent = Math.max(mMaxAscent, childBaseline); + mMaxDescent = Math.max(mMaxDescent, childHeight - childBaseline); + } + maxChildHeight = Math.max(maxChildHeight, childHeight); } // Ensure that there is at least enough space for the icons @@ -125,7 +155,7 @@ public class NotificationTopLineView extends ViewGroup { shrinkViewForOverflow(wrapContentHeightSpec, overFlow, mSecondaryHeaderText, 0); } - setMeasuredDimension(givenWidth, givenHeight); + setMeasuredDimension(givenWidth, wrapHeight ? maxChildHeight : givenHeight); } private int shrinkViewForOverflow(int heightSpec, int overFlow, View targetView, @@ -146,7 +176,13 @@ public class NotificationTopLineView extends ViewGroup { int left = getPaddingStart(); int end = getMeasuredWidth(); int childCount = getChildCount(); - int ownHeight = getMeasuredHeight() - getPaddingTop() - getPaddingBottom(); + int ownHeight = b - t; + int childSpace = ownHeight - mPaddingTop - mPaddingBottom; + + // Instead of centering the baseline, pick a baseline that centers views which align to it. + // Only used when mGravityY is CENTER_VERTICAL + int baselineY = mPaddingTop + ((childSpace - (mMaxAscent + mMaxDescent)) / 2) + mMaxAscent; + for (int i = 0; i < childCount; i++) { View child = getChildAt(i); if (child.getVisibility() == GONE) { @@ -156,8 +192,42 @@ public class NotificationTopLineView extends ViewGroup { MarginLayoutParams params = (MarginLayoutParams) child.getLayoutParams(); int layoutLeft; int layoutRight; - int top = (int) (getPaddingTop() + (ownHeight - childHeight) / 2.0f); - int bottom = top + childHeight; + + // Calculate vertical alignment of the views, accounting for the view baselines + int childTop; + int childBaseline = child.getBaseline(); + switch (mGravityY) { + case Gravity.TOP: + childTop = mPaddingTop + params.topMargin; + if (childBaseline != -1) { + childTop += mMaxAscent - childBaseline; + } + break; + case Gravity.CENTER_VERTICAL: + if (childBaseline != -1) { + // Align baselines vertically only if the child is smaller than us + if (childSpace - childHeight > 0) { + childTop = baselineY - childBaseline; + } else { + childTop = mPaddingTop + (childSpace - childHeight) / 2; + } + } else { + childTop = mPaddingTop + ((childSpace - childHeight) / 2) + + params.topMargin - params.bottomMargin; + } + break; + case Gravity.BOTTOM: + int childBottom = ownHeight - mPaddingBottom; + childTop = childBottom - childHeight - params.bottomMargin; + if (childBaseline != -1) { + int descent = childHeight - childBaseline; + childTop -= (mMaxDescent - descent); + } + break; + default: + childTop = mPaddingTop; + } + // Icons that should go at the end if (mIconsAtEnd.contains(child)) { if (end == getMeasuredWidth()) { @@ -179,7 +249,7 @@ public class NotificationTopLineView extends ViewGroup { layoutLeft = getWidth() - layoutRight; layoutRight = getWidth() - ltrLeft; } - child.layout(layoutLeft, top, layoutRight, bottom); + child.layout(layoutLeft, childTop, layoutRight, childTop + childHeight); } updateTouchListener(); } diff --git a/core/java/android/view/OnReceiveContentCallback.java b/core/java/android/view/OnReceiveContentCallback.java index a217ff642ab7..d74938c1d1fd 100644 --- a/core/java/android/view/OnReceiveContentCallback.java +++ b/core/java/android/view/OnReceiveContentCallback.java @@ -19,9 +19,7 @@ package android.view; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.SuppressLint; import android.content.ClipData; -import android.content.ClipDescription; import android.net.Uri; import android.os.Bundle; @@ -30,11 +28,10 @@ import com.android.internal.util.Preconditions; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Objects; -import java.util.Set; /** - * Callback for apps to implement handling for insertion of content. "Content" here refers to both - * text and non-text (plain/styled text, HTML, images, videos, audio files, etc). + * Callback for apps to implement handling for insertion of content. Content may be both text and + * non-text (plain/styled text, HTML, images, videos, audio files, etc). * * <p>This callback can be attached to different types of UI components using * {@link View#setOnReceiveContentCallback}. @@ -45,32 +42,38 @@ import java.util.Set; * * <p>Example implementation:<br> * <pre class="prettyprint"> + * // (1) Define the callback * public class MyOnReceiveContentCallback implements OnReceiveContentCallback<TextView> { - * - * private static final Set<String> SUPPORTED_MIME_TYPES = Collections.unmodifiableSet( + * public static final Set<String> MIME_TYPES = Collections.unmodifiableSet( * Set.of("image/*", "video/*")); * - * @NonNull - * @Override - * public Set<String> getSupportedMimeTypes() { - * return SUPPORTED_MIME_TYPES; - * } - * * @Override * public boolean onReceiveContent(@NonNull TextView view, @NonNull Payload payload) { * // ... app-specific logic to handle the content in the payload ... * } * } + * + * // (2) Register the callback + * public class MyActivity extends Activity { + * @Override + * public void onCreate(Bundle savedInstanceState) { + * // ... + * + * EditText myInput = findViewById(R.id.my_input); + * myInput.setOnReceiveContentCallback( + * MyOnReceiveContentCallback.MIME_TYPES, + * new MyOnReceiveContentCallback()); + * } * </pre> * - * @param <T> The type of {@link View} with which this receiver can be associated. + * @param <T> The type of {@link View} with which this callback can be associated. */ public interface OnReceiveContentCallback<T extends View> { /** * Receive the given content. * - * <p>This function will only be invoked if the MIME type of the content is in the set of - * types returned by {@link #getSupportedMimeTypes}. + * <p>This method is only invoked for content whose MIME type matches a type specified via + * {@link View#setOnReceiveContentCallback}. * * <p>For text, if the view has a selection, the selection should be overwritten by the clip; if * there's no selection, this method should insert the content at the current cursor position. @@ -81,54 +84,14 @@ public interface OnReceiveContentCallback<T extends View> { * @param view The view where the content insertion was requested. * @param payload The content to insert and related metadata. * - * @return Returns true if some or all of the content is accepted for insertion. If accepted, - * actual insertion may be handled asynchronously in the background and may or may not result in - * successful insertion. For example, the app may not end up inserting an accepted item if it + * @return Returns true if the content was handled in some way, false otherwise. Actual + * insertion may be processed asynchronously in the background and may or may not succeed even + * if this method returns true. For example, an app may not end up inserting an item if it * exceeds the app's size limit for that type of content. */ boolean onReceiveContent(@NonNull T view, @NonNull Payload payload); /** - * Returns the MIME types that can be handled by this callback. - * - * <p>The {@link #onReceiveContent} callback method will only be invoked if the MIME type of the - * content is in the set of supported types returned here. - * - * <p>Different platform features (e.g. pasting from the clipboard, inserting stickers from the - * keyboard, etc) may use this function to conditionally alter their behavior. For example, the - * keyboard may choose to hide its UI for inserting GIFs if the input field that has focus has - * a {@link OnReceiveContentCallback} set and the MIME types returned from this function don't - * include "image/gif". - * - * <p><em>Note: MIME type matching in the Android framework is case-sensitive, unlike formal RFC - * MIME types. As a result, you should always write your MIME types with lower case letters, or - * use {@link android.content.Intent#normalizeMimeType} to ensure that it is converted to lower - * case.</em> - * - * @param view The target view. - * @return An immutable set with the MIME types supported by this callback. The returned MIME - * types may contain wildcards such as "text/*", "image/*", etc. - */ - @SuppressLint("CallbackMethodName") - @NonNull - Set<String> getSupportedMimeTypes(@NonNull T view); - - /** - * Returns true if at least one of the MIME types of the given clip is - * {@link #getSupportedMimeTypes supported} by this receiver. - * - * @hide - */ - default boolean supports(@NonNull T view, @NonNull ClipDescription description) { - for (String supportedMimeType : getSupportedMimeTypes(view)) { - if (description.hasMimeType(supportedMimeType)) { - return true; - } - } - return false; - } - - /** * Holds all the relevant data for a request to {@link OnReceiveContentCallback}. */ final class Payload { diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index bda368ecb3a2..ac628e145eee 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -47,6 +47,7 @@ import android.annotation.UiThread; import android.compat.annotation.UnsupportedAppUsage; import android.content.AutofillOptions; import android.content.ClipData; +import android.content.ClipDescription; import android.content.Context; import android.content.ContextWrapper; import android.content.Intent; @@ -143,6 +144,7 @@ import android.widget.ScrollBarDrawable; import com.android.internal.R; import com.android.internal.util.FrameworkStatsLog; +import com.android.internal.util.Preconditions; import com.android.internal.view.ScrollCaptureInternal; import com.android.internal.view.TooltipPopup; import com.android.internal.view.menu.MenuBuilder; @@ -5243,7 +5245,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, int mUnbufferedInputSource = InputDevice.SOURCE_CLASS_NONE; @Nullable - private OnReceiveContentCallback<? extends View> mOnReceiveContentCallback; + private String[] mOnReceiveContentMimeTypes; + @Nullable + private OnReceiveContentCallback mOnReceiveContentCallback; /** * Simple constructor to use when creating a view from code. @@ -9001,36 +9005,78 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** - * Returns the callback used for handling insertion of content into this view. See - * {@link #setOnReceiveContentCallback} for more info. - * - * @return The callback for handling insertion of content. Returns null if no callback has been - * {@link #setOnReceiveContentCallback set}. - */ - @Nullable - public OnReceiveContentCallback<? extends View> getOnReceiveContentCallback() { - return mOnReceiveContentCallback; - } - - /** * Sets the callback to handle insertion of content into this view. * * <p>Depending on the view, this callback may be invoked for scenarios such as content * insertion from the IME, Autofill, etc. * - * <p>The callback will only be invoked if the MIME type of the content is - * {@link OnReceiveContentCallback#getSupportedMimeTypes declared as supported} by the callback. - * If the content type is not supported by the callback, the default platform handling will be - * executed instead. + * <p>This callback is only invoked for content whose MIME type matches a type specified via + * the {code mimeTypes} parameter. If the MIME type is not supported by the callback, the + * default platform handling will be executed instead (no-op for the default {@link View}). * + * <p><em>Note: MIME type matching in the Android framework is case-sensitive, unlike formal RFC + * MIME types. As a result, you should always write your MIME types with lower case letters, or + * use {@link android.content.Intent#normalizeMimeType} to ensure that it is converted to lower + * case.</em> + * + * @param mimeTypes The type of content for which the callback should be invoked. This may use + * wildcards such as "text/*", "image/*", etc. This must not be null or empty if a non-null + * callback is passed in. * @param callback The callback to use. This can be null to reset to the default behavior. */ - public void setOnReceiveContentCallback( - @Nullable OnReceiveContentCallback<? extends View> callback) { + @SuppressWarnings("rawtypes") + public void setOnReceiveContentCallback(@Nullable String[] mimeTypes, + @Nullable OnReceiveContentCallback callback) { + if (callback != null) { + Preconditions.checkArgument(mimeTypes != null && mimeTypes.length > 0, + "When the callback is set, MIME types must also be set"); + } + mOnReceiveContentMimeTypes = mimeTypes; mOnReceiveContentCallback = callback; } /** + * Receives the given content. The default implementation invokes the callback set via + * {@link #setOnReceiveContentCallback}. If no callback is set or if the callback does not + * support the given content (based on the MIME type), returns false. + * + * @param payload The content to insert and related metadata. + * + * @return Returns true if the content was handled in some way, false otherwise. Actual + * insertion may be processed asynchronously in the background and may or may not succeed even + * if this method returns true. For example, an app may not end up inserting an item if it + * exceeds the app's size limit for that type of content. + */ + public boolean onReceiveContent(@NonNull OnReceiveContentCallback.Payload payload) { + ClipDescription description = payload.getClip().getDescription(); + if (mOnReceiveContentCallback != null && mOnReceiveContentMimeTypes != null + && description.hasMimeType(mOnReceiveContentMimeTypes)) { + return mOnReceiveContentCallback.onReceiveContent(this, payload); + } + return false; + } + + /** + * Returns the MIME types that can be handled by {@link #onReceiveContent} for this view, as + * configured via {@link #setOnReceiveContentCallback}. By default returns null. + * + * <p>Different platform features (e.g. pasting from the clipboard, inserting stickers from the + * keyboard, etc) may use this function to conditionally alter their behavior. For example, the + * soft keyboard may choose to hide its UI for inserting GIFs for a particular input field if + * the MIME types returned here for that field don't include "image/gif". + * + * <p>Note: Comparisons of MIME types should be performed using utilities such as + * {@link ClipDescription#compareMimeTypes} rather than simple string equality, in order to + * correctly handle patterns (e.g. "text/*"). + * + * @return The MIME types supported by {@link #onReceiveContent} for this view. The returned + * MIME types may contain wildcards such as "text/*", "image/*", etc. + */ + public @Nullable String[] getOnReceiveContentMimeTypes() { + return mOnReceiveContentMimeTypes; + } + + /** * Automatically fills the content of this view with the {@code value}. * * <p>Views support the Autofill Framework mainly by: diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 9bc07702feee..f1005e91868e 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -1758,7 +1758,6 @@ public final class ViewRootImpl implements ViewParent, destroySurface(); } } - scheduleConsumeBatchedInputImmediately(); } @@ -8314,11 +8313,8 @@ public final class ViewRootImpl implements ViewParent, @Override public void onBatchedInputEventPending(int source) { - // mStopped: There will be no more choreographer callbacks if we are stopped, - // so we must consume all input immediately to prevent ANR final boolean unbuffered = mUnbufferedInputDispatch - || (source & mUnbufferedInputSource) != SOURCE_CLASS_NONE - || mStopped; + || (source & mUnbufferedInputSource) != SOURCE_CLASS_NONE; if (unbuffered) { if (mConsumeBatchedInputScheduled) { unscheduleConsumeBatchedInput(); diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 2cab32b48793..d6c53d0979a0 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -2154,7 +2154,7 @@ public interface WindowManager extends ViewManager { * {@link DragEvent#ACTION_DROP}) will be relinquished to the window. * @hide */ - @RequiresPermission(permission.MANAGE_ACTIVITY_STACKS) + @RequiresPermission(permission.MANAGE_ACTIVITY_TASKS) public static final int PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP = 0x80000000; /** @@ -4069,11 +4069,12 @@ public interface WindowManager extends ViewManager { /** * Holds the WM lock for the specified amount of milliseconds. * Intended for use by the tests that need to imitate lock contention. + * The token should be obtained by + * {@link android.content.pm.PackageManager#getHoldLockToken()}. * @hide */ @TestApi - @RequiresPermission(android.Manifest.permission.INJECT_EVENTS) - default void holdLock(int durationMs) { + default void holdLock(IBinder token, int durationMs) { throw new UnsupportedOperationException(); } } diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java index 7dfae002b554..4292a800afe1 100644 --- a/core/java/android/view/WindowManagerImpl.java +++ b/core/java/android/view/WindowManagerImpl.java @@ -280,9 +280,9 @@ public final class WindowManagerImpl implements WindowManager { } @Override - public void holdLock(int durationMs) { + public void holdLock(IBinder token, int durationMs) { try { - WindowManagerGlobal.getWindowManagerService().holdLock(durationMs); + WindowManagerGlobal.getWindowManagerService().holdLock(token, durationMs); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java index fb66b5298839..81db62857c17 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -19,6 +19,7 @@ package android.view.autofill; import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST; import static android.service.autofill.FillRequest.FLAG_PASSWORD_INPUT_TYPE; import static android.service.autofill.FillRequest.FLAG_VIEW_NOT_FOCUSED; +import static android.view.OnReceiveContentCallback.Payload.SOURCE_AUTOFILL; import static android.view.autofill.Helper.sDebug; import static android.view.autofill.Helper.sVerbose; import static android.view.autofill.Helper.toList; @@ -32,6 +33,7 @@ import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; import android.content.AutofillOptions; +import android.content.ClipData; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -60,6 +62,7 @@ import android.util.Slog; import android.util.SparseArray; import android.view.Choreographer; import android.view.KeyEvent; +import android.view.OnReceiveContentCallback; import android.view.View; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; @@ -2350,6 +2353,49 @@ public final class AutofillManager { } } + private void autofillContent(int sessionId, AutofillId id, ClipData clip) { + synchronized (mLock) { + if (sessionId != mSessionId) { + return; + } + final AutofillClient client = getClient(); + if (client == null) { + return; + } + final View view = client.autofillClientFindViewByAutofillIdTraversal(id); + if (view == null) { + // Most likely view has been removed after the initial request was sent to the + // the service; this is fine, but we need to update the view status in the + // server side so it can be triggered again. + Log.d(TAG, "autofillContent(): no view with id " + id); + reportAutofillContentFailure(id); + return; + } + OnReceiveContentCallback.Payload payload = + new OnReceiveContentCallback.Payload.Builder(clip, SOURCE_AUTOFILL) + .build(); + boolean handled = view.onReceiveContent(payload); + if (!handled) { + Log.w(TAG, "autofillContent(): receiver returned false: id=" + id + + ", view=" + view + ", clip=" + clip); + reportAutofillContentFailure(id); + return; + } + mMetricsLogger.write(newLog(MetricsEvent.AUTOFILL_DATASET_APPLIED) + .addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_VALUES, 1) + .addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_VIEWS_FILLED, 1)); + } + } + + private void reportAutofillContentFailure(AutofillId id) { + try { + mService.setAutofillFailure(mSessionId, Collections.singletonList(id), + mContext.getUserId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + private LogMaker newLog(int category) { final LogMaker log = new LogMaker(category) .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SESSION_ID, mSessionId); @@ -3391,6 +3437,14 @@ public final class AutofillManager { } @Override + public void autofillContent(int sessionId, AutofillId id, ClipData content) { + final AutofillManager afm = mAfm.get(); + if (afm != null) { + afm.post(() -> afm.autofillContent(sessionId, id, content)); + } + } + + @Override public void authenticate(int sessionId, int authenticationId, IntentSender intent, Intent fillInIntent, boolean authenticateInline) { final AutofillManager afm = mAfm.get(); diff --git a/core/java/android/view/autofill/IAutoFillManagerClient.aidl b/core/java/android/view/autofill/IAutoFillManagerClient.aidl index f8ccea5d8356..1f833f66c257 100644 --- a/core/java/android/view/autofill/IAutoFillManagerClient.aidl +++ b/core/java/android/view/autofill/IAutoFillManagerClient.aidl @@ -18,6 +18,7 @@ package android.view.autofill; import java.util.List; +import android.content.ClipData; import android.content.ComponentName; import android.content.Intent; import android.content.IntentSender; @@ -48,6 +49,11 @@ oneway interface IAutoFillManagerClient { boolean hideHighlight); /** + * Autofills the activity with rich content data (e.g. an image) from a dataset. + */ + void autofillContent(int sessionId, in AutofillId id, in ClipData content); + + /** * Authenticates a fill response or a data set. */ void authenticate(int sessionId, int authenticationId, in IntentSender intent, diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java index e0711132f459..093dfb4e196e 100644 --- a/core/java/android/view/inputmethod/BaseInputConnection.java +++ b/core/java/android/view/inputmethod/BaseInputConnection.java @@ -22,6 +22,7 @@ import android.annotation.CallSuper; import android.annotation.IntRange; import android.annotation.Nullable; import android.content.ClipData; +import android.content.ClipDescription; import android.content.Context; import android.content.res.TypedArray; import android.os.Bundle; @@ -918,23 +919,18 @@ public class BaseInputConnection implements InputConnection { } /** - * Default implementation which invokes the target view's {@link OnReceiveContentCallback} if - * it is {@link View#setOnReceiveContentCallback set} and supports the MIME type of the given - * content; otherwise, simply returns false. + * Default implementation which invokes {@link View#onReceiveContent} on the target view if the + * MIME type of the content matches one of the MIME types returned by + * {@link View#getOnReceiveContentMimeTypes()}. If the MIME type of the content is not matched, + * returns false without any side effects. */ public boolean commitContent(InputContentInfo inputContentInfo, int flags, Bundle opts) { - @SuppressWarnings("unchecked") final OnReceiveContentCallback<View> receiver = - (OnReceiveContentCallback<View>) mTargetView.getOnReceiveContentCallback(); - if (receiver == null) { + ClipDescription description = inputContentInfo.getDescription(); + final String[] viewMimeTypes = mTargetView.getOnReceiveContentMimeTypes(); + if (viewMimeTypes == null || !description.hasMimeType(viewMimeTypes)) { if (DEBUG) { - Log.d(TAG, "Can't insert content from IME; no callback"); - } - return false; - } - if (!receiver.supports(mTargetView, inputContentInfo.getDescription())) { - if (DEBUG) { - Log.d(TAG, "Can't insert content from IME; callback doesn't support MIME type: " - + inputContentInfo.getDescription()); + Log.d(TAG, "Can't insert content from IME; unsupported MIME type: content=" + + description + ", viewMimeTypes=" + viewMimeTypes); } return false; } @@ -946,13 +942,13 @@ public class BaseInputConnection implements InputConnection { return false; } } - final ClipData clip = new ClipData(inputContentInfo.getDescription(), + final ClipData clip = new ClipData(description, new ClipData.Item(inputContentInfo.getContentUri())); final OnReceiveContentCallback.Payload payload = new OnReceiveContentCallback.Payload.Builder(clip, SOURCE_INPUT_METHOD) .setLinkUri(inputContentInfo.getLinkUri()) .setExtras(opts) .build(); - return receiver.onReceiveContent(mTargetView, payload); + return mTargetView.onReceiveContent(payload); } } diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 3fc0f4efd608..5280a48596b4 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -8747,12 +8747,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener outAttrs.initialSelEnd = getSelectionEnd(); outAttrs.initialCapsMode = ic.getCursorCapsMode(getInputType()); outAttrs.setInitialSurroundingText(mText); - // If a custom `OnReceiveContentCallback` is set, pass its supported MIME types. - OnReceiveContentCallback<TextView> receiver = getOnReceiveContentCallback(); - if (receiver != null) { - outAttrs.contentMimeTypes = receiver.getSupportedMimeTypes(this) - .toArray(new String[0]); - } + outAttrs.contentMimeTypes = getOnReceiveContentMimeTypes(); return ic; } } @@ -13735,20 +13730,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } /** - * Returns the callback used for handling insertion of content into this view. See - * {@link #setOnReceiveContentCallback} for more info. - * - * @return The callback for handling insertion of content. Returns null if no callback has been - * {@link #setOnReceiveContentCallback set}. - */ - @SuppressWarnings("unchecked") - @Nullable - @Override - public OnReceiveContentCallback<TextView> getOnReceiveContentCallback() { - return (OnReceiveContentCallback<TextView>) super.getOnReceiveContentCallback(); - } - - /** * Sets the callback to handle insertion of content into this view. * * <p>This callback will be invoked for the following scenarios: @@ -13761,32 +13742,51 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * <li>{@link Intent#ACTION_PROCESS_TEXT} replacement * </ol> * - * <p>The callback will only be invoked if the MIME type of the content is - * {@link OnReceiveContentCallback#getSupportedMimeTypes declared as supported} by the callback. - * If the content type is not supported by the callback, the default platform handling will be - * executed instead. + * <p>This callback is only invoked for content whose MIME type matches a type specified via + * the {code mimeTypes} parameter. If the MIME type is not supported by the callback, the + * default platform handling will be executed instead (no-op for the default {@link View}). + * + * <p><em>Note: MIME type matching in the Android framework is case-sensitive, unlike formal RFC + * MIME types. As a result, you should always write your MIME types with lower case letters, or + * use {@link android.content.Intent#normalizeMimeType} to ensure that it is converted to lower + * case.</em> * + * @param mimeTypes The type of content for which the callback should be invoked. This may use + * wildcards such as "text/*", "image/*", etc. This must not be null or empty if a non-null + * callback is passed in. * @param callback The callback to use. This can be null to reset to the default behavior. */ + @SuppressWarnings("rawtypes") @Override public void setOnReceiveContentCallback( - @Nullable OnReceiveContentCallback<? extends View> callback) { - super.setOnReceiveContentCallback(callback); + @Nullable String[] mimeTypes, + @Nullable OnReceiveContentCallback callback) { + super.setOnReceiveContentCallback(mimeTypes, callback); } /** - * Handles the request to insert content using the configured callback or the default callback. + * Receives the given content. The default implementation invokes the callback set via + * {@link #setOnReceiveContentCallback}. If no callback is set or if the callback does not + * support the given content (based on the MIME type), executes the default platform handling + * (e.g. coerces content to text if the source is + * {@link OnReceiveContentCallback.Payload#SOURCE_CLIPBOARD} and this is an editable + * {@link TextView}). * - * @hide + * @param payload The content to insert and related metadata. + * + * @return Returns true if the content was handled in some way, false otherwise. Actual + * insertion may be processed asynchronously in the background and may or may not succeed even + * if this method returns true. For example, an app may not end up inserting an item if it + * exceeds the app's size limit for that type of content. */ - void onReceiveContent(@NonNull OnReceiveContentCallback.Payload payload) { - OnReceiveContentCallback<TextView> receiver = getOnReceiveContentCallback(); - ClipDescription description = payload.getClip().getDescription(); - if (receiver != null && receiver.supports(this, description)) { - receiver.onReceiveContent(this, payload); + @Override + public boolean onReceiveContent(@NonNull OnReceiveContentCallback.Payload payload) { + if (super.onReceiveContent(payload)) { + return true; } else if (mEditor != null) { - mEditor.getDefaultOnReceiveContentCallback().onReceiveContent(this, payload); + return mEditor.getDefaultOnReceiveContentCallback().onReceiveContent(this, payload); } + return false; } private static void logCursor(String location, @Nullable String msgFormat, Object ... msgArgs) { diff --git a/core/java/android/widget/TextViewOnReceiveContentCallback.java b/core/java/android/widget/TextViewOnReceiveContentCallback.java index d7c95b7eae86..7ed70ec18a7b 100644 --- a/core/java/android/widget/TextViewOnReceiveContentCallback.java +++ b/core/java/android/widget/TextViewOnReceiveContentCallback.java @@ -20,12 +20,12 @@ import static android.content.ContentResolver.SCHEME_CONTENT; import static android.view.OnReceiveContentCallback.Payload.FLAG_CONVERT_TO_PLAIN_TEXT; import static android.view.OnReceiveContentCallback.Payload.SOURCE_AUTOFILL; import static android.view.OnReceiveContentCallback.Payload.SOURCE_DRAG_AND_DROP; +import static android.view.OnReceiveContentCallback.Payload.SOURCE_INPUT_METHOD; import static java.util.Collections.singleton; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.SuppressLint; import android.compat.Compatibility; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledAfter; @@ -72,16 +72,6 @@ public class TextViewOnReceiveContentCallback implements OnReceiveContentCallbac @Nullable private InputConnectionInfo mInputConnectionInfo; @Nullable private ArraySet<String> mCachedSupportedMimeTypes; - @SuppressLint("CallbackMethodName") - @NonNull - @Override - public Set<String> getSupportedMimeTypes(@NonNull TextView view) { - if (!isUsageOfImeCommitContentEnabled(view)) { - return MIME_TYPES_ALL_TEXT; - } - return getSupportedMimeTypesAugmentedWithImeCommitContentMimeTypes(); - } - @Override public boolean onReceiveContent(@NonNull TextView view, @NonNull Payload payload) { if (Log.isLoggable(LOG_TAG, Log.DEBUG)) { @@ -90,6 +80,11 @@ public class TextViewOnReceiveContentCallback implements OnReceiveContentCallbac ClipData clip = payload.getClip(); @Source int source = payload.getSource(); @Flags int flags = payload.getFlags(); + if (source == SOURCE_INPUT_METHOD) { + // InputConnection.commitContent() should only be used for non-text input which is not + // supported by the default implementation. + return false; + } if (source == SOURCE_AUTOFILL) { return onReceiveForAutofill(view, clip, flags); } @@ -123,7 +118,7 @@ public class TextViewOnReceiveContentCallback implements OnReceiveContentCallbac } } } - return true; + return didFirst; } private static void replaceSelection(@NonNull Editable editable, @@ -160,7 +155,7 @@ public class TextViewOnReceiveContentCallback implements OnReceiveContentCallbac @NonNull ClipData clip, @Flags int flags) { final CharSequence text = coerceToText(clip, textView.getContext(), flags); if (text.length() == 0) { - return true; + return false; } replaceSelection((Editable) textView.getText(), text); return true; @@ -205,7 +200,7 @@ public class TextViewOnReceiveContentCallback implements OnReceiveContentCallbac * non-text content. */ private static boolean isUsageOfImeCommitContentEnabled(@NonNull View view) { - if (view.getOnReceiveContentCallback() != null) { + if (view.getOnReceiveContentMimeTypes() != null) { if (Log.isLoggable(LOG_TAG, Log.VERBOSE)) { Log.v(LOG_TAG, "Fallback to commitContent disabled (custom callback is set)"); } @@ -267,6 +262,17 @@ public class TextViewOnReceiveContentCallback implements OnReceiveContentCallbac mInputConnectionInfo = null; } + // TODO(b/168253885): Use this to populate the assist structure for Autofill + + /** @hide */ + @VisibleForTesting + public Set<String> getMimeTypes(TextView view) { + if (!isUsageOfImeCommitContentEnabled(view)) { + return MIME_TYPES_ALL_TEXT; + } + return getSupportedMimeTypesAugmentedWithImeCommitContentMimeTypes(); + } + private Set<String> getSupportedMimeTypesAugmentedWithImeCommitContentMimeTypes() { InputConnectionInfo icInfo = mInputConnectionInfo; if (icInfo == null) { @@ -291,7 +297,8 @@ public class TextViewOnReceiveContentCallback implements OnReceiveContentCallbac } /** - * We want to avoid creating a new set on every invocation of {@link #getSupportedMimeTypes}. + * We want to avoid creating a new set on every invocation of + * {@link #getSupportedMimeTypesAugmentedWithImeCommitContentMimeTypes()}. * This method will check if the cached set of MIME types matches the data in the given array * from {@link EditorInfo} or if a new set should be created. The custom logic is needed for * comparing the data because the set contains the additional "text/*" MIME type. diff --git a/core/java/android/window/DisplayAreaOrganizer.java b/core/java/android/window/DisplayAreaOrganizer.java index 78fa30358d74..38b2190a57f3 100644 --- a/core/java/android/window/DisplayAreaOrganizer.java +++ b/core/java/android/window/DisplayAreaOrganizer.java @@ -84,7 +84,7 @@ public class DisplayAreaOrganizer extends WindowOrganizer { */ public static final int FEATURE_VENDOR_FIRST = FEATURE_SYSTEM_LAST + 1; - @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void registerOrganizer(int displayAreaFeature) { try { getController().registerOrganizer(mInterface, displayAreaFeature); @@ -96,7 +96,7 @@ public class DisplayAreaOrganizer extends WindowOrganizer { /** * @hide */ - @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void unregisterOrganizer() { try { getController().unregisterOrganizer(mInterface); diff --git a/core/java/android/window/TaskOrganizer.java b/core/java/android/window/TaskOrganizer.java index ad48a9f9f776..4e209206f233 100644 --- a/core/java/android/window/TaskOrganizer.java +++ b/core/java/android/window/TaskOrganizer.java @@ -62,7 +62,7 @@ public class TaskOrganizer extends WindowOrganizer { * @return a list of the tasks that should be managed by the organizer, not including tasks * created via {@link #createRootTask}. */ - @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) @CallSuper @NonNull public List<TaskAppearedInfo> registerOrganizer() { @@ -74,7 +74,7 @@ public class TaskOrganizer extends WindowOrganizer { } /** Unregisters a previously registered task organizer. */ - @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) @CallSuper public void unregisterOrganizer() { try { @@ -109,7 +109,7 @@ public class TaskOrganizer extends WindowOrganizer { * @param launchCookie Launch cookie to associate with the task so that is can be identified * when the {@link ITaskOrganizer#onTaskAppeared} callback is called. */ - @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) @Nullable public void createRootTask(int displayId, int windowingMode, @Nullable IBinder launchCookie) { try { @@ -120,7 +120,7 @@ public class TaskOrganizer extends WindowOrganizer { } /** Deletes a persistent root task in WM */ - @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public boolean deleteRootTask(@NonNull WindowContainerToken task) { try { return mTaskOrganizerController.deleteRootTask(task); @@ -130,7 +130,7 @@ public class TaskOrganizer extends WindowOrganizer { } /** Gets direct child tasks (ordered from top-to-bottom) */ - @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) @Nullable public List<ActivityManager.RunningTaskInfo> getChildTasks( @NonNull WindowContainerToken parent, @NonNull int[] activityTypes) { @@ -142,7 +142,7 @@ public class TaskOrganizer extends WindowOrganizer { } /** Gets all root tasks on a display (ordered from top-to-bottom) */ - @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) @Nullable public List<ActivityManager.RunningTaskInfo> getRootTasks( int displayId, @NonNull int[] activityTypes) { @@ -154,7 +154,7 @@ public class TaskOrganizer extends WindowOrganizer { } /** Get the root task which contains the current ime target */ - @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) @Nullable public WindowContainerToken getImeTarget(int display) { try { @@ -168,7 +168,7 @@ public class TaskOrganizer extends WindowOrganizer { * Set's the root task to launch new tasks into on a display. {@code null} means no launch * root and thus new tasks just end up directly on the display. */ - @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void setLaunchRoot(int displayId, @NonNull WindowContainerToken root) { try { mTaskOrganizerController.setLaunchRoot(displayId, root); @@ -181,7 +181,7 @@ public class TaskOrganizer extends WindowOrganizer { * Requests that the given task organizer is notified when back is pressed on the root activity * of one of its controlled tasks. */ - @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void setInterceptBackPressedOnTaskRoot(@NonNull WindowContainerToken task, boolean interceptBackPressed) { try { diff --git a/core/java/android/window/WindowOrganizer.java b/core/java/android/window/WindowOrganizer.java index 5ac19fa685d7..bb03e2829715 100644 --- a/core/java/android/window/WindowOrganizer.java +++ b/core/java/android/window/WindowOrganizer.java @@ -39,7 +39,7 @@ public class WindowOrganizer { * Apply multiple WindowContainer operations at once. * @param t The transaction to apply. */ - @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void applyTransaction(@NonNull WindowContainerTransaction t) { try { getWindowOrganizerController().applyTransaction(t); @@ -57,7 +57,7 @@ public class WindowOrganizer { * @return An ID for the sync operation which will later be passed to transactionReady callback. * This lets the caller differentiate overlapping sync operations. */ - @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public int applySyncTransaction(@NonNull WindowContainerTransaction t, @NonNull WindowContainerTransactionCallback callback) { try { @@ -76,7 +76,7 @@ public class WindowOrganizer { * was provided. * @hide */ - @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) @NonNull public IBinder startTransition(int type, @Nullable IBinder transitionToken, @Nullable WindowContainerTransaction t) { @@ -97,7 +97,7 @@ public class WindowOrganizer { * @hide */ @SuppressLint("ExecutorRegistration") - @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public int finishTransition(@NonNull IBinder transitionToken, @Nullable WindowContainerTransaction t, @Nullable WindowContainerTransactionCallback callback) { @@ -135,7 +135,7 @@ public class WindowOrganizer { * Register an ITransitionPlayer to handle transition animations. * @hide */ - @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void registerTransitionPlayer(@Nullable ITransitionPlayer player) { try { getWindowOrganizerController().registerTransitionPlayer(player); @@ -144,7 +144,7 @@ public class WindowOrganizer { } } - @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) IWindowOrganizerController getWindowOrganizerController() { return IWindowOrganizerControllerSingleton.get(); } diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl index 77c7ce8cf5c4..b9c2fd532d0f 100644 --- a/core/java/com/android/internal/statusbar/IStatusBar.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl @@ -145,8 +145,8 @@ oneway interface IStatusBar // Used to show the authentication dialog (Biometrics, Device Credential) void showAuthenticationDialog(in PromptInfo promptInfo, IBiometricSysuiReceiver sysuiReceiver, - int biometricModality, boolean requireConfirmation, int userId, String opPackageName, - long operationId); + in int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation, int userId, + String opPackageName, long operationId); // Used to notify the authentication dialog that a biometric has been authenticated void onBiometricAuthenticated(); // Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl index bcbbf6e98dae..bb0fd7fb8c23 100644 --- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl @@ -106,8 +106,9 @@ interface IStatusBarService // Used to show the authentication dialog (Biometrics, Device Credential) void showAuthenticationDialog(in PromptInfo promptInfo, IBiometricSysuiReceiver sysuiReceiver, - int biometricModality, boolean requireConfirmation, int userId, String opPackageName, - long operationId); + in int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation, + int userId, String opPackageName,long operationId); + // Used to notify the authentication dialog that a biometric has been authenticated void onBiometricAuthenticated(); // Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc diff --git a/core/jni/android_view_InputEventReceiver.md b/core/jni/android_view_InputEventReceiver.md new file mode 100644 index 000000000000..7df346139a4d --- /dev/null +++ b/core/jni/android_view_InputEventReceiver.md @@ -0,0 +1,49 @@ +# Batched consumption # + +Most apps draw once per vsync. Therefore, apps can only respond to 1 input event per frame. If multiple input events come in during the period of 1 vsync, it would be wasteful to deliver them all at once to the app. For this reason, input events are batched to only deliver 1 event per frame to the app. + +The batching process works in the following manner: + +1. `InputDispatcher` sends an event to the app +2. The app's `Looper` is notified about the available event. +3. The `handleEvent` callback is executed. Events are read from fd. +4. If a batched input event is available, `InputConsumer::hasPendingBatch` returns true. No event is sent to the app at this point. +5. The app is notified that a batched event is available for consumption, and schedules a runnable via the `Choreographer` to consume it a short time before the next frame +6. When the scheduled runnable is executed, it doesn't just consume the batched input. It proactively tries to consume everything that has come in to the socket. +7. The batched event is sent to the app, along with any of the other events that have come in. + +Let's discuss the specifics of some of these steps. + +## 1. Consuming events in `handleEvent` callback ## + +The app is notified about the available event via the `Looper` callback `handleEvent`. When the app's input socket becomes readable (e.g., it has unread events), the looper will execute `handleEvent`. At this point, the app is expected to read in the events that have come in to the socket. The function `handleEvent` will continue to trigger as long as there are unread events in the socket. Thus, the app could choose to read events 1 at a time, or all at once. If there are no more events in the app's socket, handleEvent will no longer execute. + +Even though it is perfectly valid for the app to read events 1 at a time, it is more efficient to read them all at once. Therefore, whenever the events are available, the app will try to completely drain the socket. + +To consume the events inside `handleEvent`, the app calls `InputConsumer::consume(.., consumeBatches=false, frameTime=-1, ..)`. That is, when `handleEvent` runs, there is no information about the upcoming frameTime, and we dont want to consume the batches because there may be other events that come in before the 'consume batched input' runnable runs. + +If a batched event comes in at this point (typically, any MOVE event that has source = TOUCHSCREEN), the `consume` function above would actually return a `NULL` event with status `WOULD_BLOCK`. When this happens, the caller (`NativeInputEventReceiver`) is responsible for checking whether `InputConsumer::hasPendingBatch` is set to true. If so, the caller is responsible for scheduling a runnable to consume these batched events. + +## 2. Consuming batched events ## + +In the previous section, we learned that the app can read events inside the `handleEvent` callback. The other time when the app reads events is when the 'consume batched input' runnable is executed. This runnable is scheduled via the Choreographer by requesting a `CALLBACK_INPUT` event. + +Before the batched events are consumed, the socket is drained once again. This is an optimization. + +To consume the events inside 'consume batched input' runnable, the app calls `InputConsumer::consume(.., consumeBatches=true, frameTime=<valid frame time>, ..)`. At this point, the `consume` function will return all batched events up to the `frameTime` point. There may be batched events remaining. + +## 3. Key points ## + +Some of the behaviours above should be highlighted, because they may be unexpected. + +1. Even if events have been read by `InputConsumer`, `consume` will return `NULL` event with status `WOULD_BLOCK` if those events caused a new batch to be started. + +2. Events are read from the fd outside of the regular `handleEvent` case, during batched consumption. + +3. The function `handleEvent` will always execute as long as there are unread events in the fd + +4. The `consume` function is called in 1 of 2 possible ways: + - `consumeBatches=false, frameTime=-1` + - `consumeBatches=true, frameTime=<valid time>` + + I.e., it is never called with `consumeBatches=true, frameTime=-1`. diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto index 16a691c9c4ec..9291a90574cd 100644 --- a/core/proto/android/providers/settings/global.proto +++ b/core/proto/android/providers/settings/global.proto @@ -510,7 +510,7 @@ message GlobalSettingsProto { optional IntentFirewall intent_firewall = 65; reserved 66; // job_scheduler_constants - optional SettingProto job_scheduler_quota_controller_constants = 149 [ (android.privacy).dest = DEST_AUTOMATIC ]; + reserved 149; // job_scheduler_quota_controller_constants reserved 150; // job_scheduler_time_controller_constants optional SettingProto keep_profile_in_background = 67 [ (android.privacy).dest = DEST_AUTOMATIC ]; diff --git a/core/proto/android/stats/tls/enums.proto b/core/proto/android/stats/tls/enums.proto new file mode 100644 index 000000000000..0ae87ee1d89b --- /dev/null +++ b/core/proto/android/stats/tls/enums.proto @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +syntax = "proto2"; +package android.stats.tls; + +// Keep in sync with +// external/conscrypt/{android,platform}/src/main/java/org/conscrypt/Platform.java +enum Protocol { + UNKNOWN_PROTO = 0; + SSLv3 = 1; + TLSv1 = 2; + TLSv1_1 = 3; + TLSv1_2 = 4; + TLSv1_3 = 5; +} + +// Cipher suites' ids are based on IANA's database: +// https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4 +// +// If you add new cipher suite, make sure id is the same as in IANA's database (see link above) +// +// Keep in sync with +// external/conscrypt/{android,platform}/src/main/java/org/conscrypt/Platform.java +enum CipherSuite { + UNKNOWN_CIPHER_SUITE = 0x0000; + + TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = 0xC00A; + TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = 0xC014; + TLS_RSA_WITH_AES_256_CBC_SHA = 0x0035; + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = 0xC009; + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = 0xC013; + TLS_RSA_WITH_AES_128_CBC_SHA = 0x002F; + TLS_RSA_WITH_3DES_EDE_CBC_SHA = 0x000A; + + // TLSv1.2 cipher suites + TLS_RSA_WITH_AES_128_GCM_SHA256 = 0x009C; + TLS_RSA_WITH_AES_256_GCM_SHA384 = 0x009D; + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = 0xC02F; + TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = 0xC030; + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 = 0xC02B; + TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = 0xC02C; + TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCCA9; + TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCCA8; + + // Pre-Shared Key (PSK) cipher suites + TLS_PSK_WITH_AES_128_CBC_SHA = 0x008C; + TLS_PSK_WITH_AES_256_CBC_SHA = 0x008D; + TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA = 0xC035; + TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA = 0xC036; + TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 = 0xCCAC; + + // TLS 1.3 cipher suites + TLS_AES_128_GCM_SHA256 = 0x1301; + TLS_AES_256_GCM_SHA384 = 0x1302; + TLS_CHACHA20_POLY1305_SHA256 = 0x1303; +} + diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 8a7fa04b3cf4..3248cfedb523 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -349,6 +349,7 @@ <protected-broadcast android:name="com.android.server.WifiManager.action.START_PNO" /> <protected-broadcast android:name="com.android.server.WifiManager.action.DELAYED_DRIVER_STOP" /> <protected-broadcast android:name="com.android.server.WifiManager.action.DEVICE_IDLE" /> + <protected-broadcast android:name="com.android.server.action.REMOTE_BUGREPORT_DISPATCH" /> <protected-broadcast android:name="com.android.server.action.REMOTE_BUGREPORT_SHARING_ACCEPTED" /> <protected-broadcast android:name="com.android.server.action.REMOTE_BUGREPORT_SHARING_DECLINED" /> <protected-broadcast android:name="com.android.internal.action.EUICC_FACTORY_RESET" /> @@ -668,6 +669,10 @@ <!-- For tether entitlement recheck--> <protected-broadcast android:name="com.android.server.connectivity.tethering.PROVISIONING_RECHECK_ALARM" /> + + <!-- Made protected in S (was added in R) --> + <protected-broadcast android:name="com.android.internal.intent.action.BUGREPORT_REQUESTED" /> + <!-- ====================================================================== --> <!-- RUNTIME PERMISSIONS --> <!-- ====================================================================== --> @@ -2530,10 +2535,15 @@ <permission android:name="android.permission.REMOVE_TASKS" android:protectionLevel="signature|documenter" /> - <!-- @SystemApi @TestApi @hide Allows an application to create/manage/remove stacks --> + <!-- @deprecated Use MANAGE_ACTIVITY_TASKS instead. + @SystemApi @TestApi @hide Allows an application to create/manage/remove stacks --> <permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" android:protectionLevel="signature" /> + <!-- @SystemApi @TestApi @hide Allows an application to create/manage/remove tasks --> + <permission android:name="android.permission.MANAGE_ACTIVITY_TASKS" + android:protectionLevel="signature" /> + <!-- @SystemApi @TestApi @hide Allows an application to embed other activities --> <permission android:name="android.permission.ACTIVITY_EMBEDDING" android:protectionLevel="signature|privileged" /> @@ -5155,6 +5165,12 @@ <permission android:name="android.permission.INPUT_CONSUMER" android:protectionLevel="signature" /> + <!-- @hide Allows an application to control the system's device state managed by the + {@link android.service.devicestate.DeviceStateManagerService}. For example, on foldable + devices this would grant access to toggle between the folded and unfolded states. --> + <permission android:name="android.permission.CONTROL_DEVICE_STATE" + android:protectionLevel="signature" /> + <!-- Attribution for Geofencing service. --> <attribution android:tag="GeofencingService" android:label="@string/geofencing_service"/> <!-- Attribution for Country Detector. --> diff --git a/core/res/res/layout/notification_material_action_list.xml b/core/res/res/layout/notification_material_action_list.xml index df271f0f2942..ffb9603529c2 100644 --- a/core/res/res/layout/notification_material_action_list.xml +++ b/core/res/res/layout/notification_material_action_list.xml @@ -28,6 +28,7 @@ android:gravity="end" android:orientation="horizontal" android:paddingEnd="@dimen/bubble_gone_padding_end" + android:background="@color/notification_action_list_background_color" > <com.android.internal.widget.NotificationActionListLayout @@ -38,7 +39,6 @@ android:orientation="horizontal" android:gravity="center_vertical" android:visibility="gone" - android:background="@color/notification_action_list_background_color" > <!-- actions will be added here --> </com.android.internal.widget.NotificationActionListLayout> diff --git a/core/res/res/layout/notification_template_material_base.xml b/core/res/res/layout/notification_template_material_base.xml index 221bcf6a800c..34c7fa734f21 100644 --- a/core/res/res/layout/notification_template_material_base.xml +++ b/core/res/res/layout/notification_template_material_base.xml @@ -39,10 +39,6 @@ android:layout_height="@dimen/notification_progress_bar_height" android:layout_marginTop="@dimen/notification_progress_margin_top" layout="@layout/notification_template_progress" /> - <include layout="@layout/notification_template_smart_reply_container" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/notification_content_margin" /> </LinearLayout> <include layout="@layout/notification_template_right_icon" /> </FrameLayout> diff --git a/core/res/res/layout/notification_template_top_line.xml b/core/res/res/layout/notification_template_top_line.xml index 27fab859a045..0786e138559f 100644 --- a/core/res/res/layout/notification_template_top_line.xml +++ b/core/res/res/layout/notification_template_top_line.xml @@ -102,9 +102,8 @@ android:id="@+id/alerted_icon" android:layout_width="@dimen/notification_alerted_size" android:layout_height="@dimen/notification_alerted_size" - android:layout_gravity="center" android:layout_marginStart="4dp" - android:paddingTop="1dp" + android:baseline="10dp" android:scaleType="fitCenter" android:visibility="gone" android:contentDescription="@string/notification_alerted_content_description" @@ -116,8 +115,7 @@ android:layout_height="@dimen/notification_feedback_size" android:layout_marginStart="6dp" android:layout_marginEnd="6dp" - android:paddingTop="2dp" - android:layout_gravity="center" + android:baseline="10dp" android:scaleType="fitCenter" android:src="@drawable/ic_feedback_indicator" android:background="?android:selectableItemBackgroundBorderless" @@ -128,9 +126,8 @@ android:id="@+id/profile_badge" android:layout_width="@dimen/notification_badge_size" android:layout_height="@dimen/notification_badge_size" - android:layout_gravity="center" android:layout_marginStart="4dp" - android:paddingTop="1dp" + android:baseline="10dp" android:scaleType="fitCenter" android:visibility="gone" android:contentDescription="@string/notification_work_profile_content_description" diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index 747ecb353e6d..31993fb5860d 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"AF"</string> <string name="checked" msgid="9179896827054513119">"gemerk"</string> <string name="not_checked" msgid="7972320087569023342">"nie gemerk nie"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"gekies"</string> + <string name="not_selected" msgid="410652016565864475">"nie gekies nie"</string> <string name="whichApplication" msgid="5432266899591255759">"Voltooi handeling met"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Voltooi handeling met gebruik van %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Voltooi handeling"</string> diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index 4142a5c6f71e..dee3521a1b2e 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"ውጪ"</string> <string name="checked" msgid="9179896827054513119">"ምልክት ተደርጎበታል"</string> <string name="not_checked" msgid="7972320087569023342">"ምልክት አልተደረገበትም"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"ተመርጧል"</string> + <string name="not_selected" msgid="410652016565864475">"አልተመረጠም"</string> <string name="whichApplication" msgid="5432266899591255759">"... በመጠቀም ድርጊቱን አጠናቅ"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$sን ተጠቅመው እርምጃ ያጠናቅቁ"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"እርምጃውን አጠናቅቅ"</string> diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index 8ec3140d7e75..905d2ddad1db 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -1209,10 +1209,8 @@ <string name="capital_off" msgid="7443704171014626777">"إيقاف"</string> <string name="checked" msgid="9179896827054513119">"تم وضع علامة"</string> <string name="not_checked" msgid="7972320087569023342">"لم يتم وضع علامة"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"محدّد"</string> + <string name="not_selected" msgid="410652016565864475">"غير محدّد"</string> <string name="whichApplication" msgid="5432266899591255759">"إكمال الإجراء باستخدام"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"إكمال الإجراء باستخدام %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"إكمال الإجراء"</string> diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml index d142b6bb2e2d..e58274cedf89 100644 --- a/core/res/res/values-as/strings.xml +++ b/core/res/res/values-as/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"অফ কৰক"</string> <string name="checked" msgid="9179896827054513119">"টিক চিহ্ন দিয়া হৈছে"</string> <string name="not_checked" msgid="7972320087569023342">"টিক চিহ্ন দিয়া হোৱা নাই"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"বাছনি কৰা"</string> + <string name="not_selected" msgid="410652016565864475">"বাছনি কৰা হোৱা নাই"</string> <string name="whichApplication" msgid="5432266899591255759">"এয়া ব্যৱহাৰ কৰি কার্য সম্পূর্ণ কৰক"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ব্যৱহাৰ কৰি কাৰ্যটো সম্পূৰ্ণ কৰক"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"কাৰ্য সম্পূৰ্ণ কৰক"</string> diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml index 0db22cc6b46a..499cd202b8ea 100644 --- a/core/res/res/values-az/strings.xml +++ b/core/res/res/values-az/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"QAPALI"</string> <string name="checked" msgid="9179896827054513119">"yoxlanılıb"</string> <string name="not_checked" msgid="7972320087569023342">"yoxlanılmayıb"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"seçilib"</string> + <string name="not_selected" msgid="410652016565864475">"seçilməyib"</string> <string name="whichApplication" msgid="5432266899591255759">"Əməliyyatı tamamlayın:"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s istifadə edərək əməliyyatı tamamlayın"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Əməliyyatı tamamlayın"</string> diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml index a21090218a5e..5e264537c2b0 100644 --- a/core/res/res/values-b+sr+Latn/strings.xml +++ b/core/res/res/values-b+sr+Latn/strings.xml @@ -1149,10 +1149,8 @@ <string name="capital_off" msgid="7443704171014626777">"NE"</string> <string name="checked" msgid="9179896827054513119">"označeno je"</string> <string name="not_checked" msgid="7972320087569023342">"nije označeno"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"izabrano"</string> + <string name="not_selected" msgid="410652016565864475">"nije izabrano"</string> <string name="whichApplication" msgid="5432266899591255759">"Dovrši radnju preko"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Završite radnju pomoću aplikacije %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Završi radnju"</string> diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml index 38da725b342a..d6a725706433 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/strings.xml @@ -1169,10 +1169,8 @@ <string name="capital_off" msgid="7443704171014626777">"Выключана"</string> <string name="checked" msgid="9179896827054513119">"пазначана"</string> <string name="not_checked" msgid="7972320087569023342">"не пазначана"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"выбраны"</string> + <string name="not_selected" msgid="410652016565864475">"не выбраны"</string> <string name="whichApplication" msgid="5432266899591255759">"Завяршыць дзеянне з дапамогай"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Завяршыць дзеянне з дапамогай %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Завяршыць дзеянне"</string> diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index 3fca6eb686f6..376ef26412ff 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"ИЗКЛ"</string> <string name="checked" msgid="9179896827054513119">"с отметка"</string> <string name="not_checked" msgid="7972320087569023342">"без отметка"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"избрано"</string> + <string name="not_selected" msgid="410652016565864475">"не е избрано"</string> <string name="whichApplication" msgid="5432266899591255759">"Изпълняване на действието чрез"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Завършване на действието посредством %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Изпълняване на действието"</string> diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml index eb626f229bdd..f180df6dbe71 100644 --- a/core/res/res/values-bs/strings.xml +++ b/core/res/res/values-bs/strings.xml @@ -1149,10 +1149,8 @@ <string name="capital_off" msgid="7443704171014626777">"Isključeno"</string> <string name="checked" msgid="9179896827054513119">"označeno"</string> <string name="not_checked" msgid="7972320087569023342">"nije označeno"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"odabrano"</string> + <string name="not_selected" msgid="410652016565864475">"nije odabrano"</string> <string name="whichApplication" msgid="5432266899591255759">"Završite radnju pomoću aplikacije"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Završite radnju pomoću aplikacije %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Izvršiti akciju"</string> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index dd6e5a36f33f..8c9c674372f8 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -327,7 +327,7 @@ <string name="capability_desc_canControlMagnification" msgid="2206586716709254805">"Controla el nivell i la posició del zoom de la pantalla."</string> <string name="capability_title_canPerformGestures" msgid="9106545062106728987">"Fer gestos"</string> <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Permet tocar, lliscar, pinçar i fer altres gestos."</string> - <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Gestos d\'empremtes dactilars"</string> + <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Gestos d\'empremtes digitals"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Captura gestos realitzats en el sensor d\'empremtes dactilars del dispositiu."</string> <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Fes una captura de pantalla"</string> <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Pots fer una captura de la pantalla."</string> @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"NO"</string> <string name="checked" msgid="9179896827054513119">"seleccionat"</string> <string name="not_checked" msgid="7972320087569023342">"no seleccionat"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"seleccionat"</string> + <string name="not_selected" msgid="410652016565864475">"no seleccionat"</string> <string name="whichApplication" msgid="5432266899591255759">"Completa l\'acció mitjançant"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Completa l\'acció amb %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Completa l\'acció"</string> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index d9f09a2557fb..e9f1fad5e95d 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -1169,10 +1169,8 @@ <string name="capital_off" msgid="7443704171014626777">"O"</string> <string name="checked" msgid="9179896827054513119">"vybráno"</string> <string name="not_checked" msgid="7972320087569023342">"nevybráno"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"vybráno"</string> + <string name="not_selected" msgid="410652016565864475">"nevybráno"</string> <string name="whichApplication" msgid="5432266899591255759">"Dokončit akci pomocí aplikace"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Dokončit akci pomocí aplikace %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Dokončit akci"</string> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index d37cee45b5ae..75bdda0b590c 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"FRA"</string> <string name="checked" msgid="9179896827054513119">"slået til"</string> <string name="not_checked" msgid="7972320087569023342">"slået fra"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"valgt"</string> + <string name="not_selected" msgid="410652016565864475">"ikke valgt"</string> <string name="whichApplication" msgid="5432266899591255759">"Brug"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Gennemfør handling ved hjælp af %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Afslut handling"</string> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index 4ab45b439d0b..6d82b62daf2e 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -327,7 +327,7 @@ <string name="capability_desc_canControlMagnification" msgid="2206586716709254805">"Legt die Zoom-Stufe und -Position auf dem Display fest."</string> <string name="capability_title_canPerformGestures" msgid="9106545062106728987">"Touch-Gesten möglich"</string> <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Tippen, Wischen, Zusammenziehen und andere Touch-Gesten möglich."</string> - <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Fingerabdrucksensor-Gesten"</string> + <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Gesten auf dem Fingerabdrucksensor"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Erfasst Touch-Gesten auf dem Fingerabdrucksensor des Geräts."</string> <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Screenshot erstellen"</string> <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Es kann ein Screenshot des Displays erstellt werden."</string> @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"AUS"</string> <string name="checked" msgid="9179896827054513119">"aktiviert"</string> <string name="not_checked" msgid="7972320087569023342">"deaktiviert"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"ausgewählt"</string> + <string name="not_selected" msgid="410652016565864475">"nicht ausgewählt"</string> <string name="whichApplication" msgid="5432266899591255759">"Aktion durchführen mit"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Aktion mit %1$s abschließen"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Abschließen"</string> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index 933ddf7588e0..42513aa77300 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"Ανενεργό"</string> <string name="checked" msgid="9179896827054513119">"επιλεγμένο"</string> <string name="not_checked" msgid="7972320087569023342">"μη επιλεγμένο"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"επιλεγμένο"</string> + <string name="not_selected" msgid="410652016565864475">"μη επιλεγμένο"</string> <string name="whichApplication" msgid="5432266899591255759">"Ολοκλήρωση ενέργειας με τη χρήση"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Ολοκληρωμένη ενέργεια με χρήση %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Ολοκλήρωση ενέργειας"</string> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index d88f58021a70..1e07593956b3 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"No"</string> <string name="checked" msgid="9179896827054513119">"activado"</string> <string name="not_checked" msgid="7972320087569023342">"desactivado"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"seleccionado"</string> + <string name="not_selected" msgid="410652016565864475">"no seleccionado"</string> <string name="whichApplication" msgid="5432266899591255759">"Completar la acción mediante"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Completar acción con %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Completar acción"</string> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index a498c6afe39f..d0fceb094355 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -1778,7 +1778,7 @@ <item quantity="other">Vuelve a intentarlo en <xliff:g id="COUNT">%d</xliff:g> segundos</item> <item quantity="one">Vuelve a intentarlo en 1 segundo</item> </plurals> - <string name="restr_pin_try_later" msgid="5897719962541636727">"Volver a intentar más tarde"</string> + <string name="restr_pin_try_later" msgid="5897719962541636727">"Reintentar más tarde"</string> <string name="immersive_cling_title" msgid="2307034298721541791">"Modo de pantalla completa"</string> <string name="immersive_cling_description" msgid="7092737175345204832">"Para salir, desliza el dedo de arriba abajo."</string> <string name="immersive_cling_positive" msgid="7047498036346489883">"Entendido"</string> diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml index 05cd7eb32c0b..69d1526845b8 100644 --- a/core/res/res/values-et/strings.xml +++ b/core/res/res/values-et/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"VÄLJAS"</string> <string name="checked" msgid="9179896827054513119">"märgitud"</string> <string name="not_checked" msgid="7972320087569023342">"märkimata"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"valitud"</string> + <string name="not_selected" msgid="410652016565864475">"pole valitud"</string> <string name="whichApplication" msgid="5432266899591255759">"Lõpetage toiming rakendusega"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Toimingu lõpetamine, kasutades rakendust %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Vii toiming lõpule"</string> diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml index 5f63703d0e2a..a00282ff4292 100644 --- a/core/res/res/values-eu/strings.xml +++ b/core/res/res/values-eu/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"DESAKTIBATUTA"</string> <string name="checked" msgid="9179896827054513119">"markatuta"</string> <string name="not_checked" msgid="7972320087569023342">"markatu gabe"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"hautatuta"</string> + <string name="not_selected" msgid="410652016565864475">"hautatu gabe"</string> <string name="whichApplication" msgid="5432266899591255759">"Gauzatu ekintza hau erabilita:"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Osatu ekintza %1$s erabiliz"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Osatu ekintza"</string> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index 00956a4129e8..6783b7700a67 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"خاموش"</string> <string name="checked" msgid="9179896827054513119">"علامتزدهشده"</string> <string name="not_checked" msgid="7972320087569023342">"بدون علامت"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"انتخاب شده"</string> + <string name="not_selected" msgid="410652016565864475">"انتخاب نشده"</string> <string name="whichApplication" msgid="5432266899591255759">"تکمیل کنش بااستفاده از"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"تکمیل کنش بااستفاده از %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"تکمیل عملکرد"</string> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index 4e488017b71c..27abeea5dd86 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"POIS"</string> <string name="checked" msgid="9179896827054513119">"valittu"</string> <string name="not_checked" msgid="7972320087569023342">"ei valittu"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"valittu"</string> + <string name="not_selected" msgid="410652016565864475">"ei valittu"</string> <string name="whichApplication" msgid="5432266899591255759">"Tee toiminto käyttäen sovellusta"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Suorita sovelluksella %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Suorita toiminto"</string> diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index 283588eaaf58..542aaf0b456b 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"NON"</string> <string name="checked" msgid="9179896827054513119">"coché"</string> <string name="not_checked" msgid="7972320087569023342">"non coché"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"sélectionné"</string> + <string name="not_selected" msgid="410652016565864475">"non sélectionné"</string> <string name="whichApplication" msgid="5432266899591255759">"Continuer avec"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Continuer avec %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Terminer l\'action"</string> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index 83ba1e97b773..4c2984973594 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"NON"</string> <string name="checked" msgid="9179896827054513119">"activé"</string> <string name="not_checked" msgid="7972320087569023342">"désactivé"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"sélectionné"</string> + <string name="not_selected" msgid="410652016565864475">"non sélectionné"</string> <string name="whichApplication" msgid="5432266899591255759">"Continuer avec"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Terminer l\'action avec %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Terminer l\'action"</string> diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml index dbe9593a6526..893433b7b8a2 100644 --- a/core/res/res/values-gl/strings.xml +++ b/core/res/res/values-gl/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"NON"</string> <string name="checked" msgid="9179896827054513119">"seleccionado"</string> <string name="not_checked" msgid="7972320087569023342">"non seleccionado"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"elemento seleccionado"</string> + <string name="not_selected" msgid="410652016565864475">"elemento non seleccionado"</string> <string name="whichApplication" msgid="5432266899591255759">"Completar a acción usando"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Completar a acción usando %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Completar acción"</string> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index eac5f2d42214..f1e57801d3ec 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"बंद"</string> <string name="checked" msgid="9179896827054513119">"चालू है"</string> <string name="not_checked" msgid="7972320087569023342">"बंद है"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"चुना गया"</string> + <string name="not_selected" msgid="410652016565864475">"नहीं चुना गया"</string> <string name="whichApplication" msgid="5432266899591255759">"इसका इस्तेमाल करके कार्रवाई को पूरा करें"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s का उपयोग करके कार्रवाई पूरी करें"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"कार्रवाई पूरी करें"</string> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index 1c80380734ae..4ff37c575a0f 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -1149,10 +1149,8 @@ <string name="capital_off" msgid="7443704171014626777">"Isklj."</string> <string name="checked" msgid="9179896827054513119">"potvrđeno"</string> <string name="not_checked" msgid="7972320087569023342">"nije potvrđeno"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"odabrano"</string> + <string name="not_selected" msgid="410652016565864475">"nije odabrano"</string> <string name="whichApplication" msgid="5432266899591255759">"Radnju dovrši pomoću stavke"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Dovršavanje radnje pomoću aplikacije %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Dovrši radnju"</string> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index 68ba61e1f848..d01373f749f3 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"Ki"</string> <string name="checked" msgid="9179896827054513119">"kiválasztva"</string> <string name="not_checked" msgid="7972320087569023342">"nincs kiválasztva"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"kiválasztva"</string> + <string name="not_selected" msgid="410652016565864475">"nincs kiválasztva"</string> <string name="whichApplication" msgid="5432266899591255759">"Művelet végrehajtása a következővel:"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Művelet elvégzése a(z) %1$s segítségével"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Művelet végrehajtása"</string> diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml index 6c5223285f52..b1fe76e760e2 100644 --- a/core/res/res/values-hy/strings.xml +++ b/core/res/res/values-hy/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"O"</string> <string name="checked" msgid="9179896827054513119">"նշված է"</string> <string name="not_checked" msgid="7972320087569023342">"նշված չէ"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"ընտրված է"</string> + <string name="not_selected" msgid="410652016565864475">"ընտրված չէ"</string> <string name="whichApplication" msgid="5432266899591255759">"Ավարտել գործողությունը` օգտագործելով"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Եզրափակել գործողությունը՝ օգտագործելով %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Ավարտել գործողությունը"</string> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index b420b6e4f692..cc8071bf7b9a 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"MATI"</string> <string name="checked" msgid="9179896827054513119">"dicentang"</string> <string name="not_checked" msgid="7972320087569023342">"tidak dicentang"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"dipilih"</string> + <string name="not_selected" msgid="410652016565864475">"tidak dipilih"</string> <string name="whichApplication" msgid="5432266899591255759">"Selesaikan tindakan menggunakan"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Selesaikan tindakan menggunakan %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Selesaikan tindakan"</string> diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml index a4390e3f8eb9..5d1912236a99 100644 --- a/core/res/res/values-is/strings.xml +++ b/core/res/res/values-is/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"SLÖKKT"</string> <string name="checked" msgid="9179896827054513119">"valið"</string> <string name="not_checked" msgid="7972320087569023342">"ekki valið"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"valið"</string> + <string name="not_selected" msgid="410652016565864475">"ekki valið"</string> <string name="whichApplication" msgid="5432266899591255759">"Ljúka aðgerð með"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Ljúka aðgerð með %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Ljúka aðgerð"</string> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index 9835e8b83347..a537e7ed38ac 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"OFF"</string> <string name="checked" msgid="9179896827054513119">"selezionato"</string> <string name="not_checked" msgid="7972320087569023342">"deselezionato"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"selezionato"</string> + <string name="not_selected" msgid="410652016565864475">"non selezionato"</string> <string name="whichApplication" msgid="5432266899591255759">"Completa l\'azione con"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Completamento azione con %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Completa azione"</string> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index db190f7a3e04..422d810d3c09 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -1169,10 +1169,8 @@ <string name="capital_off" msgid="7443704171014626777">"כבוי"</string> <string name="checked" msgid="9179896827054513119">"מסומן"</string> <string name="not_checked" msgid="7972320087569023342">"לא מסומן"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"נבחר"</string> + <string name="not_selected" msgid="410652016565864475">"לא נבחר"</string> <string name="whichApplication" msgid="5432266899591255759">"השלמת פעולה באמצעות"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"להשלמת הפעולה באמצעות %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"השלם פעולה"</string> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index d9c74c500609..f5adb5962783 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"OFF"</string> <string name="checked" msgid="9179896827054513119">"ON"</string> <string name="not_checked" msgid="7972320087569023342">"OFF"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"選択済み"</string> + <string name="not_selected" msgid="410652016565864475">"未選択"</string> <string name="whichApplication" msgid="5432266899591255759">"アプリケーションを選択"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$sを使用してアクションを完了"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"アクションを実行"</string> diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml index 491793de3438..0c3e7b9f207c 100644 --- a/core/res/res/values-ka/strings.xml +++ b/core/res/res/values-ka/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"გამორთ."</string> <string name="checked" msgid="9179896827054513119">"მონიშნულია"</string> <string name="not_checked" msgid="7972320087569023342">"არ არის მონიშნული"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"არჩეულია"</string> + <string name="not_selected" msgid="410652016565864475">"არ არის არჩეული"</string> <string name="whichApplication" msgid="5432266899591255759">"რა გამოვიყენოთ?"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"მოქმედების %1$s-ის გამოყენებით დასრულება"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"მოქმედების დასრულება"</string> diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml index 857892b37389..093daf1c0069 100644 --- a/core/res/res/values-kk/strings.xml +++ b/core/res/res/values-kk/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"Өшірулі"</string> <string name="checked" msgid="9179896827054513119">"белгіленген"</string> <string name="not_checked" msgid="7972320087569023342">"белгіленбеген"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"таңдалған"</string> + <string name="not_selected" msgid="410652016565864475">"таңдалмаған"</string> <string name="whichApplication" msgid="5432266899591255759">"Әрекетті аяқтау"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Әрекетті %1$s қолданбасын пайдаланып аяқтау"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Әрекетті аяқтау"</string> diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml index 45d7ff73862f..82a27a85a264 100644 --- a/core/res/res/values-km/strings.xml +++ b/core/res/res/values-km/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"បិទ"</string> <string name="checked" msgid="9179896827054513119">"បានធីក"</string> <string name="not_checked" msgid="7972320087569023342">"មិនបានធីក"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"បានជ្រើសរើស"</string> + <string name="not_selected" msgid="410652016565864475">"មិនបានជ្រើសរើសទេ"</string> <string name="whichApplication" msgid="5432266899591255759">"បញ្ចប់សកម្មភាពដោយប្រើ"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"បញ្ចប់សកម្មភាពដោយប្រើ %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"បញ្ចប់សកម្មភាព"</string> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index 0e746f9733de..f08ed6c253f1 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"OFF"</string> <string name="checked" msgid="9179896827054513119">"선택함"</string> <string name="not_checked" msgid="7972320087569023342">"선택 안함"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"선택됨"</string> + <string name="not_selected" msgid="410652016565864475">"선택되지 않음"</string> <string name="whichApplication" msgid="5432266899591255759">"작업을 수행할 때 사용하는 애플리케이션"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s을(를) 사용하여 작업 완료"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"작업 완료"</string> diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml index d12ec8b4db75..451821681f0b 100644 --- a/core/res/res/values-ky/strings.xml +++ b/core/res/res/values-ky/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"ӨЧҮК"</string> <string name="checked" msgid="9179896827054513119">"белгиленген"</string> <string name="not_checked" msgid="7972320087569023342">"белгилене элек"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"тандалган"</string> + <string name="not_selected" msgid="410652016565864475">"тандалган жок"</string> <string name="whichApplication" msgid="5432266899591255759">"Кайсынысын колдоносуз?"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s аркылуу аракетти аягына чейин чыгаруу"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Аракетти аягына чыгаруу"</string> diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml index 5d15180db8aa..35d2e2d9857b 100644 --- a/core/res/res/values-lo/strings.xml +++ b/core/res/res/values-lo/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"ປິດ"</string> <string name="checked" msgid="9179896827054513119">"ໝາຍຖືກແລ້ວ"</string> <string name="not_checked" msgid="7972320087569023342">"ບໍ່ໄດ້ໝາຍຖືກ"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"ເລືອກແລ້ວ"</string> + <string name="not_selected" msgid="410652016565864475">"ບໍ່ໄດ້ເລືອກແລ້ວ"</string> <string name="whichApplication" msgid="5432266899591255759">"ດຳເນີນການໂດຍໃຊ້"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"ສຳເລັດການດຳເນີນການໂດຍໃຊ້ %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"ສຳເລັດຄຳສັ່ງ"</string> diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index bef1f26d50bc..99e8b1f7277f 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -1169,10 +1169,8 @@ <string name="capital_off" msgid="7443704171014626777">"IŠJ."</string> <string name="checked" msgid="9179896827054513119">"pažymėta"</string> <string name="not_checked" msgid="7972320087569023342">"nepažymėta"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"pasirinkta"</string> + <string name="not_selected" msgid="410652016565864475">"nepasirinkta"</string> <string name="whichApplication" msgid="5432266899591255759">"Užbaigti veiksmą naudojant"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Užbaigti veiksmą naudojant %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Užbaigti veiksmą"</string> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index 44cf3a2db1bb..95752c336749 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -1149,10 +1149,8 @@ <string name="capital_off" msgid="7443704171014626777">"IZSL."</string> <string name="checked" msgid="9179896827054513119">"atzīmēts"</string> <string name="not_checked" msgid="7972320087569023342">"nav atzīmēts"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"atlasīts"</string> + <string name="not_selected" msgid="410652016565864475">"nav atlasīts"</string> <string name="whichApplication" msgid="5432266899591255759">"Izvēlieties lietotni"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Pabeigt darbību, izmantojot %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Pabeigt darbību"</string> diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml index 15c7ebafe850..5e62762dc787 100644 --- a/core/res/res/values-mk/strings.xml +++ b/core/res/res/values-mk/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"ИСКЛУЧЕНО"</string> <string name="checked" msgid="9179896827054513119">"штиклирано"</string> <string name="not_checked" msgid="7972320087569023342">"не е штиклирано"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"избрано"</string> + <string name="not_selected" msgid="410652016565864475">"не е избрано"</string> <string name="whichApplication" msgid="5432266899591255759">"Активирај со"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Остварете го дејството со %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Заврши го дејството"</string> diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml index 314442bfe97c..85a797547475 100644 --- a/core/res/res/values-ml/strings.xml +++ b/core/res/res/values-ml/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"ഓഫ്"</string> <string name="checked" msgid="9179896827054513119">"പരിശോധിച്ചത്"</string> <string name="not_checked" msgid="7972320087569023342">"പരിശോധിക്കാത്തത്"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"തിരഞ്ഞെടുത്തു"</string> + <string name="not_selected" msgid="410652016565864475">"തിരഞ്ഞെടുത്തിട്ടില്ല"</string> <string name="whichApplication" msgid="5432266899591255759">"പൂർണ്ണമായ പ്രവർത്തനം ഉപയോഗിക്കുന്നു"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ഉപയോഗിച്ച് പ്രവർത്തനം പൂർത്തിയാക്കുക"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"പ്രവർത്തനം പൂർത്തിയാക്കുക"</string> diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml index f4c78e837b53..bbcfc63b3a38 100644 --- a/core/res/res/values-mn/strings.xml +++ b/core/res/res/values-mn/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"Идэвхгүй"</string> <string name="checked" msgid="9179896827054513119">"тэмдэглэсэн"</string> <string name="not_checked" msgid="7972320087569023342">"тэмдэглээгүй"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"сонгосон"</string> + <string name="not_selected" msgid="410652016565864475">"сонгоогүй"</string> <string name="whichApplication" msgid="5432266899591255759">"Үйлдлийг дуусгах"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ашиглан үйлдлийг гүйцээх"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Үйлдлийг дуусгах"</string> diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml index 6d33cfadd511..b38dec2c25ba 100644 --- a/core/res/res/values-ms/strings.xml +++ b/core/res/res/values-ms/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"MATIKAN"</string> <string name="checked" msgid="9179896827054513119">"ditandai"</string> <string name="not_checked" msgid="7972320087569023342">"tidak ditandai"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"dipilih"</string> + <string name="not_selected" msgid="410652016565864475">"tidak dipilih"</string> <string name="whichApplication" msgid="5432266899591255759">"Selesaikan tindakan menggunakan"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Selesaikan tindakan menggunakan %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Selesaikan tindakan"</string> diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml index df33b37f9b0b..e1f3dcf31a49 100644 --- a/core/res/res/values-my/strings.xml +++ b/core/res/res/values-my/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"ပိတ်"</string> <string name="checked" msgid="9179896827054513119">"အမှန်ခြစ်ပြီး"</string> <string name="not_checked" msgid="7972320087569023342">"ခြစ် မထား"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"ရွေးချယ်ထားသည်"</string> + <string name="not_selected" msgid="410652016565864475">"ရွေးချယ်မထားပါ"</string> <string name="whichApplication" msgid="5432266899591255759">"အောက်ပါတို့ကို အသုံးပြုမှု အပြီးသတ်ခြင်း"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ကို သုံးပြီး လုပ်ဆောင်ချက် ပြီးဆုံးပါစေ"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"လုပ်ဆောင်ချက်ကို အပြီးသတ်ပါ"</string> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index e62bf51dfe63..1c2e5c03d658 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"Av"</string> <string name="checked" msgid="9179896827054513119">"avmerket"</string> <string name="not_checked" msgid="7972320087569023342">"ikke avmerket"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"valgt"</string> + <string name="not_selected" msgid="410652016565864475">"ikke valgt"</string> <string name="whichApplication" msgid="5432266899591255759">"Fullfør med"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Fullfør handlingen med %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Fullfør handlingen"</string> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index c041cb55a485..f768c833da66 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"UIT"</string> <string name="checked" msgid="9179896827054513119">"aangevinkt"</string> <string name="not_checked" msgid="7972320087569023342">"niet aangevinkt"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"geselecteerd"</string> + <string name="not_selected" msgid="410652016565864475">"niet geselecteerd"</string> <string name="whichApplication" msgid="5432266899591255759">"Actie voltooien met"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Actie voltooien via %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Actie voltooien"</string> diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml index 81a967625535..520673279ce7 100644 --- a/core/res/res/values-or/strings.xml +++ b/core/res/res/values-or/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"ବନ୍ଦ"</string> <string name="checked" msgid="9179896827054513119">"ଯାଞ୍ଚ ହୋଇଛି"</string> <string name="not_checked" msgid="7972320087569023342">"ଯାଞ୍ଚ ହୋଇନାହିଁ"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"ଚୟନ କରାଯାଇଛି"</string> + <string name="not_selected" msgid="410652016565864475">"ଚୟନ କରାଯାଇନାହିଁ"</string> <string name="whichApplication" msgid="5432266899591255759">"ବ୍ୟବହାର କରି କାର୍ଯ୍ୟ ସମ୍ପୂର୍ଣ୍ଣ କରନ୍ତୁ"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ବ୍ୟବହାର କରି କାର୍ଯ୍ୟ ସମ୍ପୂର୍ଣ୍ଣ କରନ୍ତୁ"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"କାର୍ଯ୍ୟ ସମ୍ପୂର୍ଣ୍ଣ କରନ୍ତୁ"</string> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index 3962f743b9fa..07773da7f933 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -1169,10 +1169,8 @@ <string name="capital_off" msgid="7443704171014626777">"Wył."</string> <string name="checked" msgid="9179896827054513119">"wybrano"</string> <string name="not_checked" msgid="7972320087569023342">"nie wybrano"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"wybrano"</string> + <string name="not_selected" msgid="410652016565864475">"nie wybrano"</string> <string name="whichApplication" msgid="5432266899591255759">"Wykonaj czynność przez..."</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Wykonaj czynność w aplikacji %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Wykonaj działanie"</string> diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index 72a867ed2901..bfd32f35c993 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"DESL"</string> <string name="checked" msgid="9179896827054513119">"marcado"</string> <string name="not_checked" msgid="7972320087569023342">"não marcado"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"selecionado"</string> + <string name="not_selected" msgid="410652016565864475">"não selecionado"</string> <string name="whichApplication" msgid="5432266899591255759">"Complete a ação usando"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Concluir a ação usando %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Concluir ação"</string> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index 28b83c1a637c..e83d5578cb32 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"Desativado"</string> <string name="checked" msgid="9179896827054513119">"selecionado"</string> <string name="not_checked" msgid="7972320087569023342">"não selecionado"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"selecionado"</string> + <string name="not_selected" msgid="410652016565864475">"não selecionado"</string> <string name="whichApplication" msgid="5432266899591255759">"Concluir ação utilizando"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Concluir ação utilizando %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Concluir ação"</string> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index 72a867ed2901..bfd32f35c993 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"DESL"</string> <string name="checked" msgid="9179896827054513119">"marcado"</string> <string name="not_checked" msgid="7972320087569023342">"não marcado"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"selecionado"</string> + <string name="not_selected" msgid="410652016565864475">"não selecionado"</string> <string name="whichApplication" msgid="5432266899591255759">"Complete a ação usando"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Concluir a ação usando %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Concluir ação"</string> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index bbe35ed00b73..fcd70eb61a25 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -1149,10 +1149,8 @@ <string name="capital_off" msgid="7443704171014626777">"NU"</string> <string name="checked" msgid="9179896827054513119">"bifat"</string> <string name="not_checked" msgid="7972320087569023342">"nebifat"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"selectat"</string> + <string name="not_selected" msgid="410652016565864475">"neselectat"</string> <string name="whichApplication" msgid="5432266899591255759">"Finalizare acțiune utilizând"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Finalizați acțiunea utilizând %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Finalizați acțiunea"</string> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index 2903ba215cdd..3a8b28b8c7bf 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -1169,10 +1169,8 @@ <string name="capital_off" msgid="7443704171014626777">"O"</string> <string name="checked" msgid="9179896827054513119">"отмечено"</string> <string name="not_checked" msgid="7972320087569023342">"не отмечено"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"выбрано"</string> + <string name="not_selected" msgid="410652016565864475">"не выбрано"</string> <string name="whichApplication" msgid="5432266899591255759">"Что использовать?"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Выполнить с помощью приложения \"%1$s\""</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Выполнить действие"</string> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index f6c1b89c09f7..cef059d8cfde 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -1169,10 +1169,8 @@ <string name="capital_off" msgid="7443704171014626777">"O"</string> <string name="checked" msgid="9179896827054513119">"začiarknuté"</string> <string name="not_checked" msgid="7972320087569023342">"nezačiarknuté"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"vybrané"</string> + <string name="not_selected" msgid="410652016565864475">"nevybrané"</string> <string name="whichApplication" msgid="5432266899591255759">"Dokončiť akciu pomocou aplikácie"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Dokončiť akciu pomocou aplikácie %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Dokončiť akciu"</string> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index 2f2fcc214627..b29748c1360f 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -1169,10 +1169,8 @@ <string name="capital_off" msgid="7443704171014626777">"IZKLOPLJENO"</string> <string name="checked" msgid="9179896827054513119">"potrjeno"</string> <string name="not_checked" msgid="7972320087569023342">"ni potrjeno"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"izbrano"</string> + <string name="not_selected" msgid="410652016565864475">"ni izbrano"</string> <string name="whichApplication" msgid="5432266899591255759">"Dokončanje dejanja z aplikacijo"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Dokončanje dejanja z aplikacijo %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Izvedba dejanja"</string> diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml index a36e860cc80b..c852d277a92f 100644 --- a/core/res/res/values-sq/strings.xml +++ b/core/res/res/values-sq/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"Çaktivizuar"</string> <string name="checked" msgid="9179896827054513119">"u përzgjodh"</string> <string name="not_checked" msgid="7972320087569023342">"nuk u përzgjodh"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"i zgjedhur"</string> + <string name="not_selected" msgid="410652016565864475">"i pazgjedhur"</string> <string name="whichApplication" msgid="5432266899591255759">"Përfundo veprimin duke përdorur"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Përfundo veprimin duke përdorur %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Përfundo veprimin"</string> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index f9968ef1499a..6a66c1be3d07 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -1149,10 +1149,8 @@ <string name="capital_off" msgid="7443704171014626777">"НЕ"</string> <string name="checked" msgid="9179896827054513119">"означено је"</string> <string name="not_checked" msgid="7972320087569023342">"није означено"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"изабрано"</string> + <string name="not_selected" msgid="410652016565864475">"није изабрано"</string> <string name="whichApplication" msgid="5432266899591255759">"Доврши радњу преко"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Завршите радњу помоћу апликације %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Заврши радњу"</string> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index de346c6be54d..8c28252bdfd3 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"AV"</string> <string name="checked" msgid="9179896827054513119">"markerad"</string> <string name="not_checked" msgid="7972320087569023342">"inte markerad"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"valt"</string> + <string name="not_selected" msgid="410652016565864475">"inte valt"</string> <string name="whichApplication" msgid="5432266899591255759">"Slutför åtgärd genom att använda"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Slutför åtgärden med %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Slutför åtgärd"</string> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index 0d56560bc40c..9124c1231988 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"ZIMA"</string> <string name="checked" msgid="9179896827054513119">"imeteuliwa"</string> <string name="not_checked" msgid="7972320087569023342">"haijateuliwa"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"imechaguliwa"</string> + <string name="not_selected" msgid="410652016565864475">"haijachaguliwa"</string> <string name="whichApplication" msgid="5432266899591255759">"Kamilisha kitendo ukitumia"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Kamilisha kitendo ukitumia %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Kamilisha kitendo"</string> diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml index f69414484f4f..4db2bec7cad1 100644 --- a/core/res/res/values-ta/strings.xml +++ b/core/res/res/values-ta/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"ஆஃப்"</string> <string name="checked" msgid="9179896827054513119">"இயக்கப்பட்டுள்ளது"</string> <string name="not_checked" msgid="7972320087569023342">"முடக்கப்பட்டுள்ளது"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"தேர்ந்தெடுக்கப்பட்டது"</string> + <string name="not_selected" msgid="410652016565864475">"தேர்ந்தெடுக்கப்படவில்லை"</string> <string name="whichApplication" msgid="5432266899591255759">"இதைப் பயன்படுத்தி செயலை நிறைவுசெய்"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ஐப் பயன்படுத்தி செயலை முடிக்கவும்"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"செயலை முடி"</string> diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index 4cc2e16e202f..5102f148bb7c 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"ปิด"</string> <string name="checked" msgid="9179896827054513119">"เลือกไว้"</string> <string name="not_checked" msgid="7972320087569023342">"ยังไม่เลือก"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"เลือกไว้"</string> + <string name="not_selected" msgid="410652016565864475">"ไม่ได้เลือกไว้"</string> <string name="whichApplication" msgid="5432266899591255759">"ทำงานให้เสร็จโดยใช้"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"ดำเนินการให้เสร็จสมบูรณ์โดยใช้ %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"ทำงานให้เสร็จสิ้น"</string> diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index 02c6f875c23c..6a15ffc38432 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"I-OFF"</string> <string name="checked" msgid="9179896827054513119">"nilagyan ng check"</string> <string name="not_checked" msgid="7972320087569023342">"hindi nilagyan ng check"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"pinili"</string> + <string name="not_selected" msgid="410652016565864475">"hindi pinili"</string> <string name="whichApplication" msgid="5432266899591255759">"Kumpletuhin ang pagkilos gamit ang"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Tapusin ang pagkilos gamit ang %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Gawin ang pagkilos"</string> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index 08f07f2076fb..8ee1d30a11bc 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"KAPALI"</string> <string name="checked" msgid="9179896827054513119">"işaretli"</string> <string name="not_checked" msgid="7972320087569023342">"işaretli değil"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"seçili"</string> + <string name="not_selected" msgid="410652016565864475">"seçili değil"</string> <string name="whichApplication" msgid="5432266899591255759">"İşlemi şunu kullanarak tamamla"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"İşlemi %1$s kullanarak tamamla"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"İşlemi tamamla"</string> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index a8029337cf45..5ad2ea188200 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -1169,10 +1169,8 @@ <string name="capital_off" msgid="7443704171014626777">"ВИМК"</string> <string name="checked" msgid="9179896827054513119">"вибрано"</string> <string name="not_checked" msgid="7972320087569023342">"не вибрано"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"вибрано"</string> + <string name="not_selected" msgid="410652016565864475">"не вибрано"</string> <string name="whichApplication" msgid="5432266899591255759">"Що використовувати?"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Завершити дію за допомогою %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Завершити дію"</string> diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml index e2901bc9f907..78c9330a85e9 100644 --- a/core/res/res/values-ur/strings.xml +++ b/core/res/res/values-ur/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"آف"</string> <string name="checked" msgid="9179896827054513119">"چیک کیا گیا"</string> <string name="not_checked" msgid="7972320087569023342">"چیک نہیں کیا گیا"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"منتخب کردہ"</string> + <string name="not_selected" msgid="410652016565864475">"غیر منتخب کردہ"</string> <string name="whichApplication" msgid="5432266899591255759">"اس کا استعمال کرکے کارروائی مکمل کریں"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s کا استعمال کر کے کارروائی مکمل کریں"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"کارروائی مکمل کریں"</string> diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml index f49db4540a37..229e225ab63d 100644 --- a/core/res/res/values-uz/strings.xml +++ b/core/res/res/values-uz/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"O"</string> <string name="checked" msgid="9179896827054513119">"belgilandi"</string> <string name="not_checked" msgid="7972320087569023342">"belgilanmadi"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"tanlangan"</string> + <string name="not_selected" msgid="410652016565864475">"tanlanmagan"</string> <string name="whichApplication" msgid="5432266899591255759">"Nima ishlatilsin?"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"“%1$s” bilan ochish"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Amalni bajarish"</string> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index 17ef57670c95..050fa0b24cc4 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"TẮT"</string> <string name="checked" msgid="9179896827054513119">"đã chọn"</string> <string name="not_checked" msgid="7972320087569023342">"chưa chọn"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"đã chọn"</string> + <string name="not_selected" msgid="410652016565864475">"chưa được chọn"</string> <string name="whichApplication" msgid="5432266899591255759">"Hoàn tất thao tác bằng"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Hoàn tất thao tác bằng %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Hoàn thành tác vụ"</string> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index 0fe62a9d631d..ec01ae3acbd7 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"关闭"</string> <string name="checked" msgid="9179896827054513119">"已勾选"</string> <string name="not_checked" msgid="7972320087569023342">"未勾选"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"已选择"</string> + <string name="not_selected" msgid="410652016565864475">"未选择"</string> <string name="whichApplication" msgid="5432266899591255759">"选择要使用的应用:"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"使用%1$s完成操作"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"完成操作"</string> diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml index 8f9c7c439dc1..58232b912b7f 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"關"</string> <string name="checked" msgid="9179896827054513119">"已勾選"</string> <string name="not_checked" msgid="7972320087569023342">"未勾選"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"揀咗"</string> + <string name="not_selected" msgid="410652016565864475">"未揀"</string> <string name="whichApplication" msgid="5432266899591255759">"完成操作需使用"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"完成操作需使用 %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"完成操作"</string> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index eba79789a630..617a671500ec 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"關閉"</string> <string name="checked" msgid="9179896827054513119">"已勾選"</string> <string name="not_checked" msgid="7972320087569023342">"未勾選"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"已選取"</string> + <string name="not_selected" msgid="410652016565864475">"未選取"</string> <string name="whichApplication" msgid="5432266899591255759">"選擇要使用的應用程式"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"完成操作需使用 %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"完成操作"</string> diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml index 0f6fcb5c85d6..fab89962ef69 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"VALIWE"</string> <string name="checked" msgid="9179896827054513119">"kuhloliwe"</string> <string name="not_checked" msgid="7972320087569023342">"akuhloliwe"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"okukhethiwe"</string> + <string name="not_selected" msgid="410652016565864475">"akukhethiwe"</string> <string name="whichApplication" msgid="5432266899591255759">"Qedela isenzo usebenzisa"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Qedela isenzo usebenzisa i-%1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Qedela isenzo"</string> diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index e3ddbd8d25a2..f8266ba177ca 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -3202,10 +3202,23 @@ <attr name="minHeight" /> <!-- Window layout affinity of this activity. Activities with the same window layout - affinity will share the same layout record. If an activity is launched in freeform window, - the activity will be launched to the latest position and size where any task, if the root - activity of that task shares the same window layout affinity with the activity being - launched. Window layout affinity is shared only among activities with the same UID. + affinity will share the same layout record. That is, if a user is opening an activity in + a new task on a display that can host freeform windows, and the user had opened a task + before and that task had a root activity who had the same window layout affinity, the + new task's window will be created in the same window mode and around the location which + the previously opened task was in. + + <p>For example, if a user maximizes a task with root activity A and opens another + activity B that has the same window layout affinity as activity A has, activity B will + be created in fullscreen window mode. Similarly, if they move/resize a task with root + activity C and open another activity D that has the same window layout affinity as + activity C has, activity D will be in freeform window mode and as close to the position + of activity C as conditions permit. It doesn't require the user to keep the task with + activity A or activity C open. It won't, however, put any task into split-screen or PIP + window mode on launch. + + <p>If the user is opening an activity with its window layout affinity for the first time, + the window mode and position is OEM defined. <p>By default activity doesn't share any affinity with other activities. --> <attr name="windowLayoutAffinity" format="string" /> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 8d5129465b0e..68fd7c71bcfd 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -4469,4 +4469,10 @@ TODO: b/170470621 - remove once we can have multiple Internal displays in DMS as well as a notification from DisplayStateManager. --> <string-array name="config_internalFoldedPhysicalDisplayIds" translatable="false" /> + + <!-- Aspect ratio of task level letterboxing. Values <= 1.0 will be ignored. + Note: Activity min/max aspect ratio restrictions will still be respected by the + activity-level letterboxing (size-compat mode). Therefore this override can control the + maximum screen area that can be occupied by the app in the letterbox mode. --> + <item name="config_taskLetterboxAspectRatio" format="float" type="dimen">0.0</item> </resources> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 697f7e0e898a..8daa6539ff64 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -4084,4 +4084,6 @@ <java-symbol type="dimen" name="controls_thumbnail_image_max_height" /> <java-symbol type="dimen" name="controls_thumbnail_image_max_width" /> + + <java-symbol type="dimen" name="config_taskLetterboxAspectRatio" /> </resources> diff --git a/core/tests/coretests/src/android/widget/TextViewOnReceiveContentCallbackTest.java b/core/tests/coretests/src/android/widget/TextViewOnReceiveContentCallbackTest.java index 5112326ea0b6..ef659af6c570 100644 --- a/core/tests/coretests/src/android/widget/TextViewOnReceiveContentCallbackTest.java +++ b/core/tests/coretests/src/android/widget/TextViewOnReceiveContentCallbackTest.java @@ -66,8 +66,8 @@ import org.mockito.Mockito; * {@link android.widget.cts.TextViewOnReceiveContentCallbackTest}. This class tests some internal * implementation details, e.g. fallback to the keyboard image API. */ -@RunWith(AndroidJUnit4.class) @MediumTest +@RunWith(AndroidJUnit4.class) public class TextViewOnReceiveContentCallbackTest { private static final Uri SAMPLE_CONTENT_URI = Uri.parse("content://com.example/path"); @@ -101,7 +101,7 @@ public class TextViewOnReceiveContentCallbackTest { // Assert that the callback returns the MIME types declared in the EditorInfo in addition to // the default. - assertThat(mDefaultCallback.getSupportedMimeTypes(mEditText)).containsExactly( + assertThat(mDefaultCallback.getMimeTypes(mEditText)).containsExactly( "text/*", "image/gif", "image/png"); } @@ -118,7 +118,7 @@ public class TextViewOnReceiveContentCallbackTest { onView(withId(mEditText.getId())).perform(clickOnTextAtIndex(0)); // Assert that the callback returns the default MIME types. - assertThat(mDefaultCallback.getSupportedMimeTypes(mEditText)).containsExactly("text/*"); + assertThat(mDefaultCallback.getMimeTypes(mEditText)).containsExactly("text/*"); } @Test diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml index bda84dd76cf5..54e8a0c1638e 100644 --- a/data/fonts/fonts.xml +++ b/data/fonts/fonts.xml @@ -528,7 +528,7 @@ </font> <font weight="400" style="normal" fallbackFor="serif">NotoSerifKhmer-Regular.otf</font> <font weight="700" style="normal" fallbackFor="serif">NotoSerifKhmer-Bold.otf</font> - </family> + </family> <family lang="und-Khmr" variant="compact"> <font weight="400" style="normal">NotoSansKhmerUI-Regular.ttf</font> <font weight="700" style="normal">NotoSansKhmerUI-Bold.ttf</font> @@ -762,8 +762,18 @@ <font weight="400" style="normal">NotoSansTaiViet-Regular.ttf</font> </family> <family lang="und-Tibt"> - <font weight="400" style="normal">NotoSansTibetan-Regular.ttf</font> - <font weight="700" style="normal">NotoSansTibetan-Bold.ttf</font> + <font weight="400" style="normal">NotoSerifTibetan-VF.ttf + <axis tag="wght" stylevalue="400" /> + </font> + <font weight="500" style="normal">NotoSerifTibetan-VF.ttf + <axis tag="wght" stylevalue="500" /> + </font> + <font weight="600" style="normal">NotoSerifTibetan-VF.ttf + <axis tag="wght" stylevalue="600" /> + </font> + <font weight="700" style="normal">NotoSerifTibetan-VF.ttf + <axis tag="wght" stylevalue="700" /> + </font> </family> <family lang="und-Tfng"> <font weight="400" style="normal">NotoSansTifinagh-Regular.otf</font> @@ -893,4 +903,83 @@ <family lang="und-Wara"> <font weight="400" style="normal">NotoSansWarangCiti-Regular.otf</font> </family> + <family lang="und-Gran"> + <font weight="400" style="normal">NotoSansGrantha-Regular.ttf</font> + </family> + <family lang="und-Modi"> + <font weight="400" style="normal">NotoSansModi-Regular.ttf</font> + </family> + <family lang="und-Dogr"> + <font weight="400" style="normal">NotoSerifDogra-Regular.ttf</font> + </family> + <family lang="und-Medf"> + <font weight="400" style="normal">NotoSansMedefaidrin-VF.ttf + <axis tag="wght" stylevalue="400" /> + </font> + <font weight="500" style="normal">NotoSansMedefaidrin-VF.ttf + <axis tag="wght" stylevalue="500" /> + </font> + <font weight="600" style="normal">NotoSansMedefaidrin-VF.ttf + <axis tag="wght" stylevalue="600" /> + </font> + <font weight="700" style="normal">NotoSansMedefaidrin-VF.ttf + <axis tag="wght" stylevalue="700" /> + </font> + </family> + <family lang="und-Soyo"> + <font weight="400" style="normal">NotoSansSoyombo-VF.ttf + <axis tag="wght" stylevalue="400" /> + </font> + <font weight="500" style="normal">NotoSansSoyombo-VF.ttf + <axis tag="wght" stylevalue="500" /> + </font> + <font weight="600" style="normal">NotoSansSoyombo-VF.ttf + <axis tag="wght" stylevalue="600" /> + </font> + <font weight="700" style="normal">NotoSansSoyombo-VF.ttf + <axis tag="wght" stylevalue="700" /> + </font> + </family> + <family lang="und-Takr"> + <font weight="400" style="normal">NotoSansTakri-VF.ttf + <axis tag="wght" stylevalue="400" /> + </font> + <font weight="500" style="normal">NotoSansTakri-VF.ttf + <axis tag="wght" stylevalue="500" /> + </font> + <font weight="600" style="normal">NotoSansTakri-VF.ttf + <axis tag="wght" stylevalue="600" /> + </font> + <font weight="700" style="normal">NotoSansTakri-VF.ttf + <axis tag="wght" stylevalue="700" /> + </font> + </family> + <family lang="und-Hmnp"> + <font weight="400" style="normal">NotoSerifNyiakengPuachueHmong-VF.ttf + <axis tag="wght" stylevalue="400" /> + </font> + <font weight="500" style="normal">NotoSerifNyiakengPuachueHmong-VF.ttf + <axis tag="wght" stylevalue="500" /> + </font> + <font weight="600" style="normal">NotoSerifNyiakengPuachueHmong-VF.ttf + <axis tag="wght" stylevalue="600" /> + </font> + <font weight="700" style="normal">NotoSerifNyiakengPuachueHmong-VF.ttf + <axis tag="wght" stylevalue="700" /> + </font> + </family> + <family lang="und-Yezi"> + <font weight="400" style="normal">NotoSerifYezidi-VF.ttf + <axis tag="wght" stylevalue="400" /> + </font> + <font weight="500" style="normal">NotoSerifYezidi-VF.ttf + <axis tag="wght" stylevalue="500" /> + </font> + <font weight="600" style="normal">NotoSerifYezidi-VF.ttf + <axis tag="wght" stylevalue="600" /> + </font> + <font weight="700" style="normal">NotoSerifYezidi-VF.ttf + <axis tag="wght" stylevalue="700" /> + </font> + </family> </familyset> diff --git a/libs/WindowManager/Shell/res/layout/tv_pip_controls.xml b/libs/WindowManager/Shell/res/layout/tv_pip_controls.xml index d2f235e273d5..9157f63ce1b3 100644 --- a/libs/WindowManager/Shell/res/layout/tv_pip_controls.xml +++ b/libs/WindowManager/Shell/res/layout/tv_pip_controls.xml @@ -16,7 +16,6 @@ --> <!-- Layout for {@link com.android.wm.shell.pip.tv.PipControlsView}. --> <merge xmlns:android="http://schemas.android.com/apk/res/android"> - <com.android.wm.shell.pip.tv.PipControlButtonView android:id="@+id/full_button" android:layout_width="@dimen/picture_in_picture_button_width" @@ -31,13 +30,4 @@ android:layout_marginStart="@dimen/picture_in_picture_button_start_margin" android:src="@drawable/pip_ic_close_white" android:text="@string/pip_close" /> - - <com.android.wm.shell.pip.tv.PipControlButtonView - android:id="@+id/play_pause_button" - android:layout_width="@dimen/picture_in_picture_button_width" - android:layout_height="wrap_content" - android:layout_marginStart="@dimen/picture_in_picture_button_start_margin" - android:src="@drawable/pip_ic_pause_white" - android:text="@string/pip_pause" - android:visibility="gone" /> </merge> diff --git a/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json b/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json index a4e69de97299..bee9f4163b04 100644 --- a/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json +++ b/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json @@ -169,6 +169,12 @@ "group": "WM_SHELL_DRAG_AND_DROP", "at": "com\/android\/wm\/shell\/draganddrop\/DragLayout.java" }, + "1842752748": { + "message": "Clip description: handlingDrag=%b mimeTypes=%s", + "level": "VERBOSE", + "group": "WM_SHELL_DRAG_AND_DROP", + "at": "com\/android\/wm\/shell\/draganddrop\/DragAndDropController.java" + }, "1862198614": { "message": "Drag event: action=%s x=%f y=%f xOffset=%f yOffset=%f", "level": "VERBOSE", diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java index 8f8b98bbfbae..bf5b1d8a4bcc 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java @@ -16,8 +16,17 @@ package com.android.wm.shell.draganddrop; +import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; +import static android.content.ClipDescription.EXTRA_ACTIVITY_OPTIONS; +import static android.content.ClipDescription.EXTRA_PENDING_INTENT; import static android.content.ClipDescription.MIMETYPE_APPLICATION_ACTIVITY; +import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT; +import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK; +import static android.content.Intent.EXTRA_PACKAGE_NAME; +import static android.content.Intent.EXTRA_SHORTCUT_ID; +import static android.content.Intent.EXTRA_TASK_ID; +import static android.content.Intent.EXTRA_USER; import static android.view.DragEvent.ACTION_DRAG_ENDED; import static android.view.DragEvent.ACTION_DRAG_ENTERED; import static android.view.DragEvent.ACTION_DRAG_EXITED; @@ -33,15 +42,24 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMA import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.ActivityOptions; +import android.app.ActivityTaskManager; import android.app.PendingIntent; +import android.content.ActivityNotFoundException; import android.content.ClipData; import android.content.ClipDescription; import android.content.Context; import android.content.Intent; +import android.content.pm.LauncherApps; import android.content.res.Configuration; import android.graphics.PixelFormat; import android.os.Binder; +import android.os.Bundle; +import android.os.Handler; +import android.os.RemoteException; +import android.os.UserHandle; import android.util.Slog; import android.util.SparseArray; import android.view.DragEvent; @@ -68,6 +86,7 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange private static final String TAG = DragAndDropController.class.getSimpleName(); + private final Context mContext; private final DisplayController mDisplayController; private SplitScreen mSplitScreen; @@ -76,7 +95,8 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange private DragLayout mDragLayout; private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction(); - public DragAndDropController(DisplayController displayController) { + public DragAndDropController(Context context, DisplayController displayController) { + mContext = context; mDisplayController = displayController; mDisplayController.addDisplayWindowListener(this); } @@ -135,13 +155,16 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange event.getOffsetX(), event.getOffsetY()); final int displayId = target.getDisplay().getDisplayId(); final PerDisplay pd = mDisplayDropTargets.get(displayId); + final ClipDescription description = event.getClipDescription(); if (event.getAction() == ACTION_DRAG_STARTED) { - final ClipDescription description = event.getClipDescription(); - final boolean hasValidClipData = description.hasMimeType(MIMETYPE_APPLICATION_ACTIVITY); + final boolean hasValidClipData = description.hasMimeType(MIMETYPE_APPLICATION_ACTIVITY) + || description.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT) + || description.hasMimeType(MIMETYPE_APPLICATION_TASK); mIsHandlingDrag = hasValidClipData; - ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Clip description: %s", - getMimeTypes(description)); + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, + "Clip description: handlingDrag=%b mimeTypes=%s", + mIsHandlingDrag, getMimeTypes(description)); } if (!mIsHandlingDrag) { @@ -163,31 +186,7 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange mDragLayout.update(event); break; case ACTION_DROP: { - final SurfaceControl dragSurface = event.getDragSurface(); - final View dragLayout = mDragLayout; - final ClipData data = event.getClipData(); - return mDragLayout.drop(event, dragSurface, (dropTargetBounds) -> { - if (dropTargetBounds != null) { - // TODO(b/169894807): Properly handle the drop, for now just launch it - if (data.getItemCount() > 0) { - Intent intent = data.getItemAt(0).getIntent(); - PendingIntent pi = intent.getParcelableExtra( - ClipDescription.EXTRA_PENDING_INTENT); - try { - pi.send(); - } catch (PendingIntent.CanceledException e) { - Slog.e(TAG, "Failed to launch activity", e); - } - } - } - - setDropTargetWindowVisibility(pd, View.INVISIBLE); - pd.dropTarget.removeView(dragLayout); - - // Clean up the drag surface - mTransaction.reparent(dragSurface, null); - mTransaction.apply(); - }); + return handleDrop(event, pd); } case ACTION_DRAG_EXITED: { // Either one of DROP or EXITED will happen, and when EXITED we won't consume @@ -211,6 +210,62 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange return true; } + /** + * Handles dropping on the drop target. + */ + private boolean handleDrop(DragEvent event, PerDisplay pd) { + final ClipData data = event.getClipData(); + final ClipDescription description = event.getClipDescription(); + final SurfaceControl dragSurface = event.getDragSurface(); + final View dragLayout = mDragLayout; + final boolean isTask = description.hasMimeType(MIMETYPE_APPLICATION_TASK); + final boolean isShortcut = description.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT); + return mDragLayout.drop(event, dragSurface, (dropTargetBounds) -> { + if (dropTargetBounds != null && data.getItemCount() > 0) { + final Intent intent = data.getItemAt(0).getIntent(); + // TODO(b/169894807): Properly handle the drop, for now just launch it + if (isTask) { + int taskId = intent.getIntExtra(EXTRA_TASK_ID, INVALID_TASK_ID); + try { + ActivityTaskManager.getService().startActivityFromRecents( + taskId, null); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to launch task", e); + } + } else if (isShortcut) { + try { + Bundle opts = intent.hasExtra(EXTRA_ACTIVITY_OPTIONS) + ? intent.getBundleExtra(EXTRA_ACTIVITY_OPTIONS) + : null; + LauncherApps launcherApps = + mContext.getSystemService(LauncherApps.class); + launcherApps.startShortcut( + intent.getStringExtra(EXTRA_PACKAGE_NAME), + intent.getStringExtra(EXTRA_SHORTCUT_ID), + null /* sourceBounds */, opts, + intent.getParcelableExtra(EXTRA_USER)); + } catch (ActivityNotFoundException e) { + Slog.e(TAG, "Failed to launch shortcut", e); + } + } else { + PendingIntent pi = intent.getParcelableExtra(EXTRA_PENDING_INTENT); + try { + pi.send(); + } catch (PendingIntent.CanceledException e) { + Slog.e(TAG, "Failed to launch activity", e); + } + } + } + + setDropTargetWindowVisibility(pd, View.INVISIBLE); + pd.dropTarget.removeView(dragLayout); + + // Clean up the drag surface + mTransaction.reparent(dragSurface, null); + mTransaction.apply(); + }); + } + private void setDropTargetWindowVisibility(PerDisplay pd, int visibility) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Set drop target window visibility: displayId=%d visibility=%d", diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java index 3ded4091ec11..8d5da1a5ffcb 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java @@ -22,10 +22,8 @@ import android.app.PictureInPictureParams; import android.content.ComponentName; import android.content.pm.ActivityInfo; import android.graphics.Rect; -import android.media.session.MediaController; import com.android.wm.shell.pip.phone.PipTouchHandler; -import com.android.wm.shell.pip.tv.PipController; import java.io.PrintWriter; import java.util.function.Consumer; @@ -35,19 +33,6 @@ import java.util.function.Consumer; */ public interface Pip { /** - * Registers {@link com.android.wm.shell.pip.tv.PipController.Listener} that gets called. - * whenever receiving notification on changes in PIP. - */ - default void addListener(PipController.Listener listener) { - } - - /** - * Registers a {@link PipController.MediaListener} to PipController. - */ - default void addMediaListener(PipController.MediaListener listener) { - } - - /** * Closes PIP (PIPed activity and PIP system UI). */ default void closePip() { @@ -68,17 +53,8 @@ public interface Pip { } /** - * Get current play back state. (e.g: Used in TV) - * - * @return The state of defined in PipController. - */ - default int getPlaybackState() { - return -1; - } - - /** * Get the touch handler which manages all the touch handling for PIP on the Phone, - * including moving, dismissing and expanding the PIP. (Do not used in TV) + * including moving, dismissing and expanding the PIP. (Do not use in TV) * * @return */ @@ -87,15 +63,6 @@ public interface Pip { } /** - * Get MediaController. - * - * @return The MediaController instance. - */ - default MediaController getMediaController() { - return null; - } - - /** * Hides the PIP menu. */ default void hidePipMenu(Runnable onStartCallback, Runnable onEndCallback) {} @@ -171,18 +138,6 @@ public interface Pip { } /** - * Removes a {@link PipController.Listener} from PipController. - */ - default void removeListener(PipController.Listener listener) { - } - - /** - * Removes a {@link PipController.MediaListener} from PipController. - */ - default void removeMediaListener(PipController.MediaListener listener) { - } - - /** * Resize the Pip to the appropriate size for the input state. * * @param state In Pip state also used to determine the new size for the Pip. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMediaController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMediaController.java index 64e3758fd81a..a7c34fd4465a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMediaController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMediaController.java @@ -14,12 +14,11 @@ * limitations under the License. */ -package com.android.wm.shell.pip.phone; +package com.android.wm.shell.pip; import static android.app.PendingIntent.FLAG_IMMUTABLE; import static android.app.PendingIntent.FLAG_UPDATE_CURRENT; -import android.app.IActivityManager; import android.app.PendingIntent; import android.app.RemoteAction; import android.content.BroadcastReceiver; @@ -28,11 +27,14 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.graphics.drawable.Icon; +import android.media.MediaMetadata; import android.media.session.MediaController; import android.media.session.MediaSessionManager; import android.media.session.PlaybackState; import android.os.UserHandle; +import androidx.annotation.Nullable; + import com.android.wm.shell.R; import java.util.ArrayList; @@ -46,10 +48,10 @@ import java.util.List; */ public class PipMediaController { - private static final String ACTION_PLAY = "com.android.wm.shell.pip.phone.PLAY"; - private static final String ACTION_PAUSE = "com.android.wm.shell.pip.phone.PAUSE"; - private static final String ACTION_NEXT = "com.android.wm.shell.pip.phone.NEXT"; - private static final String ACTION_PREV = "com.android.wm.shell.pip.phone.PREV"; + private static final String ACTION_PLAY = "com.android.wm.shell.pip.PLAY"; + private static final String ACTION_PAUSE = "com.android.wm.shell.pip.PAUSE"; + private static final String ACTION_NEXT = "com.android.wm.shell.pip.NEXT"; + private static final String ACTION_PREV = "com.android.wm.shell.pip.PREV"; /** * A listener interface to receive notification on changes to the media actions. @@ -61,8 +63,17 @@ public class PipMediaController { void onMediaActionsChanged(List<RemoteAction> actions); } + /** + * A listener interface to receive notification on changes to the media metadata. + */ + public interface MetadataListener { + /** + * Called when the media metadata changes. + */ + void onMediaMetadataChanged(MediaMetadata metadata); + } + private final Context mContext; - private final IActivityManager mActivityManager; private final MediaSessionManager mMediaSessionManager; private MediaController mMediaController; @@ -94,16 +105,21 @@ public class PipMediaController { public void onPlaybackStateChanged(PlaybackState state) { notifyActionsChanged(); } + + @Override + public void onMetadataChanged(@Nullable MediaMetadata metadata) { + notifyMetadataChanged(metadata); + } }; private final MediaSessionManager.OnActiveSessionsChangedListener mSessionsChangedListener = - controllers -> resolveActiveMediaController(controllers); + this::resolveActiveMediaController; - private ArrayList<ActionListener> mListeners = new ArrayList<>(); + private final ArrayList<ActionListener> mActionListeners = new ArrayList<>(); + private final ArrayList<MetadataListener> mMetadataListeners = new ArrayList<>(); - public PipMediaController(Context context, IActivityManager activityManager) { + public PipMediaController(Context context) { mContext = context; - mActivityManager = activityManager; IntentFilter mediaControlFilter = new IntentFilter(); mediaControlFilter.addAction(ACTION_PLAY); mediaControlFilter.addAction(ACTION_PAUSE); @@ -113,8 +129,7 @@ public class PipMediaController { UserHandle.USER_ALL); createMediaActions(); - mMediaSessionManager = - (MediaSessionManager) context.getSystemService(Context.MEDIA_SESSION_SERVICE); + mMediaSessionManager = context.getSystemService(MediaSessionManager.class); } /** @@ -129,9 +144,9 @@ public class PipMediaController { /** * Adds a new media action listener. */ - public void addListener(ActionListener listener) { - if (!mListeners.contains(listener)) { - mListeners.add(listener); + public void addActionListener(ActionListener listener) { + if (!mActionListeners.contains(listener)) { + mActionListeners.add(listener); listener.onMediaActionsChanged(getMediaActions()); } } @@ -139,9 +154,31 @@ public class PipMediaController { /** * Removes a media action listener. */ - public void removeListener(ActionListener listener) { - listener.onMediaActionsChanged(Collections.EMPTY_LIST); - mListeners.remove(listener); + public void removeActionListener(ActionListener listener) { + listener.onMediaActionsChanged(Collections.emptyList()); + mActionListeners.remove(listener); + } + + /** + * Adds a new media metadata listener. + */ + public void addMetadataListener(MetadataListener listener) { + if (!mMetadataListeners.contains(listener)) { + mMetadataListeners.add(listener); + listener.onMediaMetadataChanged(getMediaMetadata()); + } + } + + /** + * Removes a media metadata listener. + */ + public void removeMetadataListener(MetadataListener listener) { + listener.onMediaMetadataChanged(null); + mMetadataListeners.remove(listener); + } + + private MediaMetadata getMediaMetadata() { + return mMediaController != null ? mMediaController.getMetadata() : null; } /** @@ -149,7 +186,7 @@ public class PipMediaController { */ private List<RemoteAction> getMediaActions() { if (mMediaController == null || mMediaController.getPlaybackState() == null) { - return Collections.EMPTY_LIST; + return Collections.emptyList(); } ArrayList<RemoteAction> mediaActions = new ArrayList<>(); @@ -216,8 +253,7 @@ public class PipMediaController { */ private void resolveActiveMediaController(List<MediaController> controllers) { if (controllers != null) { - final ComponentName topActivity = PipUtils.getTopPipActivity(mContext, - mActivityManager).first; + final ComponentName topActivity = PipUtils.getTopPipActivity(mContext).first; if (topActivity != null) { for (int i = 0; i < controllers.size(); i++) { final MediaController controller = controllers.get(i); @@ -244,6 +280,7 @@ public class PipMediaController { controller.registerCallback(mPlaybackChangedListener); } notifyActionsChanged(); + notifyMetadataChanged(getMediaMetadata()); // TODO(winsonc): Consider if we want to close the PIP after a timeout (like on TV) } @@ -253,9 +290,18 @@ public class PipMediaController { * Notifies all listeners that the actions have changed. */ private void notifyActionsChanged() { - if (!mListeners.isEmpty()) { + if (!mActionListeners.isEmpty()) { List<RemoteAction> actions = getMediaActions(); - mListeners.forEach(l -> l.onMediaActionsChanged(actions)); + mActionListeners.forEach(l -> l.onMediaActionsChanged(actions)); + } + } + + /** + * Notifies all listeners that the metadata have changed. + */ + private void notifyMetadataChanged(MediaMetadata metadata) { + if (!mMetadataListeners.isEmpty()) { + mMetadataListeners.forEach(l -> l.onMediaMetadataChanged(metadata)); } } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java index a05aac9dfe3e..d223934fcf34 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java @@ -60,6 +60,7 @@ import android.window.WindowContainerToken; import android.window.WindowContainerTransaction; import android.window.WindowContainerTransactionCallback; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.jank.InteractionJankMonitor; import com.android.internal.os.SomeArgs; import com.android.wm.shell.R; @@ -550,7 +551,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, return null; } - private void enterPipWithAlphaAnimation(Rect destinationBounds, long durationMs) { + @VisibleForTesting + void enterPipWithAlphaAnimation(Rect destinationBounds, long durationMs) { // If we are fading the PIP in, then we should move the pip to the final location as // soon as possible, but set the alpha immediately since the transaction can take a // while to process diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUtils.java index bd2ba32912bc..da6d9804b29d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipUtils.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUtils.java @@ -14,20 +14,20 @@ * limitations under the License. */ -package com.android.wm.shell.pip.phone; +package com.android.wm.shell.pip; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import android.app.ActivityTaskManager; import android.app.ActivityTaskManager.RootTaskInfo; -import android.app.IActivityManager; import android.content.ComponentName; import android.content.Context; import android.os.RemoteException; import android.util.Log; import android.util.Pair; +/** A class that includes convenience methods. */ public class PipUtils { private static final String TAG = "PipUtils"; @@ -35,8 +35,7 @@ public class PipUtils { * @return the ComponentName and user id of the top non-SystemUI activity in the pinned stack. * The component name may be null if no such activity exists. */ - public static Pair<ComponentName, Integer> getTopPipActivity(Context context, - IActivityManager activityManager) { + public static Pair<ComponentName, Integer> getTopPipActivity(Context context) { try { final String sysUiPackageName = context.getPackageName(); final RootTaskInfo pinnedTaskInfo = ActivityTaskManager.getService().getRootTaskInfo( diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAppOpsListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAppOpsListener.java index 6b6b5211b10a..2cd010796799 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAppOpsListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAppOpsListener.java @@ -29,6 +29,8 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.os.Handler; import android.util.Pair; +import com.android.wm.shell.pip.PipUtils; + public class PipAppOpsListener { private static final String TAG = PipAppOpsListener.class.getSimpleName(); @@ -44,7 +46,7 @@ public class PipAppOpsListener { try { // Dismiss the PiP once the user disables the app ops setting for that package final Pair<ComponentName, Integer> topPipActivityInfo = - PipUtils.getTopPipActivity(mContext, mActivityManager); + PipUtils.getTopPipActivity(mContext); if (topPipActivityInfo.first != null) { final ApplicationInfo appInfo = mContext.getPackageManager() .getApplicationInfoAsUser(packageName, 0, topPipActivityInfo.second); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java index 823979b861b4..37a5919b1c9e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java @@ -29,7 +29,6 @@ import android.content.Context; import android.content.pm.ActivityInfo; import android.content.pm.ParceledListSlice; import android.graphics.Rect; -import android.os.Handler; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; @@ -45,10 +44,12 @@ import com.android.wm.shell.WindowManagerShellWrapper; import com.android.wm.shell.common.DisplayChangeController; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayLayout; +import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.pip.PinnedStackListenerForwarder; import com.android.wm.shell.pip.Pip; import com.android.wm.shell.pip.PipBoundsHandler; import com.android.wm.shell.pip.PipBoundsState; +import com.android.wm.shell.pip.PipMediaController; import com.android.wm.shell.pip.PipTaskOrganizer; import java.io.PrintWriter; @@ -61,7 +62,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac private static final String TAG = "PipController"; private Context mContext; - private Handler mHandler = new Handler(); + private ShellExecutor mMainExecutor; private final DisplayInfo mTmpDisplayInfo = new DisplayInfo(); private final Rect mTmpInsetBounds = new Rect(); @@ -81,6 +82,8 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac protected PipMenuActivityController mMenuController; protected PipTaskOrganizer mPipTaskOrganizer; + protected PinnedStackListenerForwarder.PinnedStackListener mPinnedStackListener = + new PipControllerPinnedStackListener(); /** * Handler for display rotation changes. @@ -149,12 +152,12 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac PinnedStackListenerForwarder.PinnedStackListener { @Override public void onListenerRegistered(IPinnedStackController controller) { - mHandler.post(() -> mTouchHandler.setPinnedStackController(controller)); + mMainExecutor.execute(() -> mTouchHandler.setPinnedStackController(controller)); } @Override public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) { - mHandler.post(() -> { + mMainExecutor.execute(() -> { mPipBoundsHandler.onImeVisibilityChanged(imeVisible, imeHeight); mTouchHandler.onImeVisibilityChanged(imeVisible, imeHeight); }); @@ -162,19 +165,19 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac @Override public void onMovementBoundsChanged(boolean fromImeAdjustment) { - mHandler.post(() -> updateMovementBounds(null /* toBounds */, + mMainExecutor.execute(() -> updateMovementBounds(null /* toBounds */, false /* fromRotation */, fromImeAdjustment, false /* fromShelfAdjustment */, null /* windowContainerTransaction */)); } @Override public void onActionsChanged(ParceledListSlice<RemoteAction> actions) { - mHandler.post(() -> mMenuController.setAppActions(actions)); + mMainExecutor.execute(() -> mMenuController.setAppActions(actions)); } @Override public void onActivityHidden(ComponentName componentName) { - mHandler.post(() -> { + mMainExecutor.execute(() -> { if (componentName.equals(mPipBoundsState.getLastPipComponentName())) { // The activity was removed, we don't want to restore to the reentry state // saved for this component anymore. @@ -185,12 +188,12 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac @Override public void onDisplayInfoChanged(DisplayInfo displayInfo) { - mHandler.post(() -> mPipBoundsState.setDisplayInfo(displayInfo)); + mMainExecutor.execute(() -> mPipBoundsState.setDisplayInfo(displayInfo)); } @Override public void onConfigurationChanged() { - mHandler.post(() -> { + mMainExecutor.execute(() -> { mPipBoundsHandler.onConfigurationChanged(mContext); mTouchHandler.onConfigurationChanged(); }); @@ -200,7 +203,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac public void onAspectRatioChanged(float aspectRatio) { // TODO(b/169373982): Remove this callback as it is redundant with PipTaskOrg params // change. - mHandler.post(() -> { + mMainExecutor.execute(() -> { mPipBoundsState.setAspectRatio(aspectRatio); mTouchHandler.onAspectRatioChanged(); }); @@ -216,7 +219,8 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac PipMenuActivityController pipMenuActivityController, PipTaskOrganizer pipTaskOrganizer, PipTouchHandler pipTouchHandler, - WindowManagerShellWrapper windowManagerShellWrapper + WindowManagerShellWrapper windowManagerShellWrapper, + ShellExecutor mainExecutor ) { // Ensure that we are the primary user's SystemUI. final int processUser = UserManager.get(context).getUserHandle(); @@ -230,6 +234,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac mPipBoundsHandler = pipBoundsHandler; mPipBoundsState = pipBoundsState; mPipTaskOrganizer = pipTaskOrganizer; + mMainExecutor = mainExecutor; mPipTaskOrganizer.registerPipTransitionCallback(this); mPipTaskOrganizer.registerOnDisplayIdChangeCallback((int displayId) -> { final DisplayInfo newDisplayInfo = new DisplayInfo(); @@ -253,8 +258,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac mPipBoundsState.setDisplayInfo(displayInfo); try { - mWindowManagerShellWrapper.addPinnedStackListener( - new PipControllerPinnedStackListener()); + mWindowManagerShellWrapper.addPinnedStackListener(mPinnedStackListener); } catch (RemoteException e) { Slog.e(TAG, "Failed to register pinned stack listener", e); } @@ -262,14 +266,14 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac @Override public void onDensityOrFontScaleChanged() { - mHandler.post(() -> { + mMainExecutor.execute(() -> { mPipTaskOrganizer.onDensityOrFontScaleChanged(mContext); }); } @Override public void onActivityPinned(String packageName) { - mHandler.post(() -> { + mMainExecutor.execute(() -> { mTouchHandler.onActivityPinned(); mMediaController.onActivityPinned(); mMenuController.onActivityPinned(); @@ -279,7 +283,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac @Override public void onActivityUnpinned(ComponentName topActivity) { - mHandler.post(() -> { + mMainExecutor.execute(() -> { mMenuController.onActivityUnpinned(); mTouchHandler.onActivityUnpinned(topActivity); mAppOpsListener.onActivityUnpinned(); @@ -298,7 +302,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac @Override public void onOverlayChanged() { - mHandler.post(() -> { + mMainExecutor.execute(() -> { mPipBoundsState.setDisplayLayout(new DisplayLayout(mContext, mContext.getDisplay())); updateMovementBounds(null /* toBounds */, false /* fromRotation */, false /* fromImeAdjustment */, @@ -357,7 +361,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac */ @Override public void setShelfHeight(boolean visible, int height) { - mHandler.post(() -> setShelfHeightLocked(visible, height)); + mMainExecutor.execute(() -> setShelfHeightLocked(visible, height)); } private void setShelfHeightLocked(boolean visible, int height) { @@ -373,12 +377,12 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac @Override public void setPinnedStackAnimationType(int animationType) { - mHandler.post(() -> mPipTaskOrganizer.setOneShotAnimationType(animationType)); + mMainExecutor.execute(() -> mPipTaskOrganizer.setOneShotAnimationType(animationType)); } @Override public void setPinnedStackAnimationListener(Consumer<Boolean> callback) { - mHandler.post(() -> mPinnedStackAnimationRecentsCallback = callback); + mMainExecutor.execute(() -> mPinnedStackAnimationRecentsCallback = callback); } @Override @@ -475,7 +479,8 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac PipBoundsState pipBoundsState, PipMediaController pipMediaController, PipMenuActivityController pipMenuActivityController, PipTaskOrganizer pipTaskOrganizer, PipTouchHandler pipTouchHandler, - WindowManagerShellWrapper windowManagerShellWrapper) { + WindowManagerShellWrapper windowManagerShellWrapper, + ShellExecutor mainExecutor) { if (!context.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) { Slog.w(TAG, "Device doesn't support Pip feature"); return null; @@ -483,6 +488,6 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac return new PipController(context, displayController, pipAppOpsListener, pipBoundsHandler, pipBoundsState, pipMediaController, pipMenuActivityController, - pipTaskOrganizer, pipTouchHandler, windowManagerShellWrapper); + pipTaskOrganizer, pipTouchHandler, windowManagerShellWrapper, mainExecutor); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuActivityController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuActivityController.java index cd47d55da7f0..a87fa20a7f11 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuActivityController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuActivityController.java @@ -34,8 +34,9 @@ import android.view.MotionEvent; import android.view.WindowManager; import android.view.WindowManagerGlobal; +import com.android.wm.shell.pip.PipMediaController; +import com.android.wm.shell.pip.PipMediaController.ActionListener; import com.android.wm.shell.pip.PipTaskOrganizer; -import com.android.wm.shell.pip.phone.PipMediaController.ActionListener; import java.io.PrintWriter; import java.util.ArrayList; @@ -342,11 +343,11 @@ public class PipMenuActivityController { if (menuState == MENU_STATE_FULL) { // Once visible, start listening for media action changes. This call will trigger // the menu actions to be updated again. - mMediaController.addListener(mMediaActionListener); + mMediaController.addActionListener(mMediaActionListener); } else { // Once hidden, stop listening for media action changes. This call will trigger // the menu actions to be updated again. - mMediaController.removeListener(mMediaActionListener); + mMediaController.removeActionListener(mMediaActionListener); } try { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java index 51951409f76c..3e06ec44989e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java @@ -32,7 +32,6 @@ import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; -import android.app.ActivityManager; import android.app.PendingIntent.CanceledException; import android.app.RemoteAction; import android.content.ComponentName; @@ -61,6 +60,7 @@ import android.widget.LinearLayout; import com.android.wm.shell.R; import com.android.wm.shell.animation.Interpolators; +import com.android.wm.shell.pip.PipUtils; import java.util.ArrayList; import java.util.List; @@ -452,7 +452,7 @@ public class PipMenuView extends FrameLayout { private void showSettings() { final Pair<ComponentName, Integer> topPipActivityInfo = - PipUtils.getTopPipActivity(mContext, ActivityManager.getService()); + PipUtils.getTopPipActivity(mContext); if (topPipActivityInfo.first != null) { final Intent settingsIntent = new Intent(ACTION_PICTURE_IN_PICTURE_SETTINGS, Uri.fromParts("package", topPipActivityInfo.first.getPackageName(), null)); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java index b27af656f209..7b710553b67d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java @@ -38,9 +38,6 @@ import android.content.pm.ParceledListSlice; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Rect; -import android.media.session.MediaController; -import android.media.session.MediaSessionManager; -import android.media.session.PlaybackState; import android.os.Debug; import android.os.Handler; import android.os.RemoteException; @@ -55,6 +52,7 @@ import com.android.wm.shell.pip.PinnedStackListenerForwarder; import com.android.wm.shell.pip.Pip; import com.android.wm.shell.pip.PipBoundsHandler; import com.android.wm.shell.pip.PipBoundsState; +import com.android.wm.shell.pip.PipMediaController; import com.android.wm.shell.pip.PipTaskOrganizer; import java.util.ArrayList; @@ -106,26 +104,23 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac private int mSuspendPipResizingReason; - private Context mContext; - private PipBoundsState mPipBoundsState; - private PipBoundsHandler mPipBoundsHandler; - private PipTaskOrganizer mPipTaskOrganizer; + private final Context mContext; + private final PipBoundsState mPipBoundsState; + private final PipBoundsHandler mPipBoundsHandler; + private final PipTaskOrganizer mPipTaskOrganizer; + private final PipMediaController mPipMediaController; + private IActivityTaskManager mActivityTaskManager; - private MediaSessionManager mMediaSessionManager; private int mState = STATE_NO_PIP; private int mResumeResizePinnedStackRunnableState = STATE_NO_PIP; private final Handler mHandler = new Handler(); private List<Listener> mListeners = new ArrayList<>(); - private List<MediaListener> mMediaListeners = new ArrayList<>(); private Rect mPipBounds; private Rect mDefaultPipBounds = new Rect(); private Rect mMenuModePipBounds; private int mLastOrientation = Configuration.ORIENTATION_UNDEFINED; - private boolean mInitialized; private int mPipTaskId = TASK_ID_NO_PIP; private int mPinnedStackId = INVALID_STACK_ID; - private ComponentName mPipComponentName; - private MediaController mPipMediaController; private String[] mLastPackagesResourceGranted; private PipNotification mPipNotification; private ParceledListSlice<RemoteAction> mCustomActions; @@ -168,17 +163,13 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac } } }; - private final MediaSessionManager.OnActiveSessionsChangedListener mActiveMediaSessionListener = - controllers -> updateMediaController(controllers); + private final PinnedStackListenerForwarder.PinnedStackListener mPinnedStackListener = new PipControllerPinnedStackListener(); @Override public void registerSessionListenerForCurrentUser() { - // TODO Need confirm if TV have to re-registers when switch user - mMediaSessionManager.removeOnActiveSessionsChangedListener(mActiveMediaSessionListener); - mMediaSessionManager.addOnActiveSessionsChangedListener(mActiveMediaSessionListener, null, - UserHandle.USER_CURRENT, null); + mPipMediaController.registerSessionListenerForCurrentUser(); } /** @@ -232,48 +223,45 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac PipBoundsState pipBoundsState, PipBoundsHandler pipBoundsHandler, PipTaskOrganizer pipTaskOrganizer, - WindowManagerShellWrapper windowManagerShellWrapper - ) { - if (!mInitialized) { - mInitialized = true; - mContext = context; - mPipBoundsState = pipBoundsState; - mPipNotification = new PipNotification(context, this); - mPipBoundsHandler = pipBoundsHandler; - // Ensure that we have the display info in case we get calls to update the bounds - // before the listener calls back - final DisplayInfo displayInfo = new DisplayInfo(); - context.getDisplay().getDisplayInfo(displayInfo); - mPipBoundsState.setDisplayInfo(displayInfo); - - mResizeAnimationDuration = context.getResources() - .getInteger(R.integer.config_pipResizeAnimationDuration); - mPipTaskOrganizer = pipTaskOrganizer; - mPipTaskOrganizer.registerPipTransitionCallback(this); - mActivityTaskManager = ActivityTaskManager.getService(); - - final IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(ACTION_CLOSE); - intentFilter.addAction(ACTION_MENU); - intentFilter.addAction(ACTION_MEDIA_RESOURCE_GRANTED); - mContext.registerReceiver(mBroadcastReceiver, intentFilter, UserHandle.USER_ALL); - - // Initialize the last orientation and apply the current configuration - Configuration initialConfig = mContext.getResources().getConfiguration(); - mLastOrientation = initialConfig.orientation; - loadConfigurationsAndApply(initialConfig); - - mMediaSessionManager = mContext.getSystemService(MediaSessionManager.class); - mWindowManagerShellWrapper = windowManagerShellWrapper; - try { - mWindowManagerShellWrapper.addPinnedStackListener(mPinnedStackListener); - } catch (RemoteException e) { - Log.e(TAG, "Failed to register pinned stack listener", e); - } - - // TODO(b/169395392) Refactor PipMenuActivity to PipMenuView - PipMenuActivity.setPipController(this); + PipMediaController pipMediaController, + WindowManagerShellWrapper windowManagerShellWrapper) { + mContext = context; + mPipBoundsState = pipBoundsState; + mPipNotification = new PipNotification(context, this); + mPipBoundsHandler = pipBoundsHandler; + mPipMediaController = pipMediaController; + // Ensure that we have the display info in case we get calls to update the bounds + // before the listener calls back + final DisplayInfo displayInfo = new DisplayInfo(); + context.getDisplay().getDisplayInfo(displayInfo); + mPipBoundsState.setDisplayInfo(displayInfo); + + mResizeAnimationDuration = context.getResources() + .getInteger(R.integer.config_pipResizeAnimationDuration); + mPipTaskOrganizer = pipTaskOrganizer; + mPipTaskOrganizer.registerPipTransitionCallback(this); + mActivityTaskManager = ActivityTaskManager.getService(); + + final IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(ACTION_CLOSE); + intentFilter.addAction(ACTION_MENU); + intentFilter.addAction(ACTION_MEDIA_RESOURCE_GRANTED); + mContext.registerReceiver(mBroadcastReceiver, intentFilter, UserHandle.USER_ALL); + + // Initialize the last orientation and apply the current configuration + Configuration initialConfig = mContext.getResources().getConfiguration(); + mLastOrientation = initialConfig.orientation; + loadConfigurationsAndApply(initialConfig); + + mWindowManagerShellWrapper = windowManagerShellWrapper; + try { + mWindowManagerShellWrapper.addPinnedStackListener(mPinnedStackListener); + } catch (RemoteException e) { + Log.e(TAG, "Failed to register pinned stack listener", e); } + + // TODO(b/169395392) Refactor PipMenuActivity to PipMenuView + PipMenuActivity.setPipController(this); } private void loadConfigurationsAndApply(Configuration newConfig) { @@ -332,8 +320,6 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac mState = STATE_NO_PIP; mPipTaskId = TASK_ID_NO_PIP; - mPipMediaController = null; - mMediaSessionManager.removeOnActiveSessionsChangedListener(mActiveMediaSessionListener); if (removePipStack) { try { mActivityTaskManager.removeTask(mPinnedStackId); @@ -374,13 +360,9 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac if (DEBUG) Log.d(TAG, "PINNED_STACK:" + taskInfo); mPinnedStackId = taskInfo.taskId; mPipTaskId = taskInfo.childTaskIds[taskInfo.childTaskIds.length - 1]; - mPipComponentName = ComponentName.unflattenFromString( - taskInfo.childTaskNames[taskInfo.childTaskNames.length - 1]); // Set state to STATE_PIP so we show it when the pinned stack animation ends. mState = STATE_PIP; - mMediaSessionManager.addOnActiveSessionsChangedListener( - mActiveMediaSessionListener, null); - updateMediaController(mMediaSessionManager.getActiveSessions(null)); + mPipMediaController.onActivityPinned(); for (int i = mListeners.size() - 1; i >= 0; i--) { mListeners.get(i).onPipEntered(packageName); } @@ -545,32 +527,18 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac /** * Adds a {@link Listener} to PipController. */ - public void addListener(Listener listener) { + void addListener(Listener listener) { mListeners.add(listener); } /** * Removes a {@link Listener} from PipController. */ - public void removeListener(Listener listener) { + void removeListener(Listener listener) { mListeners.remove(listener); } /** - * Adds a {@link MediaListener} to PipController. - */ - public void addMediaListener(MediaListener listener) { - mMediaListeners.add(listener); - } - - /** - * Removes a {@link MediaListener} from PipController. - */ - public void removeMediaListener(MediaListener listener) { - mMediaListeners.remove(listener); - } - - /** * Returns {@code true} if PIP is shown. */ public boolean isPipShown() { @@ -611,69 +579,12 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac } } - private void updateMediaController(List<MediaController> controllers) { - MediaController mediaController = null; - if (controllers != null && getState() != STATE_NO_PIP && mPipComponentName != null) { - for (int i = controllers.size() - 1; i >= 0; i--) { - MediaController controller = controllers.get(i); - // We assumes that an app with PIPable activity - // keeps the single instance of media controller especially when PIP is on. - if (controller.getPackageName().equals(mPipComponentName.getPackageName())) { - mediaController = controller; - break; - } - } - } - if (mPipMediaController != mediaController) { - mPipMediaController = mediaController; - for (int i = mMediaListeners.size() - 1; i >= 0; i--) { - mMediaListeners.get(i).onMediaControllerChanged(); - } - if (mPipMediaController == null) { - mHandler.postDelayed(mClosePipRunnable, - CLOSE_PIP_WHEN_MEDIA_SESSION_GONE_TIMEOUT_MS); - } else { - mHandler.removeCallbacks(mClosePipRunnable); - } - } - } - - /** - * Gets the {@link android.media.session.MediaController} for the PIPed activity. - */ - public MediaController getMediaController() { - return mPipMediaController; - } - @Override public void hidePipMenu(Runnable onStartCallback, Runnable onEndCallback) { - } - /** - * Returns the PIPed activity's playback state. - * This returns one of {@link #PLAYBACK_STATE_PLAYING}, {@link #PLAYBACK_STATE_PAUSED}, - * or {@link #PLAYBACK_STATE_UNAVAILABLE}. - */ - public int getPlaybackState() { - if (mPipMediaController == null || mPipMediaController.getPlaybackState() == null) { - return PLAYBACK_STATE_UNAVAILABLE; - } - int state = mPipMediaController.getPlaybackState().getState(); - boolean isPlaying = (state == PlaybackState.STATE_BUFFERING - || state == PlaybackState.STATE_CONNECTING - || state == PlaybackState.STATE_PLAYING - || state == PlaybackState.STATE_FAST_FORWARDING - || state == PlaybackState.STATE_REWINDING - || state == PlaybackState.STATE_SKIPPING_TO_PREVIOUS - || state == PlaybackState.STATE_SKIPPING_TO_NEXT); - long actions = mPipMediaController.getPlaybackState().getActions(); - if (!isPlaying && ((actions & PlaybackState.ACTION_PLAY) != 0)) { - return PLAYBACK_STATE_PAUSED; - } else if (isPlaying && ((actions & PlaybackState.ACTION_PAUSE) != 0)) { - return PLAYBACK_STATE_PLAYING; - } - return PLAYBACK_STATE_UNAVAILABLE; + PipMediaController getPipMediaController() { + return mPipMediaController; } @Override @@ -721,14 +632,6 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac void onPipResizeAboutToStart(); } - /** - * A listener interface to receive change in PIP's media controller - */ - public interface MediaListener { - /** Invoked when the MediaController on PIPed activity is changed. */ - void onMediaControllerChanged(); - } - private String getStateDescription() { if (mSuspendPipResizingReason == 0) { return stateToName(mState); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipControlsView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipControlsView.java index 14960c38fd43..95d9b77c513e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipControlsView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipControlsView.java @@ -51,15 +51,11 @@ public class PipControlsView extends LinearLayout { setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL); } - PipControlButtonView getFullButtonView() { + PipControlButtonView getFullscreenButton() { return findViewById(R.id.full_button); } - PipControlButtonView getCloseButtonView() { + PipControlButtonView getCloseButton() { return findViewById(R.id.close_button); } - - PipControlButtonView getPlayPauseButtonView() { - return findViewById(R.id.play_pause_button); - } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipControlsViewController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipControlsViewController.java index f66e9025a9ed..5265e7705ed9 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipControlsViewController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipControlsViewController.java @@ -18,10 +18,10 @@ package com.android.wm.shell.pip.tv; import android.app.PendingIntent; import android.app.RemoteAction; +import android.content.Context; import android.graphics.Color; -import android.media.session.MediaController; -import android.media.session.PlaybackState; import android.os.Handler; +import android.os.Looper; import android.util.Log; import android.view.LayoutInflater; import android.view.View; @@ -29,9 +29,8 @@ import android.view.View; import com.android.wm.shell.R; import java.util.ArrayList; +import java.util.Collections; import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; /** @@ -42,213 +41,118 @@ public class PipControlsViewController { private static final float DISABLED_ACTION_ALPHA = 0.54f; - private final PipControlsView mView; - private final LayoutInflater mLayoutInflater; - private final Handler mHandler; private final PipController mPipController; - private final PipControlButtonView mPlayPauseButtonView; - private MediaController mMediaController; - private PipControlButtonView mFocusedChild; - private Listener mListener; - private ArrayList<PipControlButtonView> mCustomButtonViews = new ArrayList<>(); - private List<RemoteAction> mCustomActions = new ArrayList<>(); - - public PipControlsView getView() { - return mView; - } - - /** - * An interface to listen user action. - */ - public interface Listener { - /** - * Called when a user clicks close PIP button. - */ - void onClosed(); - } - private View.OnAttachStateChangeListener - mOnAttachStateChangeListener = - new View.OnAttachStateChangeListener() { - @Override - public void onViewAttachedToWindow(View v) { - updateMediaController(); - mPipController.addMediaListener(mPipMediaListener); - } + private final Context mContext; + private final Handler mUiThreadHandler; + private final PipControlsView mView; + private final List<PipControlButtonView> mAdditionalButtons = new ArrayList<>(); - @Override - public void onViewDetachedFromWindow(View v) { - mPipController.removeMediaListener(mPipMediaListener); - } - }; + private final List<RemoteAction> mCustomActions = new ArrayList<>(); + private final List<RemoteAction> mMediaActions = new ArrayList<>(); - private MediaController.Callback mMediaControllerCallback = new MediaController.Callback() { - @Override - public void onPlaybackStateChanged(PlaybackState state) { - updateUserActions(); - } - }; - - private final PipController.MediaListener mPipMediaListener = this::updateMediaController; - - private final View.OnFocusChangeListener - mFocusChangeListener = - new View.OnFocusChangeListener() { - @Override - public void onFocusChange(View view, boolean hasFocus) { - if (hasFocus) { - mFocusedChild = (PipControlButtonView) view; - } else if (mFocusedChild == view) { - mFocusedChild = null; - } - } - }; - - public PipControlsViewController(PipControlsView view, PipController pipController, - LayoutInflater layoutInflater, Handler handler) { - super(); - mView = view; + public PipControlsViewController(PipControlsView view, PipController pipController) { + mContext = view.getContext(); + mUiThreadHandler = new Handler(Looper.getMainLooper()); mPipController = pipController; - mLayoutInflater = layoutInflater; - mHandler = handler; - - mView.addOnAttachStateChangeListener(mOnAttachStateChangeListener); - if (mView.isAttachedToWindow()) { - mOnAttachStateChangeListener.onViewAttachedToWindow(mView); - } - - View fullButtonView = mView.getFullButtonView(); - fullButtonView.setOnFocusChangeListener(mFocusChangeListener); - fullButtonView.setOnClickListener(mView -> mPipController.movePipToFullscreen()); - - View closeButtonView = mView.getCloseButtonView(); - closeButtonView.setOnFocusChangeListener(mFocusChangeListener); - closeButtonView.setOnClickListener(v -> { - mPipController.closePip(); - if (mListener != null) { - mListener.onClosed(); - } - }); + mView = view; - mPlayPauseButtonView = mView.getPlayPauseButtonView(); - mPlayPauseButtonView.setOnFocusChangeListener(mFocusChangeListener); - mPlayPauseButtonView.setOnClickListener(v -> { - if (mMediaController == null || mMediaController.getPlaybackState() == null) { - return; - } - final int playbackState = mPipController.getPlaybackState(); - if (playbackState == PipController.PLAYBACK_STATE_PAUSED) { - mMediaController.getTransportControls().play(); - } else if (playbackState == PipController.PLAYBACK_STATE_PLAYING) { - mMediaController.getTransportControls().pause(); - } + mView.getFullscreenButton().setOnClickListener(v -> mPipController.movePipToFullscreen()); + mView.getCloseButton().setOnClickListener(v -> mPipController.closePip()); - // View will be updated later in {@link mMediaControllerCallback} - }); + mPipController.getPipMediaController().addActionListener(this::onMediaActionsChanged); } - private void updateMediaController() { - AtomicReference<MediaController> newController = new AtomicReference<>(); - newController.set(mPipController.getMediaController()); + PipControlsView getView() { + return mView; + } - if (newController.get() == null || mMediaController == newController.get()) { + /** + * Updates the set of activity-defined actions. + */ + void setCustomActions(List<? extends RemoteAction> actions) { + if (mCustomActions.isEmpty() && actions.isEmpty()) { + // Nothing changed - return early. return; } - if (mMediaController != null) { - mMediaController.unregisterCallback(mMediaControllerCallback); + mCustomActions.clear(); + mCustomActions.addAll(actions); + updateAdditionalActions(); + } + + private void onMediaActionsChanged(List<RemoteAction> actions) { + if (mMediaActions.isEmpty() && actions.isEmpty()) { + // Nothing changed - return early. + return; } - mMediaController = newController.get(); - if (mMediaController != null) { - mMediaController.registerCallback(mMediaControllerCallback); + mMediaActions.clear(); + mMediaActions.addAll(actions); + + // Update the view only if there are no custom actions (media actions are only shown when + // there no custom actions). + if (mCustomActions.isEmpty()) { + updateAdditionalActions(); } - updateUserActions(); } - /** - * Updates the actions for the PIP. If there are no custom actions, then the media session - * actions are shown. - */ - private void updateUserActions() { + private void updateAdditionalActions() { + final List<RemoteAction> actionsToDisplay; if (!mCustomActions.isEmpty()) { - // Ensure we have as many buttons as actions - while (mCustomButtonViews.size() < mCustomActions.size()) { - PipControlButtonView buttonView = (PipControlButtonView) mLayoutInflater.inflate( + // If there are custom actions: show them. + actionsToDisplay = mCustomActions; + } else if (!mMediaActions.isEmpty()) { + // If there are no custom actions, but there media actions: show them. + actionsToDisplay = mMediaActions; + } else { + // If there no custom actions and no media actions: clean up all the additional buttons. + actionsToDisplay = Collections.emptyList(); + } + + // Make sure we exactly as many additional buttons as we have actions to display. + final int actionsNumber = actionsToDisplay.size(); + int buttonsNumber = mAdditionalButtons.size(); + if (actionsNumber > buttonsNumber) { + final LayoutInflater layoutInflater = LayoutInflater.from(mContext); + // Add buttons until we have enough to display all of the actions. + while (actionsNumber > buttonsNumber) { + final PipControlButtonView button = (PipControlButtonView) layoutInflater.inflate( R.layout.tv_pip_custom_control, mView, false); - mView.addView(buttonView); - mCustomButtonViews.add(buttonView); - } + mView.addView(button); + mAdditionalButtons.add(button); - // Update the visibility of all views - for (int i = 0; i < mCustomButtonViews.size(); i++) { - mCustomButtonViews.get(i).setVisibility( - i < mCustomActions.size() ? View.VISIBLE : View.GONE); + buttonsNumber++; } - - // Update the state and visibility of the action buttons, and hide the rest - for (int i = 0; i < mCustomActions.size(); i++) { - final RemoteAction action = mCustomActions.get(i); - PipControlButtonView actionView = mCustomButtonViews.get(i); - - // TODO: Check if the action drawable has changed before we reload it - action.getIcon().loadDrawableAsync(mView.getContext(), d -> { - d.setTint(Color.WHITE); - actionView.setImageDrawable(d); - }, mHandler); - actionView.setText(action.getContentDescription()); - if (action.isEnabled()) { - actionView.setOnClickListener(v -> { - try { - action.getActionIntent().send(); - } catch (PendingIntent.CanceledException e) { - Log.w(TAG, "Failed to send action", e); - } - }); - } - actionView.setEnabled(action.isEnabled()); - actionView.setAlpha(action.isEnabled() ? 1f : DISABLED_ACTION_ALPHA); + } else if (actionsNumber < buttonsNumber) { + // Hide buttons until we as many as the actions. + while (actionsNumber < buttonsNumber) { + final View button = mAdditionalButtons.get(buttonsNumber - 1); + button.setVisibility(View.GONE); + button.setOnClickListener(null); + + buttonsNumber--; } + } - // Hide the media session buttons - mPlayPauseButtonView.setVisibility(View.GONE); - } else { - AtomicInteger state = new AtomicInteger(PipController.STATE_UNKNOWN); - state.set(mPipController.getPlaybackState()); - if (state.get() == PipController.STATE_UNKNOWN - || state.get() == PipController.PLAYBACK_STATE_UNAVAILABLE) { - mPlayPauseButtonView.setVisibility(View.GONE); - } else { - mPlayPauseButtonView.setVisibility(View.VISIBLE); - if (state.get() == PipController.PLAYBACK_STATE_PLAYING) { - mPlayPauseButtonView.setImageResource(R.drawable.pip_ic_pause_white); - mPlayPauseButtonView.setText(R.string.pip_pause); - } else { - mPlayPauseButtonView.setImageResource(R.drawable.pip_ic_play_arrow_white); - mPlayPauseButtonView.setText(R.string.pip_play); + // "Assign" actions to the buttons. + for (int index = 0; index < actionsNumber; index++) { + final RemoteAction action = actionsToDisplay.get(index); + final PipControlButtonView button = mAdditionalButtons.get(index); + button.setVisibility(View.VISIBLE); // Ensure the button is visible. + button.setText(action.getContentDescription()); + button.setEnabled(action.isEnabled()); + button.setAlpha(action.isEnabled() ? 1f : DISABLED_ACTION_ALPHA); + button.setOnClickListener(v -> { + try { + action.getActionIntent().send(); + } catch (PendingIntent.CanceledException e) { + Log.w(TAG, "Failed to send action", e); } - } + }); - // Hide all the custom action buttons - for (int i = 0; i < mCustomButtonViews.size(); i++) { - mCustomButtonViews.get(i).setVisibility(View.GONE); - } + action.getIcon().loadDrawableAsync(mContext, drawable -> { + drawable.setTint(Color.WHITE); + button.setImageDrawable(drawable); + }, mUiThreadHandler); } } - - - /** - * Sets the {@link Listener} to listen user actions. - */ - public void setListener(Listener listener) { - mListener = listener; - } - - - /** - * Updates the set of activity-defined actions. - */ - public void setActions(List<? extends RemoteAction> actions) { - mCustomActions.clear(); - mCustomActions.addAll(actions); - updateUserActions(); - } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipMenuActivity.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipMenuActivity.java index e185a9604449..d2270c278161 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipMenuActivity.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipMenuActivity.java @@ -56,8 +56,7 @@ public class PipMenuActivity extends Activity implements PipController.Listener } setContentView(R.layout.tv_pip_menu); mPipControlsViewController = new PipControlsViewController( - findViewById(R.id.pip_controls), sPipController, - getLayoutInflater(), getApplicationContext().getMainThreadHandler()); + findViewById(R.id.pip_controls), sPipController); sPipController.addListener(this); mRestorePipSizeWhenClose = true; mFadeInAnimation = AnimatorInflater.loadAnimator( @@ -141,7 +140,7 @@ public class PipMenuActivity extends Activity implements PipController.Listener if (DEBUG) Log.d(TAG, "onPipMenuActionsChanged()"); boolean hasCustomActions = actions != null && !actions.getList().isEmpty(); - mPipControlsViewController.setActions( + mPipControlsViewController.setCustomActions( hasCustomActions ? actions.getList() : Collections.emptyList()); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipNotification.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipNotification.java index f5bbd23fa1d6..d6368ea83771 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipNotification.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipNotification.java @@ -28,36 +28,32 @@ import android.content.pm.ParceledListSlice; import android.content.res.Resources; import android.graphics.Bitmap; import android.media.MediaMetadata; -import android.media.session.MediaController; -import android.media.session.PlaybackState; import android.text.TextUtils; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.wm.shell.R; +import java.util.Objects; + /** * A notification that informs users that PIP is running and also provides PIP controls. * <p>Once it's created, it will manage the PIP notification UI by itself except for handling * configuration changes. */ public class PipNotification { + private static final boolean DEBUG = PipController.DEBUG; private static final String TAG = "PipNotification"; + private static final String NOTIFICATION_TAG = PipNotification.class.getSimpleName(); - private static final boolean DEBUG = PipController.DEBUG; + public static final String NOTIFICATION_CHANNEL_TVPIP = "TPP"; static final String ACTION_MENU = "PipNotification.menu"; static final String ACTION_CLOSE = "PipNotification.close"; - public static final String NOTIFICATION_CHANNEL_TVPIP = "TPP"; - private final PackageManager mPackageManager; - - private final PipController mPipController; - private final NotificationManager mNotificationManager; private final Notification.Builder mNotificationBuilder; - private MediaController mMediaController; private String mDefaultTitle; private int mDefaultIconResId; @@ -71,7 +67,6 @@ public class PipNotification { @Override public void onPipEntered(String packageName) { mPackageName = packageName; - updateMediaControllerMetadata(); notifyPipNotification(); } @@ -103,51 +98,9 @@ public class PipNotification { } }; - private MediaController.Callback mMediaControllerCallback = new MediaController.Callback() { - @Override - public void onPlaybackStateChanged(PlaybackState state) { - if (updateMediaControllerMetadata() && mNotified) { - // update notification - notifyPipNotification(); - } - } - - @Override - public void onMetadataChanged(MediaMetadata metadata) { - if (updateMediaControllerMetadata() && mNotified) { - // update notification - notifyPipNotification(); - } - } - }; - - private final PipController.MediaListener mPipMediaListener = - new PipController.MediaListener() { - @Override - public void onMediaControllerChanged() { - MediaController newController = mPipController.getMediaController(); - if (newController == null || mMediaController == newController) { - return; - } - if (mMediaController != null) { - mMediaController.unregisterCallback(mMediaControllerCallback); - } - mMediaController = newController; - if (mMediaController != null) { - mMediaController.registerCallback(mMediaControllerCallback); - } - if (updateMediaControllerMetadata() && mNotified) { - // update notification - notifyPipNotification(); - } - } - }; - public PipNotification(Context context, PipController pipController) { mPackageManager = context.getPackageManager(); - - mNotificationManager = (NotificationManager) context.getSystemService( - Context.NOTIFICATION_SERVICE); + mNotificationManager = context.getSystemService(NotificationManager.class); mNotificationBuilder = new Notification.Builder(context, NOTIFICATION_CHANNEL_TVPIP) .setLocalOnly(true) @@ -157,13 +110,19 @@ public class PipNotification { .setContentIntent(createPendingIntent(context, ACTION_MENU)) .setDeleteIntent(createPendingIntent(context, ACTION_CLOSE))); - mPipController = pipController; pipController.addListener(mPipListener); - pipController.addMediaListener(mPipMediaListener); + pipController.getPipMediaController().addMetadataListener(this::onMediaMetadataChanged); onConfigurationChanged(context); } + private void onMediaMetadataChanged(MediaMetadata metadata) { + if (updateMediaControllerMetadata(metadata) && mNotified) { + // update notification + notifyPipNotification(); + } + } + /** * Called by {@link PipController} when the configuration is changed. */ @@ -199,28 +158,28 @@ public class PipNotification { mNotificationManager.cancel(NOTIFICATION_TAG, SystemMessage.NOTE_TV_PIP); } - private boolean updateMediaControllerMetadata() { + private boolean updateMediaControllerMetadata(MediaMetadata metadata) { String title = null; Bitmap art = null; - if (mPipController.getMediaController() != null) { - MediaMetadata metadata = mPipController.getMediaController().getMetadata(); - if (metadata != null) { - title = metadata.getString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE); - if (TextUtils.isEmpty(title)) { - title = metadata.getString(MediaMetadata.METADATA_KEY_TITLE); - } - art = metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART); - if (art == null) { - art = metadata.getBitmap(MediaMetadata.METADATA_KEY_ART); - } + if (metadata != null) { + title = metadata.getString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE); + if (TextUtils.isEmpty(title)) { + title = metadata.getString(MediaMetadata.METADATA_KEY_TITLE); + } + art = metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART); + if (art == null) { + art = metadata.getBitmap(MediaMetadata.METADATA_KEY_ART); } } - if (!TextUtils.equals(title, mMediaTitle) || art != mArt) { - mMediaTitle = title; - mArt = art; - return true; + + if (TextUtils.equals(title, mMediaTitle) && Objects.equals(art, mArt)) { + return false; } - return false; + + mMediaTitle = title; + mArt = art; + + return true; } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java index 54543d25b401..1d10a84c53b9 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java @@ -16,14 +16,28 @@ package com.android.wm.shell.pip; +import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import android.app.ActivityManager; +import android.app.PictureInPictureParams; +import android.content.ComponentName; +import android.graphics.Rect; import android.os.RemoteException; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; +import android.util.Rational; +import android.view.DisplayInfo; +import android.window.WindowContainerToken; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.DisplayController; @@ -52,14 +66,21 @@ public class PipTaskOrganizerTest extends PipTestCase { @Mock private PipUiEventLogger mMockPipUiEventLogger; @Mock private Optional<SplitScreen> mMockOptionalSplitScreen; @Mock private ShellTaskOrganizer mMockShellTaskOrganizer; - @Mock private PipBoundsState mMockPipBoundsState; + private PipBoundsState mPipBoundsState; + + private ComponentName mComponent1; + private ComponentName mComponent2; @Before public void setUp() throws RemoteException { MockitoAnnotations.initMocks(this); - mSpiedPipTaskOrganizer = new PipTaskOrganizer(mContext, mMockPipBoundsState, + mComponent1 = new ComponentName(mContext, "component1"); + mComponent2 = new ComponentName(mContext, "component2"); + mPipBoundsState = new PipBoundsState(); + mSpiedPipTaskOrganizer = spy(new PipTaskOrganizer(mContext, mPipBoundsState, mMockPipBoundsHandler, mMockPipSurfaceTransactionHelper, mMockOptionalSplitScreen, - mMockdDisplayController, mMockPipUiEventLogger, mMockShellTaskOrganizer); + mMockdDisplayController, mMockPipUiEventLogger, mMockShellTaskOrganizer)); + preparePipTaskOrg(); } @Test @@ -71,4 +92,89 @@ public class PipTaskOrganizerTest extends PipTestCase { public void instantiatePipTaskOrganizer_addsDisplayWindowListener() { verify(mMockdDisplayController).addDisplayWindowListener(any()); } + + @Test + public void startSwipePipToHome_updatesAspectRatio() { + final Rational aspectRatio = new Rational(2, 1); + + mSpiedPipTaskOrganizer.startSwipePipToHome(mComponent1, null, createPipParams(aspectRatio)); + + assertEquals(aspectRatio.floatValue(), mPipBoundsState.getAspectRatio(), 0.01f); + } + + @Test + public void startSwipePipToHome_updatesLastPipComponentName() { + mSpiedPipTaskOrganizer.startSwipePipToHome(mComponent1, null, null); + + assertEquals(mComponent1, mPipBoundsState.getLastPipComponentName()); + } + + @Test + public void onTaskAppeared_updatesAspectRatio() { + final Rational aspectRatio = new Rational(2, 1); + + mSpiedPipTaskOrganizer.onTaskAppeared(createTaskInfo(mComponent1, + createPipParams(aspectRatio)), null /* leash */); + + assertEquals(aspectRatio.floatValue(), mPipBoundsState.getAspectRatio(), 0.01f); + } + + @Test + public void onTaskAppeared_updatesLastPipComponentName() { + mSpiedPipTaskOrganizer.onTaskAppeared(createTaskInfo(mComponent1, createPipParams(null)), + null /* leash */); + + assertEquals(mComponent1, mPipBoundsState.getLastPipComponentName()); + } + + @Test + public void onTaskInfoChanged_updatesAspectRatioIfChanged() { + final Rational startAspectRatio = new Rational(2, 1); + final Rational newAspectRatio = new Rational(1, 2); + mSpiedPipTaskOrganizer.onTaskAppeared(createTaskInfo(mComponent1, + createPipParams(startAspectRatio)), null /* leash */); + + mSpiedPipTaskOrganizer.onTaskInfoChanged(createTaskInfo(mComponent1, + createPipParams(newAspectRatio))); + + assertEquals(newAspectRatio.floatValue(), mPipBoundsState.getAspectRatio(), 0.01f); + } + + @Test + public void onTaskInfoChanged_updatesLastPipComponentName() { + mSpiedPipTaskOrganizer.onTaskAppeared(createTaskInfo(mComponent1, + createPipParams(null)), null /* leash */); + + mSpiedPipTaskOrganizer.onTaskInfoChanged(createTaskInfo(mComponent2, + createPipParams(null))); + + assertEquals(mComponent2, mPipBoundsState.getLastPipComponentName()); + } + + private void preparePipTaskOrg() { + final DisplayInfo info = new DisplayInfo(); + mPipBoundsState.setDisplayInfo(info); + when(mMockPipBoundsHandler.getDestinationBounds(any(), any())).thenReturn(new Rect()); + when(mMockPipBoundsHandler.getDestinationBounds(any(), any(), anyBoolean())) + .thenReturn(new Rect()); + mPipBoundsState.setDisplayInfo(info); + mSpiedPipTaskOrganizer.setOneShotAnimationType(PipAnimationController.ANIM_TYPE_ALPHA); + doNothing().when(mSpiedPipTaskOrganizer).enterPipWithAlphaAnimation(any(), anyLong()); + doNothing().when(mSpiedPipTaskOrganizer).scheduleAnimateResizePip(any(), anyInt(), any()); + } + + private static ActivityManager.RunningTaskInfo createTaskInfo( + ComponentName componentName, PictureInPictureParams params) { + final ActivityManager.RunningTaskInfo info = new ActivityManager.RunningTaskInfo(); + info.token = mock(WindowContainerToken.class); + info.pictureInPictureParams = params; + info.topActivity = componentName; + return info; + } + + private static PictureInPictureParams createPipParams(Rational aspectRatio) { + return new PictureInPictureParams.Builder() + .setAspectRatio(aspectRatio) + .build(); + } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java index a282a48e8494..5f0f1964814f 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java @@ -20,11 +20,14 @@ import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE; import static org.junit.Assert.assertNull; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; import android.os.RemoteException; @@ -34,8 +37,10 @@ import android.testing.TestableLooper; import com.android.wm.shell.WindowManagerShellWrapper; import com.android.wm.shell.common.DisplayController; +import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.pip.PipBoundsHandler; import com.android.wm.shell.pip.PipBoundsState; +import com.android.wm.shell.pip.PipMediaController; import com.android.wm.shell.pip.PipTaskOrganizer; import com.android.wm.shell.pip.PipTestCase; @@ -63,6 +68,7 @@ public class PipControllerTest extends PipTestCase { @Mock private PipTouchHandler mMockPipTouchHandler; @Mock private WindowManagerShellWrapper mMockWindowManagerShellWrapper; @Mock private PipBoundsState mMockPipBoundsState; + @Mock private ShellExecutor mMockExecutor; @Before public void setUp() throws RemoteException { @@ -70,7 +76,11 @@ public class PipControllerTest extends PipTestCase { mPipController = new PipController(mContext, mMockDisplayController, mMockPipAppOpsListener, mMockPipBoundsHandler, mMockPipBoundsState, mMockPipMediaController, mMockPipMenuActivityController, mMockPipTaskOrganizer, - mMockPipTouchHandler, mMockWindowManagerShellWrapper); + mMockPipTouchHandler, mMockWindowManagerShellWrapper, mMockExecutor); + doAnswer(invocation -> { + ((Runnable) invocation.getArgument(0)).run(); + return null; + }).when(mMockExecutor).execute(any()); } @Test @@ -98,6 +108,27 @@ public class PipControllerTest extends PipTestCase { assertNull(PipController.create(spyContext, mMockDisplayController, mMockPipAppOpsListener, mMockPipBoundsHandler, mMockPipBoundsState, mMockPipMediaController, mMockPipMenuActivityController, mMockPipTaskOrganizer, - mMockPipTouchHandler, mMockWindowManagerShellWrapper)); + mMockPipTouchHandler, mMockWindowManagerShellWrapper, mMockExecutor)); + } + + @Test + public void onActivityHidden_isLastPipComponentName_clearLastPipComponent() { + final ComponentName component1 = new ComponentName(mContext, "component1"); + when(mMockPipBoundsState.getLastPipComponentName()).thenReturn(component1); + + mPipController.mPinnedStackListener.onActivityHidden(component1); + + verify(mMockPipBoundsState).setLastPipComponentName(null); + } + + @Test + public void onActivityHidden_isNotLastPipComponentName_lastPipComponentNotCleared() { + final ComponentName component1 = new ComponentName(mContext, "component1"); + final ComponentName component2 = new ComponentName(mContext, "component2"); + when(mMockPipBoundsState.getLastPipComponentName()).thenReturn(component1); + + mPipController.mPinnedStackListener.onActivityHidden(component2); + + verify(mMockPipBoundsState, never()).setLastPipComponentName(null); } } diff --git a/media/java/android/media/MediaCas.java b/media/java/android/media/MediaCas.java index 98ca2f9c4253..4b208ce1ec37 100644 --- a/media/java/android/media/MediaCas.java +++ b/media/java/android/media/MediaCas.java @@ -362,28 +362,34 @@ public final class MediaCas implements AutoCloseable { @Override public void onEvent(int event, int arg, @Nullable ArrayList<Byte> data) throws RemoteException { - mEventHandler.sendMessage(mEventHandler.obtainMessage( + if (mEventHandler != null) { + mEventHandler.sendMessage(mEventHandler.obtainMessage( EventHandler.MSG_CAS_EVENT, event, arg, data)); + } } @Override public void onSessionEvent(@NonNull ArrayList<Byte> sessionId, int event, int arg, @Nullable ArrayList<Byte> data) throws RemoteException { - Message msg = mEventHandler.obtainMessage(); - msg.what = EventHandler.MSG_CAS_SESSION_EVENT; - msg.arg1 = event; - msg.arg2 = arg; - Bundle bundle = new Bundle(); - bundle.putByteArray(EventHandler.SESSION_KEY, toBytes(sessionId)); - bundle.putByteArray(EventHandler.DATA_KEY, toBytes(data)); - msg.setData(bundle); - mEventHandler.sendMessage(msg); + if (mEventHandler != null) { + Message msg = mEventHandler.obtainMessage(); + msg.what = EventHandler.MSG_CAS_SESSION_EVENT; + msg.arg1 = event; + msg.arg2 = arg; + Bundle bundle = new Bundle(); + bundle.putByteArray(EventHandler.SESSION_KEY, toBytes(sessionId)); + bundle.putByteArray(EventHandler.DATA_KEY, toBytes(data)); + msg.setData(bundle); + mEventHandler.sendMessage(msg); + } } @Override public void onStatusUpdate(byte status, int arg) throws RemoteException { - mEventHandler.sendMessage(mEventHandler.obtainMessage( + if (mEventHandler != null) { + mEventHandler.sendMessage(mEventHandler.obtainMessage( EventHandler.MSG_CAS_STATUS_EVENT, status, arg)); + } } }; diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java index 3af2e17960ae..38e2bdfc308d 100644 --- a/media/java/android/media/session/MediaController.java +++ b/media/java/android/media/session/MediaController.java @@ -22,7 +22,6 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.app.PendingIntent; -import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.ParceledListSlice; import android.media.AudioAttributes; @@ -462,21 +461,14 @@ public final class MediaController { return mTag; } - /* - * @hide - */ - ISessionController getSessionBinder() { - return mSessionBinder; - } - /** - * @hide + * Returns whether this and {@code other} media controller controls the same session. + * @deprecated Check equality of {@link #getSessionToken() tokens} instead. */ - @UnsupportedAppUsage(publicAlternatives = "Check equality of {@link #getSessionToken() tokens}" - + "instead.") - public boolean controlsSameSession(MediaController other) { + @Deprecated + public boolean controlsSameSession(@Nullable MediaController other) { if (other == null) return false; - return mSessionBinder.asBinder() == other.getSessionBinder().asBinder(); + return mToken.equals(other.mToken); } private void addCallbackLocked(Callback cb, Handler handler) { diff --git a/media/java/android/media/tv/tuner/filter/AvSettings.java b/media/java/android/media/tv/tuner/filter/AvSettings.java index 5d9d53174b3e..e482875c38d3 100644 --- a/media/java/android/media/tv/tuner/filter/AvSettings.java +++ b/media/java/android/media/tv/tuner/filter/AvSettings.java @@ -199,6 +199,7 @@ public class AvSettings extends Settings { /** * Get the Audio Stream Type. */ + @AudioStreamType public int getAudioStreamType() { return mAudioStreamType; } @@ -206,6 +207,7 @@ public class AvSettings extends Settings { /** * Get the Video Stream Type. */ + @VideoStreamType public int getVideoStreamType() { return mVideoStreamType; } diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt index 8adedf5779d1..41a9057c005a 100644 --- a/non-updatable-api/current.txt +++ b/non-updatable-api/current.txt @@ -28571,6 +28571,7 @@ package android.media.session { public final class MediaController { ctor public MediaController(@NonNull android.content.Context, @NonNull android.media.session.MediaSession.Token); method public void adjustVolume(int, int); + method @Deprecated public boolean controlsSameSession(@Nullable android.media.session.MediaController); method public boolean dispatchMediaButtonEvent(@NonNull android.view.KeyEvent); method @Nullable public android.os.Bundle getExtras(); method public long getFlags(); @@ -44635,6 +44636,7 @@ package android.telecom { method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVoiceMailNumber(android.telecom.PhoneAccountHandle); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handleMmi(String); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handleMmi(String, android.telecom.PhoneAccountHandle); + method public boolean hasCompanionInCallServiceAccess(); method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isInCall(); method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isInManagedCall(); method public boolean isIncomingCallPermitted(android.telecom.PhoneAccountHandle); @@ -51897,7 +51899,6 @@ package android.view { } public interface OnReceiveContentCallback<T extends android.view.View> { - method @NonNull public java.util.Set<java.lang.String> getSupportedMimeTypes(@NonNull T); method public boolean onReceiveContent(@NonNull T, @NonNull android.view.OnReceiveContentCallback.Payload); } @@ -52475,7 +52476,7 @@ package android.view { method @IdRes public int getNextFocusRightId(); method @IdRes public int getNextFocusUpId(); method public android.view.View.OnFocusChangeListener getOnFocusChangeListener(); - method @Nullable public android.view.OnReceiveContentCallback<? extends android.view.View> getOnReceiveContentCallback(); + method @Nullable public String[] getOnReceiveContentMimeTypes(); method @ColorInt public int getOutlineAmbientShadowColor(); method public android.view.ViewOutlineProvider getOutlineProvider(); method @ColorInt public int getOutlineSpotShadowColor(); @@ -52670,6 +52671,7 @@ package android.view { method public void onProvideContentCaptureStructure(@NonNull android.view.ViewStructure, int); method public void onProvideStructure(android.view.ViewStructure); method public void onProvideVirtualStructure(android.view.ViewStructure); + method public boolean onReceiveContent(@NonNull android.view.OnReceiveContentCallback.Payload); method public android.view.PointerIcon onResolvePointerIcon(android.view.MotionEvent, int); method @CallSuper protected void onRestoreInstanceState(android.os.Parcelable); method public void onRtlPropertiesChanged(int); @@ -52827,7 +52829,7 @@ package android.view { method public void setOnHoverListener(android.view.View.OnHoverListener); method public void setOnKeyListener(android.view.View.OnKeyListener); method public void setOnLongClickListener(@Nullable android.view.View.OnLongClickListener); - method public void setOnReceiveContentCallback(@Nullable android.view.OnReceiveContentCallback<? extends android.view.View>); + method public void setOnReceiveContentCallback(@Nullable String[], @Nullable android.view.OnReceiveContentCallback); method public void setOnScrollChangeListener(android.view.View.OnScrollChangeListener); method @Deprecated public void setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener); method public void setOnTouchListener(android.view.View.OnTouchListener); @@ -59657,7 +59659,6 @@ package android.widget { method public int getMinWidth(); method public final android.text.method.MovementMethod getMovementMethod(); method public int getOffsetForPosition(float, float); - method @Nullable public android.view.OnReceiveContentCallback<android.widget.TextView> getOnReceiveContentCallback(); method public android.text.TextPaint getPaint(); method public int getPaintFlags(); method public String getPrivateImeOptions(); @@ -59846,7 +59847,6 @@ package android.widget { public class TextViewOnReceiveContentCallback implements android.view.OnReceiveContentCallback<android.widget.TextView> { ctor public TextViewOnReceiveContentCallback(); - method @NonNull public java.util.Set<java.lang.String> getSupportedMimeTypes(@NonNull android.widget.TextView); method public boolean onReceiveContent(@NonNull android.widget.TextView, @NonNull android.view.OnReceiveContentCallback.Payload); } diff --git a/non-updatable-api/system-current.txt b/non-updatable-api/system-current.txt index fe40892a959b..499eaf8b3e2c 100644 --- a/non-updatable-api/system-current.txt +++ b/non-updatable-api/system-current.txt @@ -109,7 +109,8 @@ package android { field public static final String LOCK_DEVICE = "android.permission.LOCK_DEVICE"; field public static final String LOOP_RADIO = "android.permission.LOOP_RADIO"; field public static final String MANAGE_ACCESSIBILITY = "android.permission.MANAGE_ACCESSIBILITY"; - field public static final String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS"; + field @Deprecated public static final String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS"; + field public static final String MANAGE_ACTIVITY_TASKS = "android.permission.MANAGE_ACTIVITY_TASKS"; field public static final String MANAGE_APP_OPS_RESTRICTIONS = "android.permission.MANAGE_APP_OPS_RESTRICTIONS"; field public static final String MANAGE_APP_PREDICTIONS = "android.permission.MANAGE_APP_PREDICTIONS"; field public static final String MANAGE_APP_TOKENS = "android.permission.MANAGE_APP_TOKENS"; @@ -866,6 +867,7 @@ package android.app.admin { field public static final int PROVISIONING_TRIGGER_QR_CODE = 2; // 0x2 field public static final int PROVISIONING_TRIGGER_UNSPECIFIED = 0; // 0x0 field public static final int STATE_USER_PROFILE_COMPLETE = 4; // 0x4 + field public static final int STATE_USER_PROFILE_FINALIZED = 5; // 0x5 field public static final int STATE_USER_SETUP_COMPLETE = 2; // 0x2 field public static final int STATE_USER_SETUP_FINALIZED = 3; // 0x3 field public static final int STATE_USER_SETUP_INCOMPLETE = 1; // 0x1 @@ -2140,6 +2142,7 @@ package android.content.pm { method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.SUSPEND_APPS) public String[] setPackagesSuspended(@Nullable String[], boolean, @Nullable android.os.PersistableBundle, @Nullable android.os.PersistableBundle, @Nullable String); method @Nullable @RequiresPermission(android.Manifest.permission.SUSPEND_APPS) public String[] setPackagesSuspended(@Nullable String[], boolean, @Nullable android.os.PersistableBundle, @Nullable android.os.PersistableBundle, @Nullable android.content.pm.SuspendDialogInfo); method @RequiresPermission(value=android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE, conditional=true) public void setSyntheticAppDetailsActivityEnabled(@NonNull String, boolean); + method public void setSystemAppState(@NonNull String, int); method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public abstract void setUpdateAvailable(@NonNull String, boolean); method @RequiresPermission(android.Manifest.permission.SET_PREFERRED_APPLICATIONS) public abstract boolean updateIntentVerificationStatusAsUser(@NonNull String, int, int); method @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS}) public abstract void updatePermissionFlags(@NonNull String, @NonNull String, @android.content.pm.PackageManager.PermissionFlags int, @android.content.pm.PackageManager.PermissionFlags int, @NonNull android.os.UserHandle); @@ -2218,11 +2221,16 @@ package android.content.pm { field @Deprecated public static final int MASK_PERMISSION_FLAGS = 255; // 0xff field public static final int MATCH_ANY_USER = 4194304; // 0x400000 field public static final int MATCH_FACTORY_ONLY = 2097152; // 0x200000 + field public static final int MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS = 536870912; // 0x20000000 field public static final int MATCH_INSTANT = 8388608; // 0x800000 field public static final int MODULE_APEX_NAME = 1; // 0x1 field public static final int RESTRICTION_HIDE_FROM_SUGGESTIONS = 1; // 0x1 field public static final int RESTRICTION_HIDE_NOTIFICATIONS = 2; // 0x2 field public static final int RESTRICTION_NONE = 0; // 0x0 + field public static final int SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN = 0; // 0x0 + field public static final int SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_VISIBLE = 1; // 0x1 + field public static final int SYSTEM_APP_STATE_INSTALLED = 2; // 0x2 + field public static final int SYSTEM_APP_STATE_UNINSTALLED = 3; // 0x3 } public abstract static class PackageManager.DexModuleRegisterCallback { @@ -6635,6 +6643,7 @@ package android.net { method @NonNull public int[] getTransportTypes(); method public boolean satisfiedByNetworkCapabilities(@Nullable android.net.NetworkCapabilities); field public static final int NET_CAPABILITY_OEM_PAID = 22; // 0x16 + field public static final int NET_CAPABILITY_OEM_PRIVATE = 26; // 0x1a field public static final int NET_CAPABILITY_PARTIAL_CONNECTIVITY = 24; // 0x18 } @@ -8880,6 +8889,7 @@ package android.service.autofill { public static final class Dataset.Builder { ctor public Dataset.Builder(@NonNull android.service.autofill.InlinePresentation); + method @NonNull public android.service.autofill.Dataset.Builder setContent(@NonNull android.view.autofill.AutofillId, @Nullable android.content.ClipData); method @NonNull public android.service.autofill.Dataset.Builder setFieldInlinePresentation(@NonNull android.view.autofill.AutofillId, @Nullable android.view.autofill.AutofillValue, @Nullable java.util.regex.Pattern, @NonNull android.service.autofill.InlinePresentation); } diff --git a/packages/CarSystemUI/res/values-ar/strings.xml b/packages/CarSystemUI/res/values-ar/strings.xml index 61a08a4eae49..d9abb0af5608 100644 --- a/packages/CarSystemUI/res/values-ar/strings.xml +++ b/packages/CarSystemUI/res/values-ar/strings.xml @@ -28,6 +28,5 @@ <string name="user_add_user_message_update" msgid="7061671307004867811">"يمكن لأي مستخدم تحديث التطبيقات لجميع المستخدمين الآخرين."</string> <string name="car_loading_profile" msgid="4507385037552574474">"جارٍ التحميل"</string> <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"جارٍ تحميل الملف الشخصي الجديد للمستخدم (من <xliff:g id="FROM_USER">%1$d</xliff:g> إلى <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> - <!-- no translation found for rear_view_camera_close_button_text (8430918817320533693) --> - <skip /> + <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"إغلاق"</string> </resources> diff --git a/packages/CarSystemUI/res/values-bn/strings.xml b/packages/CarSystemUI/res/values-bn/strings.xml index a45e66e8c2f2..5664cc12e109 100644 --- a/packages/CarSystemUI/res/values-bn/strings.xml +++ b/packages/CarSystemUI/res/values-bn/strings.xml @@ -28,6 +28,5 @@ <string name="user_add_user_message_update" msgid="7061671307004867811">"যেকোনও ব্যবহারকারী বাকি সব ব্যবহারকারীর জন্য অ্যাপ আপডেট করতে পারবেন।"</string> <string name="car_loading_profile" msgid="4507385037552574474">"লোড হচ্ছে"</string> <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"ব্যবহারকারীর প্রোফাইল লোড করা হচ্ছে (<xliff:g id="FROM_USER">%1$d</xliff:g> থেকে <xliff:g id="TO_USER">%2$d</xliff:g>-এ)"</string> - <!-- no translation found for rear_view_camera_close_button_text (8430918817320533693) --> - <skip /> + <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"বন্ধ করুন"</string> </resources> diff --git a/packages/CarSystemUI/res/values-de/strings.xml b/packages/CarSystemUI/res/values-de/strings.xml index 131dee19b0ca..e2437f0c55cb 100644 --- a/packages/CarSystemUI/res/values-de/strings.xml +++ b/packages/CarSystemUI/res/values-de/strings.xml @@ -28,6 +28,5 @@ <string name="user_add_user_message_update" msgid="7061671307004867811">"Jeder Nutzer kann Apps für alle anderen Nutzer aktualisieren."</string> <string name="car_loading_profile" msgid="4507385037552574474">"Wird geladen"</string> <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Nutzer wird geladen (von <xliff:g id="FROM_USER">%1$d</xliff:g> bis <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> - <!-- no translation found for rear_view_camera_close_button_text (8430918817320533693) --> - <skip /> + <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Schließen"</string> </resources> diff --git a/packages/CarSystemUI/res/values-eu/strings.xml b/packages/CarSystemUI/res/values-eu/strings.xml index 5d2ca3548af2..9139e650187e 100644 --- a/packages/CarSystemUI/res/values-eu/strings.xml +++ b/packages/CarSystemUI/res/values-eu/strings.xml @@ -28,6 +28,5 @@ <string name="user_add_user_message_update" msgid="7061671307004867811">"Edozein erabiltzailek egunera ditzake beste erabiltzaile guztien aplikazioak."</string> <string name="car_loading_profile" msgid="4507385037552574474">"Kargatzen"</string> <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Erabiltzailea kargatzen (<xliff:g id="FROM_USER">%1$d</xliff:g> izatetik<xliff:g id="TO_USER">%2$d</xliff:g> izatera igaroko da)"</string> - <!-- no translation found for rear_view_camera_close_button_text (8430918817320533693) --> - <skip /> + <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Itxi"</string> </resources> diff --git a/packages/CarSystemUI/res/values-gl/strings.xml b/packages/CarSystemUI/res/values-gl/strings.xml index e4586cc17a73..e77df4f50272 100644 --- a/packages/CarSystemUI/res/values-gl/strings.xml +++ b/packages/CarSystemUI/res/values-gl/strings.xml @@ -28,6 +28,5 @@ <string name="user_add_user_message_update" msgid="7061671307004867811">"Calquera usuario pode actualizar as aplicacións para o resto dos usuarios."</string> <string name="car_loading_profile" msgid="4507385037552574474">"Cargando"</string> <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Cargando usuario (do <xliff:g id="FROM_USER">%1$d</xliff:g> ao <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> - <!-- no translation found for rear_view_camera_close_button_text (8430918817320533693) --> - <skip /> + <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Pechar"</string> </resources> diff --git a/packages/CarSystemUI/res/values-gu/strings.xml b/packages/CarSystemUI/res/values-gu/strings.xml index ba884e410187..174d7a724240 100644 --- a/packages/CarSystemUI/res/values-gu/strings.xml +++ b/packages/CarSystemUI/res/values-gu/strings.xml @@ -28,6 +28,5 @@ <string name="user_add_user_message_update" msgid="7061671307004867811">"કોઈપણ વપરાશકર્તા અન્ય બધા વપરાશકર્તાઓ માટે ઍપને અપડેટ કરી શકે છે."</string> <string name="car_loading_profile" msgid="4507385037552574474">"લોડ કરી રહ્યાં છીએ"</string> <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"વપરાશકર્તાને લોડ કરી રહ્યાં છીએ (<xliff:g id="FROM_USER">%1$d</xliff:g>માંથી <xliff:g id="TO_USER">%2$d</xliff:g>માં)"</string> - <!-- no translation found for rear_view_camera_close_button_text (8430918817320533693) --> - <skip /> + <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"બંધ કરો"</string> </resources> diff --git a/packages/CarSystemUI/res/values-kn/strings.xml b/packages/CarSystemUI/res/values-kn/strings.xml index 34a83553d5c0..b9667df3afb3 100644 --- a/packages/CarSystemUI/res/values-kn/strings.xml +++ b/packages/CarSystemUI/res/values-kn/strings.xml @@ -28,6 +28,5 @@ <string name="user_add_user_message_update" msgid="7061671307004867811">"ಯಾವುದೇ ಬಳಕೆದಾರರು ಎಲ್ಲಾ ಇತರೆ ಬಳಕೆದಾರರಿಗಾಗಿ ಆ್ಯಪ್ಗಳನ್ನು ಅಪ್ಡೇಟ್ ಮಾಡಬಹುದು."</string> <string name="car_loading_profile" msgid="4507385037552574474">"ಲೋಡ್ ಆಗುತ್ತಿದೆ"</string> <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"ಬಳಕೆದಾರರನ್ನು ಲೋಡ್ ಮಾಡಲಾಗುತ್ತಿದೆ (<xliff:g id="FROM_USER">%1$d</xliff:g> ನಿಂದ <xliff:g id="TO_USER">%2$d</xliff:g> ವರೆಗೆ)"</string> - <!-- no translation found for rear_view_camera_close_button_text (8430918817320533693) --> - <skip /> + <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"ಮುಚ್ಚಿರಿ"</string> </resources> diff --git a/packages/CarSystemUI/res/values-ml/strings.xml b/packages/CarSystemUI/res/values-ml/strings.xml index 3bc7557b5484..613ea59874bc 100644 --- a/packages/CarSystemUI/res/values-ml/strings.xml +++ b/packages/CarSystemUI/res/values-ml/strings.xml @@ -28,6 +28,5 @@ <string name="user_add_user_message_update" msgid="7061671307004867811">"ഏതൊരു ഉപയോക്താവിനും മറ്റെല്ലാ ഉപയോക്താക്കൾക്കുമായി ആപ്പുകൾ അപ്ഡേറ്റ് ചെയ്യാനാവും."</string> <string name="car_loading_profile" msgid="4507385037552574474">"ലോഡ് ചെയ്യുന്നു"</string> <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"ഉപയോക്തൃ പ്രൊഫൈൽ ലോഡ് ചെയ്യുന്നു (<xliff:g id="FROM_USER">%1$d</xliff:g> എന്നതിൽ നിന്ന് <xliff:g id="TO_USER">%2$d</xliff:g> എന്നതിലേക്ക്)"</string> - <!-- no translation found for rear_view_camera_close_button_text (8430918817320533693) --> - <skip /> + <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"അടയ്ക്കുക"</string> </resources> diff --git a/packages/CarSystemUI/res/values-or/strings.xml b/packages/CarSystemUI/res/values-or/strings.xml index 58f59e4c4dbf..4168d5a109b8 100644 --- a/packages/CarSystemUI/res/values-or/strings.xml +++ b/packages/CarSystemUI/res/values-or/strings.xml @@ -28,6 +28,5 @@ <string name="user_add_user_message_update" msgid="7061671307004867811">"ଯେ କୌଣସି ଉପଯୋଗକର୍ତ୍ତା ଅନ୍ୟ ସମସ୍ତ ଉପଯୋଗକର୍ତ୍ତାଙ୍କ ପାଇଁ ଆପଗୁଡ଼ିକୁ ଅପଡେଟ୍ କରିପାରିବେ।"</string> <string name="car_loading_profile" msgid="4507385037552574474">"ଲୋଡ୍ କରାଯାଉଛି"</string> <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"ଉପଯୋଗକର୍ତ୍ତାଙ୍କୁ ଲୋଡ୍ କରାଯାଉଛି (<xliff:g id="FROM_USER">%1$d</xliff:g>ଙ୍କ ଠାରୁ <xliff:g id="TO_USER">%2$d</xliff:g> ପର୍ଯ୍ୟନ୍ତ)"</string> - <!-- no translation found for rear_view_camera_close_button_text (8430918817320533693) --> - <skip /> + <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"ବନ୍ଦ କରନ୍ତୁ"</string> </resources> diff --git a/packages/CarSystemUI/res/values-pa/strings.xml b/packages/CarSystemUI/res/values-pa/strings.xml index e73e20a5fc85..3d9d3a597c07 100644 --- a/packages/CarSystemUI/res/values-pa/strings.xml +++ b/packages/CarSystemUI/res/values-pa/strings.xml @@ -28,6 +28,5 @@ <string name="user_add_user_message_update" msgid="7061671307004867811">"ਕੋਈ ਵੀ ਵਰਤੋਂਕਾਰ ਹੋਰ ਸਾਰੇ ਵਰਤੋਂਕਾਰਾਂ ਦੀਆਂ ਐਪਾਂ ਨੂੰ ਅੱਪਡੇਟ ਕਰ ਸਕਦਾ ਹੈ।"</string> <string name="car_loading_profile" msgid="4507385037552574474">"ਲੋਡ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string> <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"ਵਰਤੋਂਕਾਰ ਨੂੰ ਲੋਡ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ (<xliff:g id="FROM_USER">%1$d</xliff:g> ਤੋਂ <xliff:g id="TO_USER">%2$d</xliff:g> ਤੱਕ)"</string> - <!-- no translation found for rear_view_camera_close_button_text (8430918817320533693) --> - <skip /> + <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"ਬੰਦ ਕਰੋ"</string> </resources> diff --git a/packages/CarSystemUI/res/values-te/strings.xml b/packages/CarSystemUI/res/values-te/strings.xml index fff0845dfb6c..cf74f8053349 100644 --- a/packages/CarSystemUI/res/values-te/strings.xml +++ b/packages/CarSystemUI/res/values-te/strings.xml @@ -28,6 +28,5 @@ <string name="user_add_user_message_update" msgid="7061671307004867811">"ఏ యూజర్ అయినా మిగతా యూజర్ల కోసం యాప్లను అప్డేట్ చేయవచ్చు."</string> <string name="car_loading_profile" msgid="4507385037552574474">"లోడ్ అవుతోంది"</string> <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"యూజర్ను లోడ్ చేస్తోంది (<xliff:g id="FROM_USER">%1$d</xliff:g> నుండి <xliff:g id="TO_USER">%2$d</xliff:g> వరకు)"</string> - <!-- no translation found for rear_view_camera_close_button_text (8430918817320533693) --> - <skip /> + <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"మూసివేయి"</string> </resources> diff --git a/packages/CarSystemUI/res/values-ur/strings.xml b/packages/CarSystemUI/res/values-ur/strings.xml index ef65c7516956..abe9214181a2 100644 --- a/packages/CarSystemUI/res/values-ur/strings.xml +++ b/packages/CarSystemUI/res/values-ur/strings.xml @@ -28,6 +28,5 @@ <string name="user_add_user_message_update" msgid="7061671307004867811">"کوئی بھی صارف دیگر سبھی صارفین کے لیے ایپس کو اپ ڈیٹ کر سکتا ہے۔"</string> <string name="car_loading_profile" msgid="4507385037552574474">"لوڈ ہو رہی ہے"</string> <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"صارف کی نئی پروفائل لوڈ ہو رہی ہے (<xliff:g id="FROM_USER">%1$d</xliff:g> سے <xliff:g id="TO_USER">%2$d</xliff:g> کو)"</string> - <!-- no translation found for rear_view_camera_close_button_text (8430918817320533693) --> - <skip /> + <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"بند کریں"</string> </resources> diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java index 02f4457bffdb..bdfbf82145c7 100644 --- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java +++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java @@ -17,6 +17,9 @@ package com.android.companiondevicemanager; import static android.companion.BluetoothDeviceFilterUtils.getDeviceMacAddress; +import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; + +import static java.util.Objects.requireNonNull; import android.app.Activity; import android.companion.CompanionDeviceManager; @@ -57,6 +60,8 @@ public class DeviceChooserActivity extends Activity { Log.e(LOG_TAG, "About to show UI, but no devices to show"); } + getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS); + if (getService().mRequest.isSingleDevice()) { setContentView(R.layout.device_confirmation); final DeviceFilterPair selectedDevice = getService().mDevicesFound.get(0); @@ -126,6 +131,11 @@ public class DeviceChooserActivity extends Activity { } @Override + public String getCallingPackage() { + return requireNonNull(getService().mRequest.getCallingPackage()); + } + + @Override public void setTitle(CharSequence title) { final TextView titleView = findViewById(R.id.title); final int padding = getPadding(getResources()); diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java index 2fd46d94d5cc..3cbf2685af26 100644 --- a/packages/SettingsLib/src/com/android/settingslib/Utils.java +++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java @@ -15,6 +15,9 @@ import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.ColorFilter; +import android.graphics.ColorMatrix; +import android.graphics.ColorMatrixColorFilter; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.location.LocationManager; @@ -308,6 +311,36 @@ public class Utils { } /** + * Create a color matrix suitable for a ColorMatrixColorFilter that modifies only the color but + * preserves the alpha for a given drawable + * @param color + * @return a color matrix that uses the source alpha and given color + */ + public static ColorMatrix getAlphaInvariantColorMatrixForColor(@ColorInt int color) { + int r = Color.red(color); + int g = Color.green(color); + int b = Color.blue(color); + + ColorMatrix cm = new ColorMatrix(new float[] { + 0, 0, 0, 0, r, + 0, 0, 0, 0, g, + 0, 0, 0, 0, b, + 0, 0, 0, 1, 0 }); + + return cm; + } + + /** + * Create a ColorMatrixColorFilter to tint a drawable but retain its alpha characteristics + * + * @return a ColorMatrixColorFilter which changes the color of the output but is invariant on + * the source alpha + */ + public static ColorFilter getAlphaInvariantColorFilterForColor(@ColorInt int color) { + return new ColorMatrixColorFilter(getAlphaInvariantColorMatrixForColor(color)); + } + + /** * Determine whether a package is a "system package", in which case certain things (like * disabling notifications or disabling the package altogether) should be disallowed. */ diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/ThemedBatteryDrawable.kt b/packages/SettingsLib/src/com/android/settingslib/graph/ThemedBatteryDrawable.kt index a5b5312707d0..5fa04f93e993 100644 --- a/packages/SettingsLib/src/com/android/settingslib/graph/ThemedBatteryDrawable.kt +++ b/packages/SettingsLib/src/com/android/settingslib/graph/ThemedBatteryDrawable.kt @@ -108,6 +108,7 @@ open class ThemedBatteryDrawable(private val context: Context, frameColor: Int) private val fillColorStrokePaint = Paint(Paint.ANTI_ALIAS_FLAG).also { p -> p.color = frameColor + p.alpha = 255 p.isDither = true p.strokeWidth = 5f p.style = Paint.Style.STROKE @@ -145,7 +146,7 @@ open class ThemedBatteryDrawable(private val context: Context, frameColor: Int) // Only used if dualTone is set to true private val dualToneBackgroundFill = Paint(Paint.ANTI_ALIAS_FLAG).also { p -> p.color = frameColor - p.alpha = 255 + p.alpha = 85 // ~0.3 alpha by default p.isDither = true p.strokeWidth = 0f p.style = Paint.Style.FILL_AND_STROKE diff --git a/packages/SettingsLib/src/com/android/settingslib/users/TEST_MAPPING b/packages/SettingsLib/src/com/android/settingslib/users/TEST_MAPPING new file mode 100644 index 000000000000..71cbcb54a1ff --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/users/TEST_MAPPING @@ -0,0 +1,12 @@ +{ + "presubmit": [ + { + "name": "SettingsLibTests", + "options": [ + { + "include-filter": "com.android.settingslib.users." + } + ] + } + ] +}
\ No newline at end of file diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java index f1d7e223c933..1a2c2c8ac2e9 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java @@ -863,9 +863,6 @@ class SettingsProtoDumpUtil { p.end(intentFirewallToken); dumpSetting(s, p, - Settings.Global.JOB_SCHEDULER_QUOTA_CONTROLLER_CONSTANTS, - GlobalSettingsProto.JOB_SCHEDULER_QUOTA_CONTROLLER_CONSTANTS); - dumpSetting(s, p, Settings.Global.KEEP_PROFILE_IN_BACKGROUND, GlobalSettingsProto.KEEP_PROFILE_IN_BACKGROUND); diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java index 10d2eab167e7..533e9bbf9e01 100644 --- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java @@ -293,6 +293,7 @@ public class SettingsBackupTest { Settings.Global.GNSS_SATELLITE_BLACKLIST, Settings.Global.GPRS_REGISTER_CHECK_PERIOD_MS, Settings.Global.HDMI_CEC_SWITCH_ENABLED, + Settings.Global.HDMI_CEC_VERSION, Settings.Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED, Settings.Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED, Settings.Global.HDMI_CONTROL_ENABLED, @@ -309,7 +310,6 @@ public class SettingsBackupTest { Settings.Global.INSTANT_APP_DEXOPT_ENABLED, Settings.Global.INTENT_FIREWALL_UPDATE_CONTENT_URL, Settings.Global.INTENT_FIREWALL_UPDATE_METADATA_URL, - Settings.Global.JOB_SCHEDULER_QUOTA_CONTROLLER_CONSTANTS, Settings.Global.KEEP_PROFILE_IN_BACKGROUND, Settings.Global.KERNEL_CPU_THREAD_READER, Settings.Global.LANG_ID_UPDATE_CONTENT_URL, @@ -443,6 +443,7 @@ public class SettingsBackupTest { Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, Settings.Global.SHOW_PEOPLE_SPACE, Settings.Global.SHOW_NEW_LOCKSCREEN, + Settings.Global.SHOW_NEW_NOTIF_DISMISS, Settings.Global.SHOW_RESTART_IN_CRASH_DIALOG, Settings.Global.SHOW_TEMPERATURE_WARNING, Settings.Global.SHOW_USB_TEMPERATURE_ALARM, diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index 5f018a0322a3..ec47c717ac3c 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -143,7 +143,7 @@ <uses-permission android:name="android.permission.MANAGE_APP_OPS_MODES" /> <uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.ACCESS_VIBRATOR_STATE" /> - <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" /> + <uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS" /> <uses-permission android:name="android.permission.START_TASKS_FROM_RECENTS" /> <uses-permission android:name="android.permission.START_ACTIVITIES_FROM_BACKGROUND" /> <uses-permission android:name="android.permission.ACTIVITY_EMBEDDING" /> @@ -338,6 +338,9 @@ <!-- Permissions required for CTS test - NotificationManagerTest --> <uses-permission android:name="android.permission.MANAGE_NOTIFICATION_LISTENERS" /> + <!-- Allows overriding the system's device state from the shell --> + <uses-permission android:name="android.permission.CONTROL_DEVICE_STATE"/> + <application android:label="@string/app_label" android:theme="@android:style/Theme.DeviceDefault.DayNight" android:defaultToDeviceProtectedStorage="true" diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index ddd0dac0e9db..f9268eece293 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -99,7 +99,7 @@ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" /> <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" /> <uses-permission android:name="android.permission.GET_TOP_ACTIVITY_INFO" /> - <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" /> + <uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS" /> <uses-permission android:name="android.permission.START_ACTIVITY_AS_CALLER" /> <uses-permission android:name="android.permission.START_TASKS_FROM_RECENTS" /> <uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT" /> diff --git a/packages/SystemUI/res/layout/global_screenshot.xml b/packages/SystemUI/res/layout/global_screenshot.xml index e0333eb82d51..1b5f9c1ced8f 100644 --- a/packages/SystemUI/res/layout/global_screenshot.xml +++ b/packages/SystemUI/res/layout/global_screenshot.xml @@ -27,14 +27,6 @@ android:alpha="0.0" android:src="@drawable/screenshot_actions_background_protection"/> <ImageView - android:id="@+id/global_screenshot_animated_view" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="top|start" - android:visibility="gone" - android:elevation="@dimen/screenshot_preview_elevation" - android:background="@drawable/screenshot_rounded_corners" /> - <ImageView android:id="@+id/global_screenshot_flash" android:layout_width="match_parent" android:layout_height="match_parent" diff --git a/packages/SystemUI/res/layout/quick_settings_footer_dialog_parental_controls.xml b/packages/SystemUI/res/layout/quick_settings_footer_dialog_parental_controls.xml new file mode 100644 index 000000000000..1a356769d334 --- /dev/null +++ b/packages/SystemUI/res/layout/quick_settings_footer_dialog_parental_controls.xml @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +--> +<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/scrollView" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:clipToPadding="false"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingTop="?android:attr/dialogPreferredPadding" + android:paddingRight="?android:attr/dialogPreferredPadding" + android:paddingLeft="?android:attr/dialogPreferredPadding" + android:orientation="vertical"> + <ImageView + android:id="@+id/parental_controls_icon" + android:layout_width="36dip" + android:layout_height="36dip" + android:layout_gravity="center_horizontal" + + /> + <LinearLayout + android:id="@+id/parental_controls_disclosures" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingBottom="?android:attr/dialogPreferredPadding" + android:orientation="vertical"> + <TextView + android:id="@+id/parental_controls_title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/monitoring_title_device_owned" + style="@style/DeviceManagementDialogTitle" + android:paddingBottom="@dimen/qs_footer_dialog_subtitle_padding" + /> + <TextView + android:id="@+id/parental_controls_warning" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textAppearance="@style/TextAppearance.DeviceManagementDialog.Content" + android:text="@string/monitoring_description_parental_controls" + /> + </LinearLayout> + </LinearLayout> +</ScrollView> diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index 4ce5496f2186..75a2d1cc4ea8 100644 --- a/packages/SystemUI/res/values-bs/strings.xml +++ b/packages/SystemUI/res/values-bs/strings.xml @@ -650,9 +650,9 @@ <string name="quick_settings" msgid="6211774484997470203">"Brze postavke"</string> <string name="status_bar" msgid="4357390266055077437">"Statusna traka"</string> <string name="overview" msgid="3522318590458536816">"Pregled"</string> - <string name="demo_mode" msgid="263484519766901593">"Način demonstracije Sistemskog UI-a"</string> - <string name="enable_demo_mode" msgid="3180345364745966431">"Omogući način demonstracije"</string> - <string name="show_demo_mode" msgid="3677956462273059726">"Prikaži način demonstracije"</string> + <string name="demo_mode" msgid="263484519766901593">"Način rada za demonstraciju Sistemskog UI-a"</string> + <string name="enable_demo_mode" msgid="3180345364745966431">"Omogući način rada za demonstraciju"</string> + <string name="show_demo_mode" msgid="3677956462273059726">"Prikaži način rada za demonstraciju"</string> <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string> <string name="status_bar_alarm" msgid="87160847643623352">"Alarm"</string> <string name="status_bar_work" msgid="5238641949837091056">"Profil za posao"</string> diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml index 2a6ed6e9bf65..cd757612073a 100644 --- a/packages/SystemUI/res/values-ml/strings.xml +++ b/packages/SystemUI/res/values-ml/strings.xml @@ -774,7 +774,7 @@ <item quantity="one">%d മിനിറ്റ്</item> </plurals> <string name="battery_panel_title" msgid="5931157246673665963">"ബാറ്ററി ഉപയോഗം"</string> - <string name="battery_detail_charging_summary" msgid="8821202155297559706">"ചാർജുചെയ്യുന്ന സമയത്ത് ബാറ്ററി ലാഭിക്കൽ നടക്കില്ല"</string> + <string name="battery_detail_charging_summary" msgid="8821202155297559706">"ചാർജ് ചെയ്യുമ്പോൾ ബാറ്ററി ലാഭിക്കൽ സാധ്യമല്ല"</string> <string name="battery_detail_switch_title" msgid="6940976502957380405">"ബാറ്ററി ലാഭിക്കൽ"</string> <string name="battery_detail_switch_summary" msgid="3668748557848025990">"പ്രവർത്തനവും പശ്ചാത്തല ഡാറ്റയും കുറയ്ക്കുന്നു"</string> <string name="keyboard_key_button_template" msgid="8005673627272051429">"ബട്ടൺ <xliff:g id="NAME">%1$s</xliff:g>"</string> @@ -966,7 +966,7 @@ <string name="auto_saver_text" msgid="3214960308353838764">"ബാറ്ററി ചാർജ് തീരാൻ സാധ്യതയുണ്ടെങ്കിൽ ഓണാക്കുക"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"വേണ്ട"</string> <string name="auto_saver_enabled_title" msgid="4294726198280286333">"ബാറ്ററി ലാഭിക്കൽ ഷെഡ്യൂൾ ഓണാക്കുക"</string> - <string name="auto_saver_enabled_text" msgid="7889491183116752719">"ബാറ്ററി <xliff:g id="PERCENTAGE">%d</xliff:g>%% ൽ താഴെയാകുമ്പോൾ, ബാറ്ററി ലാഭിക്കൽ സ്വമേധയാ ഓണാകും."</string> + <string name="auto_saver_enabled_text" msgid="7889491183116752719">"ബാറ്ററി <xliff:g id="PERCENTAGE">%d</xliff:g>%% ൽ താഴെയാകുമ്പോൾ, ബാറ്ററി ലാഭിക്കൽ സ്വയമേവ ഓണാകും."</string> <string name="open_saver_setting_action" msgid="2111461909782935190">"ക്രമീകരണം"</string> <string name="auto_saver_okay_action" msgid="7815925750741935386">"മനസ്സിലായി"</string> <string name="heap_dump_tile_name" msgid="2464189856478823046">"SysUI ഹീപ്പ് ഡമ്പ് ചെയ്യുക"</string> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 4b1ed0a25c90..1ab776b2a0a8 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1218,6 +1218,8 @@ <dimen name="bubble_message_padding">4dp</dimen> <!-- Offset between bubbles in their stacked position. --> <dimen name="bubble_stack_offset">10dp</dimen> + <!-- Offset between stack y and animation y for bubble swap. --> + <dimen name="bubble_swap_animation_offset">15dp</dimen> <!-- How far offscreen the bubble stack rests. Cuts off padding and part of icon bitmap. --> <dimen name="bubble_stack_offscreen">9dp</dimen> <!-- How far down the screen the stack starts. --> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index e2ba615e84e6..2be89c1dff63 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1286,6 +1286,9 @@ <!-- Footer vpn present text [CHAR LIMIT=50] --> <string name="branded_vpn_footer">Network may be monitored</string> + <!-- Disclosure at the bottom of Quick Settings that indicates that parental controls are enabled. [CHAR LIMIT=100] --> + <string name="quick_settings_disclosure_parental_controls">This device is managed by your parent</string> + <!-- Disclosure at the bottom of Quick Settings that indicates that the user's device belongs to their organization, and the organization can monitor network traffic on that device. [CHAR LIMIT=100] --> <string name="quick_settings_disclosure_management_monitoring">Your organization owns this device and may monitor network traffic</string> @@ -1359,6 +1362,9 @@ <!-- Monitoring dialog label for button opening a page with more information on the admin's abilities [CHAR LIMIT=30] --> <string name="monitoring_button_view_policies">View Policies</string> + <!-- Monitoring dialog label for button opening a page with more information on parental controls [CHAR LIMIT=30] --> + <string name="monitoring_button_view_controls">View controls</string> + <!-- Dialog that a user can access via Quick Settings. The dialog describes what the IT admin can monitor (and the changes they can make) on the user's device. [CHAR LIMIT=NONE]--> <string name="monitoring_description_named_management">This device belongs to <xliff:g id="organization_name" example="Foo, Inc.">%1$s</xliff:g>.\n\nYour IT admin can monitor and manage settings, corporate access, apps, data associated with your device, and your device\'s location information.\n\nFor more information, contact your IT admin.</string> @@ -1428,6 +1434,10 @@ <!-- Monitoring dialog VPN with profile owner text [CHAR LIMIT=400] --> <string name="monitoring_description_vpn_profile_owned">Your work profile is managed by <xliff:g id="organization">%1$s</xliff:g>.\n\nYour admin is capable of monitoring your network activity including emails, apps, and websites.\n\nFor more information, contact your admin.\n\nYou\'re also connected to a VPN, which can monitor your network activity.</string> + <!-- Dialog that a user can access via Quick Settings. [CHAR LIMIT=NONE]--> + <string name="monitoring_description_parental_controls">This device is managed by your parent. Your parent can see and manage information such as the apps you use, your location, and your screen time.</string> + + <!-- Name for a generic legacy VPN connection [CHAR LIMIT=20] --> <string name="legacy_vpn_name">VPN</string> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ClipDescriptionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ClipDescriptionCompat.java new file mode 100644 index 000000000000..0b1141ee9b30 --- /dev/null +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ClipDescriptionCompat.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.shared.system; + +import android.content.ClipDescription; +import android.content.Intent; + +/** + * Wrapper around ClipDescription. + */ +public abstract class ClipDescriptionCompat { + + public static String MIMETYPE_APPLICATION_ACTIVITY = + ClipDescription.MIMETYPE_APPLICATION_ACTIVITY; + + public static String MIMETYPE_APPLICATION_SHORTCUT = + ClipDescription.MIMETYPE_APPLICATION_SHORTCUT; + + public static String MIMETYPE_APPLICATION_TASK = + ClipDescription.MIMETYPE_APPLICATION_TASK; + + public static String EXTRA_PENDING_INTENT = ClipDescription.EXTRA_PENDING_INTENT; + + public static String EXTRA_TASK_ID = Intent.EXTRA_TASK_ID; +} diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/LauncherAppsCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/LauncherAppsCompat.java new file mode 100644 index 000000000000..d24c779b1416 --- /dev/null +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/LauncherAppsCompat.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.shared.system; + +import android.app.PendingIntent; +import android.content.ComponentName; +import android.content.pm.LauncherApps; +import android.os.Bundle; +import android.os.UserHandle; + +/** + * Wrapper around LauncherApps. + */ +public abstract class LauncherAppsCompat { + + public static PendingIntent getMainActivityLaunchIntent(LauncherApps launcherApps, + ComponentName component, Bundle startActivityOptions, UserHandle user) { + return launcherApps.getMainActivityLaunchIntent(component, startActivityOptions, user); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java index c6e5f09af572..64a2acab79ee 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java @@ -24,6 +24,7 @@ import android.content.pm.ActivityInfo; import android.graphics.PixelFormat; import android.graphics.PointF; import android.os.Bundle; +import android.os.UserHandle; import android.provider.Settings; import android.util.MathUtils; import android.view.Gravity; @@ -232,8 +233,11 @@ class MagnificationModeSwitch { mMagnificationMode ^ Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL; mMagnificationMode = newMode; mImageView.setImageResource(getIconResId(newMode)); - Settings.Secure.putInt(mContext.getContentResolver(), - Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, newMode); + Settings.Secure.putIntForUser( + mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, + newMode, + UserHandle.USER_CURRENT); } private void handleSingleTap() { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java index ab4025f7ef9d..24ab6355c2bd 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java @@ -24,6 +24,9 @@ import android.graphics.PixelFormat; import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.PromptInfo; +import android.hardware.face.FaceSensorPropertiesInternal; +import android.hardware.fingerprint.FingerprintSensorProperties; +import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.os.Binder; import android.os.Bundle; import android.os.Handler; @@ -51,6 +54,7 @@ import com.android.systemui.keyguard.WakefulnessLifecycle; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.List; /** * Top level container/controller for the BiometricPrompt UI. @@ -76,6 +80,8 @@ public class AuthContainerView extends LinearLayout final Config mConfig; final int mEffectiveUserId; + @Nullable private final List<FingerprintSensorPropertiesInternal> mFpProps; + @Nullable private final List<FaceSensorPropertiesInternal> mFaceProps; private final Handler mHandler; private final Injector mInjector; private final IBinder mWindowToken = new Binder(); @@ -111,7 +117,8 @@ public class AuthContainerView extends LinearLayout boolean mRequireConfirmation; int mUserId; String mOpPackageName; - @BiometricAuthenticator.Modality int mModalityMask; + int[] mSensorIds; + boolean mCredentialAllowed; boolean mSkipIntro; long mOperationId; } @@ -159,9 +166,12 @@ public class AuthContainerView extends LinearLayout return this; } - public AuthContainerView build(@BiometricAuthenticator.Modality int modalityMask) { - mConfig.mModalityMask = modalityMask; - return new AuthContainerView(mConfig, new Injector()); + public AuthContainerView build(int[] sensorIds, boolean credentialAllowed, + @Nullable List<FingerprintSensorPropertiesInternal> fpProps, + @Nullable List<FaceSensorPropertiesInternal> faceProps) { + mConfig.mSensorIds = sensorIds; + mConfig.mCredentialAllowed = credentialAllowed; + return new AuthContainerView(mConfig, new Injector(), fpProps, faceProps); } } @@ -242,11 +252,15 @@ public class AuthContainerView extends LinearLayout } @VisibleForTesting - AuthContainerView(Config config, Injector injector) { + AuthContainerView(Config config, Injector injector, + @Nullable List<FingerprintSensorPropertiesInternal> fpProps, + @Nullable List<FaceSensorPropertiesInternal> faceProps) { super(config.mContext); mConfig = config; mInjector = injector; + mFpProps = fpProps; + mFaceProps = faceProps; mEffectiveUserId = mInjector.getUserManager(mContext) .getCredentialOwnerProfile(mConfig.mUserId); @@ -269,24 +283,29 @@ public class AuthContainerView extends LinearLayout // Inflate biometric view only if necessary. if (Utils.isBiometricAllowed(mConfig.mPromptInfo)) { - final @BiometricAuthenticator.Modality int biometricModality = - config.mModalityMask & ~BiometricAuthenticator.TYPE_CREDENTIAL; - - switch (biometricModality) { - case BiometricAuthenticator.TYPE_FINGERPRINT: + if (config.mSensorIds.length == 1) { + final int singleSensorAuthId = config.mSensorIds[0]; + if (Utils.containsSensorId(mFpProps, singleSensorAuthId)) { mBiometricView = (AuthBiometricFingerprintView) factory.inflate(R.layout.auth_biometric_fingerprint_view, null, false); - break; - case BiometricAuthenticator.TYPE_FACE: + } else if (Utils.containsSensorId(mFaceProps, singleSensorAuthId)) { mBiometricView = (AuthBiometricFaceView) factory.inflate(R.layout.auth_biometric_face_view, null, false); - break; - default: - Log.e(TAG, "Unsupported biometric modality: " + biometricModality); + } else { + // Unknown sensorId + Log.e(TAG, "Unknown sensorId: " + singleSensorAuthId); mBiometricView = null; mBackgroundView = null; mBiometricScrollView = null; return; + } + } else { + // The UI currently only supports authentication with a single sensor. + Log.e(TAG, "Unsupported sensor array, length: " + config.mSensorIds.length); + mBiometricView = null; + mBackgroundView = null; + mBiometricScrollView = null; + return; } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java index a4aeb8a9a94d..874c73baf146 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java @@ -29,12 +29,12 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.res.Configuration; -import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricPrompt; import android.hardware.biometrics.IBiometricSysuiReceiver; import android.hardware.biometrics.PromptInfo; import android.hardware.face.FaceManager; +import android.hardware.face.FaceSensorPropertiesInternal; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.os.Bundle; @@ -74,8 +74,12 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, private final StatusBarStateController mStatusBarStateController; private final IActivityTaskManager mActivityTaskManager; @Nullable private final FingerprintManager mFingerprintManager; + @Nullable private final FaceManager mFaceManager; private final Provider<UdfpsController> mUdfpsControllerFactory; + @Nullable private final List<FingerprintSensorPropertiesInternal> mFpProps; + @Nullable private final List<FaceSensorPropertiesInternal> mFaceProps; + // TODO: These should just be saved from onSaveState private SomeArgs mCurrentDialogArgs; @VisibleForTesting @@ -285,14 +289,20 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, StatusBarStateController statusBarStateController, IActivityTaskManager activityTaskManager, @Nullable FingerprintManager fingerprintManager, + @Nullable FaceManager faceManager, Provider<UdfpsController> udfpsControllerFactory) { super(context); mCommandQueue = commandQueue; mStatusBarStateController = statusBarStateController; mActivityTaskManager = activityTaskManager; mFingerprintManager = fingerprintManager; + mFaceManager = faceManager; mUdfpsControllerFactory = udfpsControllerFactory; + mFpProps = mFingerprintManager != null ? mFingerprintManager.getSensorPropertiesInternal() + : null; + mFaceProps = mFaceManager != null ? mFaceManager.getSensorPropertiesInternal() : null; + IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); @@ -326,24 +336,30 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, @Override public void showAuthenticationDialog(PromptInfo promptInfo, IBiometricSysuiReceiver receiver, - @BiometricAuthenticator.Modality int biometricModality, boolean requireConfirmation, + int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation, int userId, String opPackageName, long operationId) { @Authenticators.Types final int authenticators = promptInfo.getAuthenticators(); if (DEBUG) { + StringBuilder ids = new StringBuilder(); + for (int sensorId : sensorIds) { + ids.append(sensorId).append(" "); + } Log.d(TAG, "showAuthenticationDialog, authenticators: " + authenticators - + ", biometricModality: " + biometricModality + + ", sensorIds: " + ids.toString() + + ", credentialAllowed: " + credentialAllowed + ", requireConfirmation: " + requireConfirmation + ", operationId: " + operationId); } SomeArgs args = SomeArgs.obtain(); args.arg1 = promptInfo; args.arg2 = receiver; - args.argi1 = biometricModality; - args.arg3 = requireConfirmation; - args.argi2 = userId; - args.arg4 = opPackageName; - args.arg5 = operationId; + args.arg3 = sensorIds; + args.arg4 = credentialAllowed; + args.arg5 = requireConfirmation; + args.argi1 = userId; + args.arg6 = opPackageName; + args.arg7 = operationId; boolean skipAnimation = false; if (mCurrentDialog != null) { @@ -467,25 +483,28 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, private void showDialog(SomeArgs args, boolean skipAnimation, Bundle savedState) { mCurrentDialogArgs = args; - final @BiometricAuthenticator.Modality int type = args.argi1; + final PromptInfo promptInfo = (PromptInfo) args.arg1; - final boolean requireConfirmation = (boolean) args.arg3; - final int userId = args.argi2; - final String opPackageName = (String) args.arg4; - final long operationId = (long) args.arg5; + final int[] sensorIds = (int[]) args.arg3; + final boolean credentialAllowed = (boolean) args.arg4; + final boolean requireConfirmation = (boolean) args.arg5; + final int userId = args.argi1; + final String opPackageName = (String) args.arg6; + final long operationId = (long) args.arg7; // Create a new dialog but do not replace the current one yet. final AuthDialog newDialog = buildDialog( promptInfo, requireConfirmation, userId, - type, + sensorIds, + credentialAllowed, opPackageName, skipAnimation, operationId); if (newDialog == null) { - Log.e(TAG, "Unsupported type: " + type); + Log.e(TAG, "Unsupported type configuration"); return; } @@ -493,8 +512,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, Log.d(TAG, "userId: " + userId + " savedState: " + savedState + " mCurrentDialog: " + mCurrentDialog - + " newDialog: " + newDialog - + " type: " + type); + + " newDialog: " + newDialog); } if (mCurrentDialog != null) { @@ -550,7 +568,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, } protected AuthDialog buildDialog(PromptInfo promptInfo, boolean requireConfirmation, - int userId, @BiometricAuthenticator.Modality int type, String opPackageName, + int userId, int[] sensorIds, boolean credentialAllowed, String opPackageName, boolean skipIntro, long operationId) { return new AuthContainerView.Builder(mContext) .setCallback(this) @@ -560,6 +578,6 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, .setOpPackageName(opPackageName) .setSkipIntro(skipIntro) .setOperationId(operationId) - .build(type); + .build(sensorIds, credentialAllowed, mFpProps, mFaceProps); } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/Utils.java b/packages/SystemUI/src/com/android/systemui/biometrics/Utils.java index 2e9afa58987a..fd5e85a953ad 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/Utils.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/Utils.java @@ -20,9 +20,11 @@ import static android.hardware.biometrics.BiometricManager.Authenticators; import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE; import android.annotation.IntDef; +import android.annotation.Nullable; import android.app.admin.DevicePolicyManager; import android.content.Context; import android.hardware.biometrics.PromptInfo; +import android.hardware.biometrics.SensorPropertiesInternal; import android.os.UserManager; import android.util.DisplayMetrics; import android.view.ViewGroup; @@ -33,6 +35,7 @@ import com.android.internal.widget.LockPatternUtils; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.List; public class Utils { @@ -98,4 +101,19 @@ public class Utils { final UserManager userManager = context.getSystemService(UserManager.class); return userManager.isManagedProfile(userId); } + + static boolean containsSensorId(@Nullable List<? extends SensorPropertiesInternal> properties, + int sensorId) { + if (properties == null) { + return false; + } + + for (SensorPropertiesInternal prop : properties) { + if (prop.sensorId == sensorId) { + return true; + } + } + + return false; + } } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BadgedImageView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BadgedImageView.java index 9f7358bf94ff..8bcffc8ece1a 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BadgedImageView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BadgedImageView.java @@ -113,6 +113,18 @@ public class BadgedImageView extends ImageView { setClickable(true); } + public void showDotAndBadge(boolean onLeft) { + removeDotSuppressionFlag(BadgedImageView.SuppressionFlag.BEHIND_STACK); + animateDotBadgePositions(onLeft); + + } + + public void hideDotAndBadge(boolean onLeft) { + addDotSuppressionFlag(BadgedImageView.SuppressionFlag.BEHIND_STACK); + mOnLeft = onLeft; + hideBadge(); + } + /** * Updates the view with provided info. */ diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java index bc060209132b..cf2e13356cca 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java @@ -252,8 +252,7 @@ public class BubbleExpandedView extends LinearLayout { mPositioner = mBubbles.getPositioner(); - mTaskView = new TaskView(mContext, mBubbles.getTaskOrganizer(), - new HandlerExecutor(getHandler())); + mTaskView = new TaskView(mContext, mBubbles.getTaskOrganizer()); // Set ActivityView's alpha value as zero, since there is no view content to be shown. setContentVisibility(false); @@ -310,6 +309,12 @@ public class BubbleExpandedView extends LinearLayout { setLayoutDirection(LAYOUT_DIRECTION_LOCALE); } + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + mTaskView.setExecutor(new HandlerExecutor(getHandler())); + } + void updateDimensions() { Resources res = getResources(); mMinHeight = res.getDimensionPixelSize(R.dimen.bubble_expanded_default_height); diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java index 0714c5eb4fa4..1201d42b1fc5 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java @@ -90,6 +90,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.function.Consumer; +import java.util.stream.Collectors; /** * Renders bubbles in a stack and handles animating expanded and collapsed states. @@ -1479,12 +1480,24 @@ public class BubbleStackView extends FrameLayout logBubbleEvent(bubble, FrameworkStatsLog.BUBBLE_UICHANGED__ACTION__UPDATED); } + /** + * Update bubble order and pointer position. + */ public void updateBubbleOrder(List<Bubble> bubbles) { - for (int i = 0; i < bubbles.size(); i++) { - Bubble bubble = bubbles.get(i); - mBubbleContainer.reorderView(bubble.getIconView(), i); + final Runnable reorder = () -> { + for (int i = 0; i < bubbles.size(); i++) { + Bubble bubble = bubbles.get(i); + mBubbleContainer.reorderView(bubble.getIconView(), i); + } + }; + if (mIsExpanded) { + reorder.run(); + updateBubbleIcons(); + } else { + List<View> bubbleViews = bubbles.stream() + .map(b -> b.getIconView()).collect(Collectors.toList()); + mStackAnimationController.animateReorder(bubbleViews, reorder); } - updateBubbleIcons(); updatePointerPosition(); } @@ -2595,17 +2608,11 @@ public class BubbleStackView extends FrameLayout bv.setZ((mMaxBubbles * mBubbleElevation) - i); if (mIsExpanded) { - bv.removeDotSuppressionFlag( - BadgedImageView.SuppressionFlag.BEHIND_STACK); - bv.animateDotBadgePositions(false /* onLeft */); + bv.showDotAndBadge(false /* onLeft */); } else if (i == 0) { - bv.removeDotSuppressionFlag( - BadgedImageView.SuppressionFlag.BEHIND_STACK); - bv.animateDotBadgePositions(!mStackOnLeftOrWillBe); + bv.showDotAndBadge(!mStackOnLeftOrWillBe); } else { - bv.addDotSuppressionFlag( - BadgedImageView.SuppressionFlag.BEHIND_STACK); - bv.hideBadge(); + bv.hideDotAndBadge(!mStackOnLeftOrWillBe); } } } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/TaskView.java b/packages/SystemUI/src/com/android/systemui/bubbles/TaskView.java index 85616d1513f5..0a2cfbfffd9e 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/TaskView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/TaskView.java @@ -30,7 +30,6 @@ import android.content.pm.LauncherApps; import android.content.pm.ShortcutInfo; import android.graphics.Rect; import android.os.Binder; -import android.os.Handler; import android.view.SurfaceControl; import android.view.SurfaceHolder; import android.view.SurfaceView; @@ -82,21 +81,25 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback, private boolean mSurfaceCreated; private boolean mIsInitialized; private Listener mListener; - private final Executor mExecutor; + private Executor mExecutor; private final Rect mTmpRect = new Rect(); private final Rect mTmpRootRect = new Rect(); - public TaskView(Context context, ShellTaskOrganizer organizer, Executor executor) { + public TaskView(Context context, ShellTaskOrganizer organizer) { super(context, null, 0, 0, true /* disableBackgroundLayer */); - mExecutor = executor; mTaskOrganizer = organizer; setUseAlpha(); getHolder().addCallback(this); mGuard.open("release"); } + // TODO: Use TaskOrganizer executor when part of wmshell proper + public void setExecutor(Executor executor) { + mExecutor = executor; + } + /** * Only one listener may be set on the view, throws an exception otherwise. */ @@ -225,6 +228,7 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback, @Override public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) { + if (mExecutor == null) return; mExecutor.execute(() -> { mTaskInfo = taskInfo; mTaskToken = taskInfo.token; @@ -253,6 +257,7 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback, @Override public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) { + if (mExecutor == null) return; mExecutor.execute(() -> { if (mTaskToken == null || !mTaskToken.equals(taskInfo.token)) return; @@ -268,6 +273,7 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback, @Override public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) { + if (mExecutor == null) return; mExecutor.execute(() -> { mTaskInfo.taskDescription = taskInfo.taskDescription; setResizeBackgroundColor(taskInfo.taskDescription.getBackgroundColor()); @@ -276,6 +282,7 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback, @Override public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) { + if (mExecutor == null) return; mExecutor.execute(() -> { if (mTaskToken == null || !mTaskToken.equals(taskInfo.token)) return; if (mListener != null) { diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java index 31e1ca839e5d..c410b8267dd4 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java @@ -34,6 +34,7 @@ import androidx.dynamicanimation.animation.SpringAnimation; import androidx.dynamicanimation.animation.SpringForce; import com.android.systemui.R; +import com.android.systemui.bubbles.BadgedImageView; import com.android.systemui.bubbles.BubblePositioner; import com.android.systemui.bubbles.BubbleStackView; import com.android.wm.shell.animation.PhysicsAnimator; @@ -45,6 +46,7 @@ import com.google.android.collect.Sets; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.HashMap; +import java.util.List; import java.util.Set; import java.util.function.IntSupplier; @@ -63,6 +65,10 @@ public class StackAnimationController extends private static final float ANIMATE_IN_STIFFNESS = 1000f; private static final int ANIMATE_IN_START_DELAY = 25; + /** Values to use for animating updated bubble to top of stack. */ + private static final float BUBBLE_SWAP_SCALE = 0.8f; + private static final long BUBBLE_SWAP_DURATION = 300L; + /** * Values to use for the default {@link SpringForce} provided to the physics animation layout. */ @@ -180,6 +186,12 @@ public class StackAnimationController extends /** Horizontal offset of bubbles in the stack. */ private float mStackOffset; + /** Offset between stack y and animation y for bubble swap. */ + private float mSwapAnimationOffset; + /** Max number of bubbles to show in the expanded bubble row. */ + private int mMaxBubbles; + /** Default bubble elevation. */ + private int mElevation; /** Diameter of the bubble icon. */ private int mBubbleBitmapSize; /** Width of the bubble (icon and padding). */ @@ -770,6 +782,50 @@ public class StackAnimationController extends } } + public void animateReorder(List<View> bubbleViews, Runnable after) { + for (int newIndex = 0; newIndex < bubbleViews.size(); newIndex++) { + View view = bubbleViews.get(newIndex); + final int oldIndex= mLayout.indexOfChild(view); + animateSwap(view, oldIndex, newIndex, after); + } + } + + private void animateSwap(View view, int oldIndex, int newIndex, Runnable finishReorder) { + final float newY = getStackPosition().y + newIndex * mSwapAnimationOffset; + final float swapY = newIndex == 0 + ? newY - mSwapAnimationOffset // Above top of stack + : newY + mSwapAnimationOffset; // Below where bubble will be + view.animate() + .scaleX(BUBBLE_SWAP_SCALE) + .scaleY(BUBBLE_SWAP_SCALE) + .translationY(swapY) + .setDuration(BUBBLE_SWAP_DURATION) + .withEndAction(() -> finishSwapAnimation(view, oldIndex, newIndex, finishReorder)); + } + + private void finishSwapAnimation(View view, int oldIndex, int newIndex, + Runnable finishReorder) { + + // At this point, swapping bubbles have the least overlap. + // Update z-index and badge visibility here for least jarring transition. + view.setZ((mMaxBubbles * mElevation) - newIndex); + BadgedImageView bv = (BadgedImageView) view; + if (oldIndex == 0 && newIndex > 0) { + bv.hideDotAndBadge(!isStackOnLeftSide()); + } else if (oldIndex > 0 && newIndex == 0) { + bv.showDotAndBadge(!isStackOnLeftSide()); + } + + // Animate bubble back into stack, at new index and original size. + final float newY = getStackPosition().y + newIndex * mStackOffset; + view.animate() + .scaleX(1f) + .scaleY(1f) + .translationY(newY) + .setDuration(BUBBLE_SWAP_DURATION) + .withEndAction(() -> finishReorder.run()); + } + @Override void onChildReordered(View child, int oldIndex, int newIndex) { if (isStackPositionSet()) { @@ -781,6 +837,9 @@ public class StackAnimationController extends void onActiveControllerForLayout(PhysicsAnimationLayout layout) { Resources res = layout.getResources(); mStackOffset = res.getDimensionPixelSize(R.dimen.bubble_stack_offset); + mSwapAnimationOffset = res.getDimensionPixelSize(R.dimen.bubble_swap_animation_offset); + mMaxBubbles = res.getInteger(R.integer.bubbles_max_rendered); + mElevation = res.getDimensionPixelSize(R.dimen.bubble_elevation); mBubbleSize = res.getDimensionPixelSize(R.dimen.individual_bubble_size); mBubbleBitmapSize = res.getDimensionPixelSize(R.dimen.bubble_bitmap_size); mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java index c90182b15da6..270fcbffbd71 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java @@ -16,11 +16,13 @@ package com.android.systemui.qs; import android.app.AlertDialog; +import android.app.admin.DeviceAdminInfo; import android.app.admin.DevicePolicyEventLogger; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.UserInfo; +import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.Looper; import android.os.Message; @@ -39,6 +41,8 @@ import android.view.Window; import android.widget.ImageView; import android.widget.TextView; +import androidx.annotation.VisibleForTesting; + import com.android.internal.util.FrameworkStatsLog; import com.android.systemui.Dependency; import com.android.systemui.FontSizeUtils; @@ -156,15 +160,16 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen mSecurityController.getWorkProfileOrganizationName(); final boolean isProfileOwnerOfOrganizationOwnedDevice = mSecurityController.isProfileOwnerOfOrganizationOwnedDevice(); + final boolean isParentalControlsEnabled = mSecurityController.isParentalControlsEnabled(); // Update visibility of footer mIsVisible = (isDeviceManaged && !isDemoDevice) || hasCACerts || hasCACertsInWorkProfile || vpnName != null || vpnNameWorkProfile != null - || isProfileOwnerOfOrganizationOwnedDevice; + || isProfileOwnerOfOrganizationOwnedDevice || isParentalControlsEnabled; // Update the string mFooterTextContent = getFooterText(isDeviceManaged, hasWorkProfile, hasCACerts, hasCACertsInWorkProfile, isNetworkLoggingEnabled, vpnName, vpnNameWorkProfile, organizationName, workProfileOrganizationName, - isProfileOwnerOfOrganizationOwnedDevice); + isProfileOwnerOfOrganizationOwnedDevice, isParentalControlsEnabled); // Update the icon int footerIconId = R.drawable.ic_info_outline; if (vpnName != null || vpnNameWorkProfile != null) { @@ -185,7 +190,10 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen boolean hasCACerts, boolean hasCACertsInWorkProfile, boolean isNetworkLoggingEnabled, String vpnName, String vpnNameWorkProfile, CharSequence organizationName, CharSequence workProfileOrganizationName, - boolean isProfileOwnerOfOrganizationOwnedDevice) { + boolean isProfileOwnerOfOrganizationOwnedDevice, boolean isParentalControlsEnabled) { + if (isParentalControlsEnabled) { + return mContext.getString(R.string.quick_settings_disclosure_parental_controls); + } if (isDeviceManaged || DEBUG_FORCE_VISIBLE) { if (hasCACerts || hasCACertsInWorkProfile || isNetworkLoggingEnabled) { if (organizationName == null) { @@ -268,6 +276,27 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen } private void createDialog() { + mDialog = new SystemUIDialog(mContext); + mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE); + mDialog.setButton(DialogInterface.BUTTON_POSITIVE, getPositiveButton(), this); + mDialog.setButton(DialogInterface.BUTTON_NEGATIVE, getNegativeButton(), this); + + mDialog.setView(createDialogView()); + + mDialog.show(); + mDialog.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT); + } + + @VisibleForTesting + View createDialogView() { + if (mSecurityController.isParentalControlsEnabled()) { + return createParentalControlsDialogView(); + } + return createOrganizationDialogView(); + } + + private View createOrganizationDialogView() { final boolean isDeviceManaged = mSecurityController.isDeviceManaged(); boolean isProfileOwnerOfOrganizationOwnedDevice = mSecurityController.isProfileOwnerOfOrganizationOwnedDevice(); @@ -282,13 +311,10 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen final String vpnName = mSecurityController.getPrimaryVpnName(); final String vpnNameWorkProfile = mSecurityController.getWorkProfileVpnName(); - mDialog = new SystemUIDialog(mContext); - mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE); + View dialogView = LayoutInflater.from( new ContextThemeWrapper(mContext, R.style.Theme_SystemUI_Dialog)) .inflate(R.layout.quick_settings_footer_dialog, null, false); - mDialog.setView(dialogView); - mDialog.setButton(DialogInterface.BUTTON_POSITIVE, getPositiveButton(), this); // device management section CharSequence managementMessage = getManagementMessage(isDeviceManaged, @@ -353,9 +379,26 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen vpnMessage != null, dialogView); - mDialog.show(); - mDialog.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT); + return dialogView; + } + + private View createParentalControlsDialogView() { + View dialogView = LayoutInflater.from( + new ContextThemeWrapper(mContext, R.style.Theme_SystemUI_Dialog)) + .inflate(R.layout.quick_settings_footer_dialog_parental_controls, null, false); + + DeviceAdminInfo info = mSecurityController.getDeviceAdminInfo(); + Drawable icon = mSecurityController.getIcon(info); + if (icon != null) { + ImageView imageView = (ImageView) dialogView.findViewById(R.id.parental_controls_icon); + imageView.setImageDrawable(icon); + } + + TextView parentalControlsTitle = + (TextView) dialogView.findViewById(R.id.parental_controls_title); + parentalControlsTitle.setText(mSecurityController.getLabel(info)); + + return dialogView; } protected void configSubtitleVisibility(boolean showDeviceManagement, boolean showCaCerts, @@ -394,6 +437,13 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen return mContext.getString(R.string.ok); } + private String getNegativeButton() { + if (mSecurityController.isParentalControlsEnabled()) { + return mContext.getString(R.string.monitoring_button_view_controls); + } + return null; + } + protected CharSequence getManagementMessage(boolean isDeviceManaged, CharSequence organizationName, boolean isProfileOwnerOfOrganizationOwnedDevice, CharSequence workProfileOrganizationName) { diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java index 5d8f70c4e460..f063fbe7a384 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java @@ -108,7 +108,7 @@ public class ScreenshotController { abstract void onActionsReady(ScreenshotController.SavedImageData imageData); } - private static final String TAG = "GlobalScreenshotController"; + private static final String TAG = "ScreenshotController"; // These strings are used for communicating the action invoked to // ScreenshotNotificationSmartActionsProvider. diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java index 03fe2920405f..29f6e8b0db00 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java @@ -49,7 +49,6 @@ import android.util.Log; import android.util.MathUtils; import android.view.LayoutInflater; import android.view.View; -import android.view.ViewGroup; import android.view.ViewOutlineProvider; import android.view.ViewTreeObserver; import android.view.WindowInsets; @@ -73,7 +72,7 @@ import java.util.function.Consumer; public class ScreenshotView extends FrameLayout implements ViewTreeObserver.OnComputeInternalInsetsListener { - private static final String TAG = "GlobalScreenshotView"; + private static final String TAG = "ScreenshotView"; private static final long SCREENSHOT_FLASH_IN_DURATION_MS = 133; private static final long SCREENSHOT_FLASH_OUT_DURATION_MS = 217; @@ -105,7 +104,6 @@ public class ScreenshotView extends FrameLayout implements private boolean mDirectionLTR; private ScreenshotSelectorView mScreenshotSelectorView; - private ImageView mScreenshotAnimatedView; private ImageView mScreenshotPreview; private ImageView mScreenshotFlash; private ImageView mActionsContainerBackground; @@ -116,7 +114,7 @@ public class ScreenshotView extends FrameLayout implements private ScreenshotActionChip mShareChip; private ScreenshotActionChip mEditChip; - private ArrayList<ScreenshotActionChip> mSmartChips = new ArrayList<>(); + private final ArrayList<ScreenshotActionChip> mSmartChips = new ArrayList<>(); private PendingInteraction mPendingInteraction; private enum PendingInteraction { @@ -183,8 +181,6 @@ public class ScreenshotView extends FrameLayout implements @Override // View protected void onFinishInflate() { - mScreenshotAnimatedView = requireNonNull( - findViewById(R.id.global_screenshot_animated_view)); mScreenshotPreview = requireNonNull(findViewById(R.id.global_screenshot_preview)); mActionsContainerBackground = requireNonNull(findViewById( R.id.global_screenshot_actions_container_background)); @@ -198,14 +194,6 @@ public class ScreenshotView extends FrameLayout implements mShareChip = requireNonNull(mActionsContainer.findViewById(R.id.screenshot_share_chip)); mEditChip = requireNonNull(mActionsContainer.findViewById(R.id.screenshot_edit_chip)); - mScreenshotAnimatedView.setClipToOutline(true); - mScreenshotAnimatedView.setOutlineProvider(new ViewOutlineProvider() { - @Override - public void getOutline(View view, Outline outline) { - outline.setRoundRect(new Rect(0, 0, view.getWidth(), view.getHeight()), - ROUNDED_CORNER_RADIUS * view.getWidth()); - } - }); mScreenshotPreview.setClipToOutline(true); mScreenshotPreview.setOutlineProvider(new ViewOutlineProvider() { @Override @@ -218,8 +206,6 @@ public class ScreenshotView extends FrameLayout implements setFocusable(true); mScreenshotSelectorView.setFocusable(true); mScreenshotSelectorView.setFocusableInTouchMode(true); - mScreenshotAnimatedView.setPivotX(0); - mScreenshotAnimatedView.setPivotY(0); mActionsContainer.setScrollX(0); mNavMode = getResources().getInteger( @@ -253,13 +239,6 @@ public class ScreenshotView extends FrameLayout implements } void prepareForAnimation(Bitmap bitmap, Rect screenRect, Insets screenInsets) { - mScreenshotAnimatedView.setImageDrawable( - createScreenDrawable(mResources, bitmap, screenInsets)); - setAnimatedViewSize(screenRect.width(), screenRect.height()); - - // will show when the animation starts - mScreenshotAnimatedView.setVisibility(View.GONE); - mScreenshotPreview.setImageDrawable(createScreenDrawable(mResources, bitmap, screenInsets)); // make static preview invisible (from gone) so we can query its location on screen mScreenshotPreview.setVisibility(View.INVISIBLE); @@ -275,10 +254,10 @@ public class ScreenshotView extends FrameLayout implements float cornerScale = mCornerSizeX / (mOrientationPortrait ? bounds.width() : bounds.height()); - final float currentScale = 1f; + final float currentScale = 1 / cornerScale; - mScreenshotAnimatedView.setScaleX(currentScale); - mScreenshotAnimatedView.setScaleY(currentScale); + mScreenshotPreview.setScaleX(currentScale); + mScreenshotPreview.setScaleY(currentScale); mDismissButton.setAlpha(0); mDismissButton.setVisibility(View.VISIBLE); @@ -312,36 +291,33 @@ public class ScreenshotView extends FrameLayout implements float t = animation.getAnimatedFraction(); if (t < scalePct) { float scale = MathUtils.lerp( - currentScale, cornerScale, mFastOutSlowIn.getInterpolation(t / scalePct)); - mScreenshotAnimatedView.setScaleX(scale); - mScreenshotAnimatedView.setScaleY(scale); + currentScale, 1, mFastOutSlowIn.getInterpolation(t / scalePct)); + mScreenshotPreview.setScaleX(scale); + mScreenshotPreview.setScaleY(scale); } else { - mScreenshotAnimatedView.setScaleX(cornerScale); - mScreenshotAnimatedView.setScaleY(cornerScale); + mScreenshotPreview.setScaleX(1); + mScreenshotPreview.setScaleY(1); } - float currentScaleX = mScreenshotAnimatedView.getScaleX(); - float currentScaleY = mScreenshotAnimatedView.getScaleY(); - if (t < xPositionPct) { float xCenter = MathUtils.lerp(startPos.x, finalPos.x, mFastOutSlowIn.getInterpolation(t / xPositionPct)); - mScreenshotAnimatedView.setX(xCenter - bounds.width() * currentScaleX / 2f); + mScreenshotPreview.setX(xCenter - mScreenshotPreview.getWidth() / 2f); } else { - mScreenshotAnimatedView.setX(finalPos.x - bounds.width() * currentScaleX / 2f); + mScreenshotPreview.setX(finalPos.x - mScreenshotPreview.getWidth() / 2f); } float yCenter = MathUtils.lerp( startPos.y, finalPos.y, mFastOutSlowIn.getInterpolation(t)); - mScreenshotAnimatedView.setY(yCenter - bounds.height() * currentScaleY / 2f); + mScreenshotPreview.setY(yCenter - mScreenshotPreview.getHeight() / 2f); if (t >= dismissPct) { mDismissButton.setAlpha((t - dismissPct) / (1 - dismissPct)); - float currentX = mScreenshotAnimatedView.getX(); - float currentY = mScreenshotAnimatedView.getY(); + float currentX = mScreenshotPreview.getX(); + float currentY = mScreenshotPreview.getY(); mDismissButton.setY(currentY - mDismissButton.getHeight() / 2f); if (mDirectionLTR) { - mDismissButton.setX(currentX - + bounds.width() * currentScaleX - mDismissButton.getWidth() / 2f); + mDismissButton.setX(currentX + mScreenshotPreview.getWidth() + - mDismissButton.getWidth() / 2f); } else { mDismissButton.setX(currentX - mDismissButton.getWidth() / 2f); } @@ -352,7 +328,7 @@ public class ScreenshotView extends FrameLayout implements @Override public void onAnimationStart(Animator animation) { super.onAnimationStart(animation); - mScreenshotAnimatedView.setVisibility(View.VISIBLE); + mScreenshotPreview.setVisibility(View.VISIBLE); } }); @@ -380,13 +356,11 @@ public class ScreenshotView extends FrameLayout implements mDismissButton.setX(finalDismissX); mDismissButton.setY( finalPos.y - dismissOffset - bounds.height() * cornerScale / 2f); - mScreenshotAnimatedView.setScaleX(1); - mScreenshotAnimatedView.setScaleY(1); - mScreenshotAnimatedView.setX(finalPos.x - bounds.width() * cornerScale / 2f); - mScreenshotAnimatedView.setY(finalPos.y - bounds.height() * cornerScale / 2f); - mScreenshotAnimatedView.setVisibility(View.GONE); - mScreenshotPreview.setVisibility(View.VISIBLE); - forceLayout(); + mScreenshotPreview.setScaleX(1); + mScreenshotPreview.setScaleY(1); + mScreenshotPreview.setX(finalPos.x - bounds.width() * cornerScale / 2f); + mScreenshotPreview.setY(finalPos.y - bounds.height() * cornerScale / 2f); + requestLayout(); createScreenshotActionsShadeAnimation().start(); } }); @@ -540,8 +514,6 @@ public class ScreenshotView extends FrameLayout implements void reset() { // Clear any references to the bitmap mScreenshotPreview.setImageDrawable(null); - mScreenshotAnimatedView.setImageDrawable(null); - mScreenshotAnimatedView.setVisibility(View.GONE); mActionsContainerBackground.setVisibility(View.GONE); mActionsContainer.setVisibility(View.GONE); mBackgroundProtection.setAlpha(0f); @@ -568,13 +540,6 @@ public class ScreenshotView extends FrameLayout implements mScreenshotSelectorView.stop(); } - private void setAnimatedViewSize(int width, int height) { - ViewGroup.LayoutParams layoutParams = mScreenshotAnimatedView.getLayoutParams(); - layoutParams.width = width; - layoutParams.height = height; - mScreenshotAnimatedView.setLayoutParams(layoutParams); - } - /** * Create a drawable using the size of the bitmap and insets as the fractional inset parameters. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index dcee9fa9e648..5b3763e66307 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -284,7 +284,7 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< default void showAuthenticationDialog(PromptInfo promptInfo, IBiometricSysuiReceiver receiver, - @BiometricAuthenticator.Modality int biometricModality, + int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation, int userId, String opPackageName, long operationId) { } default void onBiometricAuthenticated() { } @@ -829,17 +829,18 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< @Override public void showAuthenticationDialog(PromptInfo promptInfo, IBiometricSysuiReceiver receiver, - @BiometricAuthenticator.Modality int biometricModality, boolean requireConfirmation, + int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation, int userId, String opPackageName, long operationId) { synchronized (mLock) { SomeArgs args = SomeArgs.obtain(); args.arg1 = promptInfo; args.arg2 = receiver; - args.argi1 = biometricModality; - args.arg3 = requireConfirmation; - args.argi2 = userId; - args.arg4 = opPackageName; - args.arg5 = operationId; + args.arg3 = sensorIds; // + args.arg4 = credentialAllowed; // + args.arg5 = requireConfirmation; + args.argi1 = userId; + args.arg6 = opPackageName; + args.arg7 = operationId; mHandler.obtainMessage(MSG_BIOMETRIC_SHOW, args) .sendToTarget(); } @@ -1264,11 +1265,12 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< mCallbacks.get(i).showAuthenticationDialog( (PromptInfo) someArgs.arg1, (IBiometricSysuiReceiver) someArgs.arg2, - someArgs.argi1 /* biometricModality */, - (boolean) someArgs.arg3 /* requireConfirmation */, - someArgs.argi2 /* userId */, - (String) someArgs.arg4 /* opPackageName */, - (long) someArgs.arg5 /* operationId */); + (int[]) someArgs.arg3 /* sensorIds */, + (boolean) someArgs.arg4 /* credentialAllowed */, + (boolean) someArgs.arg5 /* requireConfirmation */, + someArgs.argi1 /* userId */, + (String) someArgs.arg6 /* opPackageName */, + (long) someArgs.arg7 /* operationId */); } someArgs.recycle(); break; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java index 597658276d49..25c8e7feb9b2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java @@ -170,7 +170,7 @@ public class NotificationHeaderUtil { private void sanitizeChild(View child) { if (child != null) { ViewGroup header = child.findViewById( - com.android.internal.R.id.notification_header); + com.android.internal.R.id.notification_top_line); sanitizeHeader(header); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java index 256ee2081f41..014d5c274c1f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java @@ -360,15 +360,11 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit collapseOnMainThread(); } - final int count = getVisibleNotificationsCount(); - final int rank = entry.getRanking().getRank(); NotificationVisibility.NotificationLocation location = NotificationLogger.getNotificationLocation(entry); - final NotificationVisibility nv = NotificationVisibility.obtain(notificationKey, - rank, count, true, location); + final NotificationVisibility nv = NotificationVisibility.obtain(entry.getKey(), + entry.getRanking().getRank(), getVisibleNotificationsCount(), true, location); - // NMS will officially remove notification if the notification has FLAG_AUTO_CANCEL: - mClickNotifier.onNotificationClick(notificationKey, nv); // TODO (b/162832756): delete these notification removals when migrating to the new // pipeline; this is taken care of in {@link NotifCollection#tryRemoveNotification} @@ -378,9 +374,25 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit if (shouldAutoCancel(entry.getSbn()) || mRemoteInputManager.isNotificationKeptForRemoteInputHistory( notificationKey)) { - // manually call notification removal in order to cancel any lifetime extenders - removeNotification(row.getEntry()); + // Immediately remove notification from visually showing. + // We have to post the removal to the UI thread for synchronization. + mMainThreadHandler.post(() -> { + final Runnable removeNotification = () -> { + mOnUserInteractionCallback.onDismiss(entry, REASON_CLICK); + mClickNotifier.onNotificationClick(entry.getKey(), nv); + }; + if (mPresenter.isCollapsing()) { + // To avoid lags we're only performing the remove + // after the shade is collapsed + mShadeController.addPostCollapseAction(removeNotification); + } else { + removeNotification.run(); + } + }); } + } else { + // inform NMS that the notification was clicked + mClickNotifier.onNotificationClick(notificationKey, nv); } mIsCollapsingToShowActivityOverLockscreen = false; @@ -565,21 +577,6 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit return entry.shouldSuppressFullScreenIntent(); } - private void removeNotification(NotificationEntry entry) { - // We have to post it to the UI thread for synchronization - mMainThreadHandler.post(() -> { - if (mPresenter.isCollapsing()) { - // To avoid lags we're only performing the remove - // after the shade was collapsed - mShadeController.addPostCollapseAction( - () -> mOnUserInteractionCallback.onDismiss(entry, REASON_CLICK) - ); - } else { - mOnUserInteractionCallback.onDismiss(entry, REASON_CLICK); - } - }); - } - // --------------------- NotificationEntryManager/NotifPipeline methods ------------------------ private int getVisibleNotificationsCount() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java index c84589a9e142..4552026ced4b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java @@ -73,9 +73,7 @@ import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewW import com.android.systemui.statusbar.notification.stack.StackStateAnimator; import com.android.systemui.statusbar.phone.LightBarController; -import java.util.Collections; import java.util.HashMap; -import java.util.Set; import java.util.function.Consumer; /** @@ -315,7 +313,8 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene mRemoteInputs = remoteInputs; mRemoteInput = remoteInput; mEditText.setHint(mRemoteInput.getLabel()); - mEditText.mSupportedMimeTypes = remoteInput.getAllowedDataTypes(); + mEditText.mSupportedMimeTypes = (remoteInput.getAllowedDataTypes() == null) ? null + : remoteInput.getAllowedDataTypes().toArray(new String[0]); mEntry.editedSuggestionInfo = editedSuggestionInfo; if (editedSuggestionInfo != null) { @@ -574,7 +573,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene boolean mShowImeOnInputConnection; private LightBarController mLightBarController; UserHandle mUser; - private Set<String> mSupportedMimeTypes; + private String[] mSupportedMimeTypes; public RemoteEditText(Context context, AttributeSet attrs) { super(context, attrs); @@ -585,35 +584,31 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene @Override protected void onFinishInflate() { super.onFinishInflate(); - setOnReceiveContentCallback(new OnReceiveContentCallback<View>() { - @Override - public boolean onReceiveContent(@NonNull View view, @NonNull Payload payload) { - ClipData clip = payload.getClip(); - if (clip.getItemCount() == 0) { - return false; - } - Uri contentUri = clip.getItemAt(0).getUri(); - ClipDescription description = clip.getDescription(); - String mimeType = null; - if (description.getMimeTypeCount() > 0) { - mimeType = description.getMimeType(0); - } - if (mimeType != null) { - Intent dataIntent = mRemoteInputView - .prepareRemoteInputFromData(mimeType, contentUri); - mRemoteInputView.sendRemoteInput(dataIntent); - } - return true; - } - - @NonNull - @Override - public Set<String> getSupportedMimeTypes(@NonNull View view) { - return mSupportedMimeTypes != null - ? mSupportedMimeTypes - : Collections.emptySet(); - } - }); + if (mSupportedMimeTypes != null && mSupportedMimeTypes.length > 0) { + setOnReceiveContentCallback(mSupportedMimeTypes, + new OnReceiveContentCallback<View>() { + @Override + public boolean onReceiveContent(@NonNull View view, + @NonNull Payload payload) { + ClipData clip = payload.getClip(); + if (clip.getItemCount() == 0) { + return false; + } + Uri contentUri = clip.getItemAt(0).getUri(); + ClipDescription description = clip.getDescription(); + String mimeType = null; + if (description.getMimeTypeCount() > 0) { + mimeType = description.getMimeType(0); + } + if (mimeType != null) { + Intent dataIntent = mRemoteInputView + .prepareRemoteInputFromData(mimeType, contentUri); + mRemoteInputView.sendRemoteInput(dataIntent); + } + return true; + } + }); + } } private void defocusIfNeeded(boolean animate) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java index 79d264ca4577..e8331a176134 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java @@ -15,6 +15,9 @@ */ package com.android.systemui.statusbar.policy; +import android.app.admin.DeviceAdminInfo; +import android.graphics.drawable.Drawable; + import com.android.systemui.Dumpable; import com.android.systemui.statusbar.policy.SecurityController.SecurityControllerCallback; @@ -40,6 +43,15 @@ public interface SecurityController extends CallbackController<SecurityControlle boolean hasCACertInCurrentUser(); boolean hasCACertInWorkProfile(); void onUserSwitched(int newUserId); + /** Whether or not parental controls is enabled */ + boolean isParentalControlsEnabled(); + /** DeviceAdminInfo for active admin */ + DeviceAdminInfo getDeviceAdminInfo(); + /** Icon for admin */ + Drawable getIcon(DeviceAdminInfo info); + /** Label for admin */ + CharSequence getLabel(DeviceAdminInfo info); + public interface SecurityControllerCallback { void onStateChanged(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java index 7e54e8d1c1c3..1d778419cbaf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java @@ -16,15 +16,19 @@ package com.android.systemui.statusbar.policy; import android.app.ActivityManager; +import android.app.admin.DeviceAdminInfo; import android.app.admin.DevicePolicyManager; import android.content.BroadcastReceiver; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.ResolveInfo; import android.content.pm.UserInfo; +import android.graphics.drawable.Drawable; import android.net.ConnectivityManager; import android.net.ConnectivityManager.NetworkCallback; import android.net.IConnectivityManager; @@ -53,7 +57,10 @@ import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.settings.CurrentUserTracker; +import org.xmlpull.v1.XmlPullParserException; + import java.io.FileDescriptor; +import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.concurrent.Executor; @@ -306,6 +313,50 @@ public class SecurityControllerImpl extends CurrentUserTracker implements Securi fireCallbacks(); } + @Override + public boolean isParentalControlsEnabled() { + return getProfileOwnerOrDeviceOwnerSupervisionComponent() != null; + } + + @Override + public DeviceAdminInfo getDeviceAdminInfo() { + return getDeviceAdminInfo(getProfileOwnerOrDeviceOwnerComponent()); + } + + @Override + public Drawable getIcon(DeviceAdminInfo info) { + return (info == null) ? null : info.loadIcon(mPackageManager); + } + + @Override + public CharSequence getLabel(DeviceAdminInfo info) { + return (info == null) ? null : info.loadLabel(mPackageManager); + } + + private ComponentName getProfileOwnerOrDeviceOwnerSupervisionComponent() { + UserHandle currentUser = new UserHandle(mCurrentUserId); + return mDevicePolicyManager + .getProfileOwnerOrDeviceOwnerSupervisionComponent(currentUser); + } + + // Returns the ComponentName of the current DO/PO. Right now it only checks the supervision + // component but can be changed to check for other DO/POs. This change would make getIcon() + // and getLabel() work for all admins. + private ComponentName getProfileOwnerOrDeviceOwnerComponent() { + return getProfileOwnerOrDeviceOwnerSupervisionComponent(); + } + + private DeviceAdminInfo getDeviceAdminInfo(ComponentName componentName) { + try { + ResolveInfo resolveInfo = new ResolveInfo(); + resolveInfo.activityInfo = mPackageManager.getReceiverInfo(componentName, + PackageManager.GET_META_DATA); + return new DeviceAdminInfo(mContext, resolveInfo); + } catch (NameNotFoundException | XmlPullParserException | IOException e) { + return null; + } + } + private void refreshCACerts(int userId) { mBgExecutor.execute(() -> { Pair<Integer, Boolean> idWithCert = null; diff --git a/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java b/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java index 1c682e3bb7dc..409d1361223c 100644 --- a/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java +++ b/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java @@ -129,6 +129,8 @@ public class ToastUI extends SystemUI implements CommandQueue.Callbacks { mCallback = callback; mPresenter = new ToastPresenter(context, mIAccessibilityManager, mNotificationManager, packageName); + // Set as trusted overlay so touches can pass through toasts + mPresenter.getLayoutParams().setTrustedOverlay(); mToastLogger.logOnShowToast(uid, packageName, text.toString(), token.toString()); mPresenter.show(mToast.getView(), token, windowToken, duration, mToast.getGravity(), mToast.getXOffset(), mToast.getYOffset(), mToast.getHorizontalMargin(), diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java index 6bedd392ef3a..9701b40a06a6 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java @@ -17,8 +17,6 @@ package com.android.systemui.wmshell; import android.content.Context; -import android.os.Handler; -import android.view.LayoutInflater; import com.android.systemui.dagger.WMSingleton; import com.android.wm.shell.ShellTaskOrganizer; @@ -27,6 +25,7 @@ import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.pip.Pip; import com.android.wm.shell.pip.PipBoundsHandler; import com.android.wm.shell.pip.PipBoundsState; +import com.android.wm.shell.pip.PipMediaController; import com.android.wm.shell.pip.PipSurfaceTransactionHelper; import com.android.wm.shell.pip.PipTaskOrganizer; import com.android.wm.shell.pip.PipUiEventLogger; @@ -53,6 +52,7 @@ public abstract class TvPipModule { PipBoundsState pipBoundsState, PipBoundsHandler pipBoundsHandler, PipTaskOrganizer pipTaskOrganizer, + PipMediaController pipMediaController, WindowManagerShellWrapper windowManagerShellWrapper) { return Optional.of( new PipController( @@ -60,16 +60,15 @@ public abstract class TvPipModule { pipBoundsState, pipBoundsHandler, pipTaskOrganizer, + pipMediaController, windowManagerShellWrapper)); } @WMSingleton @Provides static PipControlsViewController providePipControlsViewController( - PipControlsView pipControlsView, PipController pipController, - LayoutInflater layoutInflater, Handler handler) { - return new PipControlsViewController(pipControlsView, pipController, layoutInflater, - handler); + PipControlsView pipControlsView, PipController pipController) { + return new PipControlsViewController(pipControlsView, pipController); } @WMSingleton diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java index 4330659dde02..f896891c5039 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java @@ -71,7 +71,7 @@ import com.android.wm.shell.onehanded.OneHandedEvents; import com.android.wm.shell.onehanded.OneHandedGestureHandler.OneHandedGestureEventCallback; import com.android.wm.shell.onehanded.OneHandedTransitionCallback; import com.android.wm.shell.pip.Pip; -import com.android.wm.shell.pip.phone.PipUtils; +import com.android.wm.shell.pip.PipUtils; import com.android.wm.shell.protolog.ShellProtoLogImpl; import com.android.wm.shell.splitscreen.SplitScreen; @@ -211,8 +211,7 @@ public final class WMShell extends SystemUI @Override public void onActivityUnpinned() { final Pair<ComponentName, Integer> topPipActivityInfo = - PipUtils.getTopPipActivity( - mContext, ActivityManager.getService()); + PipUtils.getTopPipActivity(mContext); final ComponentName topActivity = topPipActivityInfo.first; pip.onActivityUnpinned(topActivity); mInputConsumerController.unregisterInputConsumer(); diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java index ead2fc1cd9dc..91ae08e07677 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java @@ -34,6 +34,7 @@ import com.android.wm.shell.common.AnimationThread; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayImeController; import com.android.wm.shell.common.HandlerExecutor; +import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.common.SystemWindows; import com.android.wm.shell.common.TransactionPool; @@ -41,10 +42,10 @@ import com.android.wm.shell.draganddrop.DragAndDropController; import com.android.wm.shell.onehanded.OneHanded; import com.android.wm.shell.onehanded.OneHandedController; import com.android.wm.shell.pip.Pip; +import com.android.wm.shell.pip.PipMediaController; import com.android.wm.shell.pip.PipSurfaceTransactionHelper; import com.android.wm.shell.pip.PipUiEventLogger; import com.android.wm.shell.pip.phone.PipAppOpsListener; -import com.android.wm.shell.pip.phone.PipMediaController; import com.android.wm.shell.pip.phone.PipTouchHandler; import com.android.wm.shell.splitscreen.SplitScreen; @@ -102,8 +103,9 @@ public abstract class WMShellBaseModule { @WMSingleton @Provides - static DragAndDropController provideDragAndDropController(DisplayController displayController) { - return new DragAndDropController(displayController); + static DragAndDropController provideDragAndDropController(Context context, + DisplayController displayController) { + return new DragAndDropController(context, displayController); } @WMSingleton @@ -122,9 +124,8 @@ public abstract class WMShellBaseModule { @WMSingleton @Provides - static PipMediaController providePipMediaController(Context context, - IActivityManager activityManager) { - return new PipMediaController(context, activityManager); + static PipMediaController providePipMediaController(Context context) { + return new PipMediaController(context); } @WMSingleton @@ -157,9 +158,9 @@ public abstract class WMShellBaseModule { @WMSingleton @Provides static ShellTaskOrganizer provideShellTaskOrganizer(SyncTransactionQueue syncQueue, - @Main Handler handler, TransactionPool transactionPool) { + ShellExecutor mainExecutor, TransactionPool transactionPool) { return new ShellTaskOrganizer(syncQueue, transactionPool, - new HandlerExecutor(handler), AnimationThread.instance().getExecutor()); + mainExecutor, AnimationThread.instance().getExecutor()); } @BindsOptionalOf @@ -174,4 +175,11 @@ public abstract class WMShellBaseModule { DisplayController displayController) { return Optional.ofNullable(OneHandedController.create(context, displayController)); } + + @WMSingleton + @Provides + static ShellExecutor provideMainShellExecutor(@Main Handler handler) { + return new HandlerExecutor(handler); + } + } diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java index a6fe72850716..b6fbd589ae2c 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java @@ -27,18 +27,19 @@ import com.android.wm.shell.WindowManagerShellWrapper; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayImeController; import com.android.wm.shell.common.FloatingContentCoordinator; +import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.common.SystemWindows; import com.android.wm.shell.common.TransactionPool; import com.android.wm.shell.pip.Pip; import com.android.wm.shell.pip.PipBoundsHandler; import com.android.wm.shell.pip.PipBoundsState; +import com.android.wm.shell.pip.PipMediaController; import com.android.wm.shell.pip.PipSurfaceTransactionHelper; import com.android.wm.shell.pip.PipTaskOrganizer; import com.android.wm.shell.pip.PipUiEventLogger; import com.android.wm.shell.pip.phone.PipAppOpsListener; import com.android.wm.shell.pip.phone.PipController; -import com.android.wm.shell.pip.phone.PipMediaController; import com.android.wm.shell.pip.phone.PipMenuActivityController; import com.android.wm.shell.pip.phone.PipTouchHandler; import com.android.wm.shell.splitscreen.SplitScreen; @@ -82,11 +83,12 @@ public class WMShellModule { PipAppOpsListener pipAppOpsListener, PipBoundsHandler pipBoundsHandler, PipBoundsState pipBoundsState, PipMediaController pipMediaController, PipMenuActivityController pipMenuActivityController, PipTaskOrganizer pipTaskOrganizer, - PipTouchHandler pipTouchHandler, WindowManagerShellWrapper windowManagerShellWrapper) { + PipTouchHandler pipTouchHandler, WindowManagerShellWrapper windowManagerShellWrapper, + ShellExecutor mainExecutor) { return Optional.ofNullable(PipController.create(context, displayController, pipAppOpsListener, pipBoundsHandler, pipBoundsState, pipMediaController, pipMenuActivityController, pipTaskOrganizer, pipTouchHandler, - windowManagerShellWrapper)); + windowManagerShellWrapper, mainExecutor)); } @WMSingleton diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml index d541c8fbdff1..e5847b08a4c5 100644 --- a/packages/SystemUI/tests/AndroidManifest.xml +++ b/packages/SystemUI/tests/AndroidManifest.xml @@ -46,7 +46,7 @@ <uses-permission android:name="android.permission.DEVICE_POWER" /> <uses-permission android:name="android.permission.READ_CONTACTS" /> <uses-permission android:name="android.permission.STATUS_BAR" /> - <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" /> + <uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS" /> <uses-permission android:name="android.permission.REAL_GET_TASKS" /> <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW" /> <uses-permission android:name="android.permission.NETWORK_SETTINGS" /> diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java index 3da1f297dfe9..c923515fc8cc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java @@ -43,6 +43,7 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.content.pm.ActivityInfo; +import android.os.UserHandle; import android.provider.Settings; import android.testing.AndroidTestingRunner; import android.view.MotionEvent; @@ -186,8 +187,8 @@ public class MagnificationModeSwitchTest extends SysuiTestCase { // Perform dragging final View.OnTouchListener listener = mTouchListenerCaptor.getValue(); final int offset = ViewConfiguration.get(mContext).getScaledTouchSlop(); - final int previousMode = Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, 0); + final int previousMode = Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, 0, UserHandle.USER_CURRENT); listener.onTouch(mSpyImageView, MotionEvent.obtain( 0, 0, ACTION_DOWN, 100, 100, 0)); verify(mViewPropertyAnimator).cancel(); @@ -334,8 +335,8 @@ public class MagnificationModeSwitchTest extends SysuiTestCase { verify(mSpyImageView).setImageResource( getIconResId(expectedMode)); verify(mWindowManager).removeView(mSpyImageView); - final int actualMode = Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, 0); + final int actualMode = Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, 0, UserHandle.USER_CURRENT); assertEquals(expectedMode, actualMode); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java index b60fa4f7ea67..777db952591e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java @@ -32,10 +32,15 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.annotation.Nullable; import android.content.Context; import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.PromptInfo; +import android.hardware.biometrics.SensorProperties; +import android.hardware.face.FaceSensorPropertiesInternal; +import android.hardware.fingerprint.FingerprintSensorProperties; +import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.os.IBinder; import android.os.UserManager; import android.test.suitebuilder.annotation.SmallTest; @@ -58,6 +63,9 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.ArrayList; +import java.util.List; + @RunWith(AndroidTestingRunner.class) @RunWithLooper @SmallTest @@ -222,18 +230,28 @@ public class AuthContainerViewTest extends SysuiTestCase { AuthContainerView.Config config = new AuthContainerView.Config(); config.mContext = mContext; config.mCallback = mCallback; - config.mModalityMask |= BiometricAuthenticator.TYPE_FINGERPRINT; + config.mSensorIds = new int[] {0}; + config.mCredentialAllowed = false; PromptInfo promptInfo = new PromptInfo(); promptInfo.setAuthenticators(authenticators); config.mPromptInfo = promptInfo; - mAuthContainer = new TestableAuthContainer(config); + final List<FingerprintSensorPropertiesInternal> fpProps = new ArrayList<>(); + fpProps.add(new FingerprintSensorPropertiesInternal(0, + SensorProperties.STRENGTH_STRONG, + 5 /* maxEnrollmentsPerUser */, + FingerprintSensorProperties.TYPE_REAR, + false /* resetLockoutRequiresHardwareAuthToken */)); + mAuthContainer = new TestableAuthContainer(config, fpProps, null /* faceProps */); } private class TestableAuthContainer extends AuthContainerView { - TestableAuthContainer(AuthContainerView.Config config) { - super(config, new MockInjector()); + TestableAuthContainer(AuthContainerView.Config config, + @Nullable List<FingerprintSensorPropertiesInternal> fpProps, + @Nullable List<FaceSensorPropertiesInternal> faceProps) { + + super(config, new MockInjector(), fpProps, faceProps); } @Override diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java index e0420ca38f45..0186d7394ecb 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java @@ -97,6 +97,8 @@ public class AuthControllerTest extends SysuiTestCase { @Mock private FingerprintManager mFingerprintManager; @Mock + private FaceManager mFaceManager; + @Mock private UdfpsController mUdfpsController; private TestableAuthController mAuthController; @@ -132,7 +134,7 @@ public class AuthControllerTest extends SysuiTestCase { when(mFingerprintManager.getSensorPropertiesInternal()).thenReturn(props); mAuthController = new TestableAuthController(context, mCommandQueue, - mStatusBarStateController, mActivityTaskManager, mFingerprintManager, + mStatusBarStateController, mActivityTaskManager, mFingerprintManager, mFaceManager, () -> mUdfpsController); mAuthController.start(); @@ -142,7 +144,7 @@ public class AuthControllerTest extends SysuiTestCase { @Test public void testSendsReasonUserCanceled_whenDismissedByUserCancel() throws Exception { - showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE); + showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); mAuthController.onDismissed(AuthDialogCallback.DISMISSED_USER_CANCELED, null /* credentialAttestation */); verify(mReceiver).onDialogDismissed( @@ -152,7 +154,7 @@ public class AuthControllerTest extends SysuiTestCase { @Test public void testSendsReasonNegative_whenDismissedByButtonNegative() throws Exception { - showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE); + showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); mAuthController.onDismissed(AuthDialogCallback.DISMISSED_BUTTON_NEGATIVE, null /* credentialAttestation */); verify(mReceiver).onDialogDismissed( @@ -162,7 +164,7 @@ public class AuthControllerTest extends SysuiTestCase { @Test public void testSendsReasonConfirmed_whenDismissedByButtonPositive() throws Exception { - showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE); + showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); mAuthController.onDismissed(AuthDialogCallback.DISMISSED_BUTTON_POSITIVE, null /* credentialAttestation */); verify(mReceiver).onDialogDismissed( @@ -172,7 +174,7 @@ public class AuthControllerTest extends SysuiTestCase { @Test public void testSendsReasonConfirmNotRequired_whenDismissedByAuthenticated() throws Exception { - showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE); + showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); mAuthController.onDismissed(AuthDialogCallback.DISMISSED_BIOMETRIC_AUTHENTICATED, null /* credentialAttestation */); verify(mReceiver).onDialogDismissed( @@ -182,7 +184,7 @@ public class AuthControllerTest extends SysuiTestCase { @Test public void testSendsReasonError_whenDismissedByError() throws Exception { - showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE); + showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); mAuthController.onDismissed(AuthDialogCallback.DISMISSED_ERROR, null /* credentialAttestation */); verify(mReceiver).onDialogDismissed( @@ -192,7 +194,7 @@ public class AuthControllerTest extends SysuiTestCase { @Test public void testSendsReasonServerRequested_whenDismissedByServer() throws Exception { - showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE); + showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); mAuthController.onDismissed(AuthDialogCallback.DISMISSED_BY_SYSTEM_SERVER, null /* credentialAttestation */); verify(mReceiver).onDialogDismissed( @@ -203,7 +205,7 @@ public class AuthControllerTest extends SysuiTestCase { @Test public void testSendsReasonCredentialConfirmed_whenDeviceCredentialAuthenticated() throws Exception { - showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE); + showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); final byte[] credentialAttestation = generateRandomHAT(); @@ -217,22 +219,21 @@ public class AuthControllerTest extends SysuiTestCase { // Statusbar tests @Test - public void testShowInvoked_whenSystemRequested() - throws Exception { - showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE); + public void testShowInvoked_whenSystemRequested() { + showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); verify(mDialog1).show(any(), any()); } @Test public void testOnAuthenticationSucceededInvoked_whenSystemRequested() { - showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE); + showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); mAuthController.onBiometricAuthenticated(); verify(mDialog1).onAuthenticationSucceeded(); } @Test public void testOnAuthenticationFailedInvoked_whenBiometricRejected() { - showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE); + showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); mAuthController.onBiometricError(BiometricAuthenticator.TYPE_NONE, BiometricConstants.BIOMETRIC_PAUSED_REJECTED, 0 /* vendorCode */); @@ -245,7 +246,7 @@ public class AuthControllerTest extends SysuiTestCase { @Test public void testOnAuthenticationFailedInvoked_whenBiometricTimedOut() { - showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE); + showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); final int error = BiometricConstants.BIOMETRIC_ERROR_TIMEOUT; final int vendorCode = 0; mAuthController.onBiometricError(BiometricAuthenticator.TYPE_FACE, error, vendorCode); @@ -258,7 +259,7 @@ public class AuthControllerTest extends SysuiTestCase { @Test public void testOnHelpInvoked_whenSystemRequested() { - showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE); + showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); final String helpMessage = "help"; mAuthController.onBiometricHelp(helpMessage); @@ -269,8 +270,8 @@ public class AuthControllerTest extends SysuiTestCase { } @Test - public void testOnErrorInvoked_whenSystemRequested() throws Exception { - showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE); + public void testOnErrorInvoked_whenSystemRequested() { + showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); final int error = 1; final int vendorCode = 0; mAuthController.onBiometricError(BiometricAuthenticator.TYPE_FACE, error, vendorCode); @@ -283,7 +284,7 @@ public class AuthControllerTest extends SysuiTestCase { @Test public void testErrorLockout_whenCredentialAllowed_AnimatesToCredentialUI() { - showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE); + showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); final int error = BiometricConstants.BIOMETRIC_ERROR_LOCKOUT; final int vendorCode = 0; @@ -296,7 +297,7 @@ public class AuthControllerTest extends SysuiTestCase { @Test public void testErrorLockoutPermanent_whenCredentialAllowed_AnimatesToCredentialUI() { - showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE); + showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); final int error = BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT; final int vendorCode = 0; @@ -309,7 +310,7 @@ public class AuthControllerTest extends SysuiTestCase { @Test public void testErrorLockout_whenCredentialNotAllowed_sendsOnError() { - showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE); + showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); final int error = BiometricConstants.BIOMETRIC_ERROR_LOCKOUT; final int vendorCode = 0; @@ -322,7 +323,7 @@ public class AuthControllerTest extends SysuiTestCase { @Test public void testErrorLockoutPermanent_whenCredentialNotAllowed_sendsOnError() { - showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE); + showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); final int error = BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT; final int vendorCode = 0; @@ -335,7 +336,7 @@ public class AuthControllerTest extends SysuiTestCase { @Test public void testHideAuthenticationDialog_invokesDismissFromSystemServer() { - showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE); + showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); mAuthController.hideAuthenticationDialog(); verify(mDialog1).dismissFromSystemServer(); @@ -355,7 +356,7 @@ public class AuthControllerTest extends SysuiTestCase { // 1) Credential is confirmed // 2) Client cancels authentication - showDialog(Authenticators.DEVICE_CREDENTIAL, BiometricPrompt.TYPE_NONE); + showDialog(new int[0] /* sensorIds */, true /* credentialAllowed */); verify(mDialog1).show(any(), any()); final byte[] credentialAttestation = generateRandomHAT(); @@ -371,10 +372,10 @@ public class AuthControllerTest extends SysuiTestCase { @Test public void testShowNewDialog_beforeOldDialogDismissed_SkipsAnimations() { - showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE); + showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); verify(mDialog1).show(any(), any()); - showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE); + showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); // First dialog should be dismissed without animation verify(mDialog1).dismissWithoutCallback(eq(false) /* animate */); @@ -385,7 +386,7 @@ public class AuthControllerTest extends SysuiTestCase { @Test public void testConfigurationPersists_whenOnConfigurationChanged() { - showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE); + showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); verify(mDialog1).show(any(), any()); // Return that the UI is in "showing" state @@ -415,8 +416,7 @@ public class AuthControllerTest extends SysuiTestCase { @Test public void testConfigurationPersists_whenBiometricFallbackToCredential() { - showDialog(Authenticators.DEVICE_CREDENTIAL | Authenticators.BIOMETRIC_WEAK, - BiometricPrompt.TYPE_FACE); + showDialog(new int[] {1} /* sensorIds */, true /* credentialAllowed */); verify(mDialog1).show(any(), any()); // Pretend that the UI is now showing device credential UI. @@ -440,7 +440,7 @@ public class AuthControllerTest extends SysuiTestCase { @Test public void testClientNotified_whenTaskStackChangesDuringAuthentication() throws Exception { - showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE); + showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); List<ActivityManager.RunningTaskInfo> tasks = new ArrayList<>(); ActivityManager.RunningTaskInfo taskInfo = mock(ActivityManager.RunningTaskInfo.class); @@ -462,7 +462,7 @@ public class AuthControllerTest extends SysuiTestCase { @Test public void testDoesNotCrash_whenTryAgainPressedAfterDismissal() { - showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE); + showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); mAuthController.onDismissed(AuthDialogCallback.DISMISSED_USER_CANCELED, null /* credentialAttestation */); mAuthController.onTryAgainPressed(); @@ -470,7 +470,7 @@ public class AuthControllerTest extends SysuiTestCase { @Test public void testDoesNotCrash_whenDeviceCredentialPressedAfterDismissal() { - showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE); + showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); mAuthController.onDismissed(AuthDialogCallback.DISMISSED_USER_CANCELED, null /* credentialAttestation */); mAuthController.onDeviceCredentialPressed(); @@ -478,7 +478,7 @@ public class AuthControllerTest extends SysuiTestCase { @Test public void testActionCloseSystemDialogs_dismissesDialogIfShowing() throws Exception { - showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE); + showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); mAuthController.mBroadcastReceiver.onReceive(mContext, intent); waitForIdleSync(); @@ -500,14 +500,14 @@ public class AuthControllerTest extends SysuiTestCase { @Test public void testOnBiometricAuthenticated_OnCancelAodInterrupt() { - showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FINGERPRINT); + showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); mAuthController.onBiometricAuthenticated(); verify(mUdfpsController).onCancelAodInterrupt(); } @Test public void testOnBiometricError_OnCancelAodInterrupt() { - showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FINGERPRINT); + showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); mAuthController.onBiometricError(0, 0, 0); verify(mUdfpsController).onCancelAodInterrupt(); } @@ -538,17 +538,18 @@ public class AuthControllerTest extends SysuiTestCase { // Helpers - private void showDialog(int authenticators, int biometricModality) { - mAuthController.showAuthenticationDialog(createTestPromptInfo(authenticators), + private void showDialog(int[] sensorIds, boolean credentialAllowed) { + mAuthController.showAuthenticationDialog(createTestPromptInfo(), mReceiver /* receiver */, - biometricModality, + sensorIds, + credentialAllowed, true /* requireConfirmation */, 0 /* userId */, "testPackage", 0 /* operationId */); } - private PromptInfo createTestPromptInfo(int authenticators) { + private PromptInfo createTestPromptInfo() { PromptInfo promptInfo = new PromptInfo(); promptInfo.setTitle("Title"); @@ -560,8 +561,6 @@ public class AuthControllerTest extends SysuiTestCase { // by user settings, and should be tested in BiometricService. promptInfo.setConfirmationRequested(true); - promptInfo.setAuthenticators(authenticators); - return promptInfo; } @@ -580,15 +579,16 @@ public class AuthControllerTest extends SysuiTestCase { StatusBarStateController statusBarStateController, IActivityTaskManager activityTaskManager, FingerprintManager fingerprintManager, + FaceManager faceManager, Provider<UdfpsController> udfpsControllerFactory) { super(context, commandQueue, statusBarStateController, activityTaskManager, - fingerprintManager, udfpsControllerFactory); + fingerprintManager, faceManager, udfpsControllerFactory); } @Override protected AuthDialog buildDialog(PromptInfo promptInfo, - boolean requireConfirmation, int userId, int type, String opPackageName, - boolean skipIntro, long operationId) { + boolean requireConfirmation, int userId, int[] sensorIds, boolean credentialAllowed, + String opPackageName, boolean skipIntro, long operationId) { mLastBiometricPromptInfo = promptInfo; diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TaskViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TaskViewTest.java index b13c6fc0cad4..5c148598f10a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TaskViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TaskViewTest.java @@ -36,7 +36,6 @@ import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.PendingIntent; import android.content.Context; -import android.os.Handler; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.view.SurfaceControl; @@ -101,7 +100,8 @@ public class TaskViewTest extends SysuiTestCase { return null; }).when(mExecutor).execute(any()); - mTaskView = new TaskView(mContext, mOrganizer, mExecutor); + mTaskView = new TaskView(mContext, mOrganizer); + mTaskView.setExecutor(mExecutor); mTaskView.setListener(mViewListener); } @@ -114,7 +114,8 @@ public class TaskViewTest extends SysuiTestCase { @Test public void testSetPendingListener_throwsException() { - TaskView taskView = new TaskView(mContext, mOrganizer, mExecutor); + TaskView taskView = new TaskView(mContext, mOrganizer); + mTaskView.setExecutor(mExecutor); taskView.setListener(mViewListener); try { taskView.setListener(mViewListener); diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java index fd1866b9ebc3..c82aee48ab91 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java @@ -17,6 +17,7 @@ package com.android.systemui.qs; import static junit.framework.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -66,6 +67,7 @@ public class QSSecurityFooterTest extends SysuiTestCase { private final String DEVICE_OWNER_PACKAGE = "TestDPC"; private final String VPN_PACKAGE = "TestVPN"; private final String VPN_PACKAGE_2 = "TestVPN 2"; + private static final String PARENTAL_CONTROLS_LABEL = "Parental Control App"; private ViewGroup mRootView; private TextView mFooterText; @@ -525,6 +527,27 @@ public class QSSecurityFooterTest extends SysuiTestCase { verify(mockHost, never()).collapsePanels(); } + @Test + public void testParentalControls() { + when(mSecurityController.isParentalControlsEnabled()).thenReturn(true); + mFooter.refreshState(); + + TestableLooper.get(this).processAllMessages(); + + assertEquals(mContext.getString(R.string.quick_settings_disclosure_parental_controls), + mFooterText.getText()); + } + + @Test + public void testParentalControlsDialog() { + when(mSecurityController.isParentalControlsEnabled()).thenReturn(true); + when(mSecurityController.getLabel(any())).thenReturn(PARENTAL_CONTROLS_LABEL); + + View view = mFooter.createDialogView(); + TextView textView = (TextView) view.findViewById(R.id.parental_controls_title); + assertEquals(PARENTAL_CONTROLS_LABEL, textView.getText()); + } + private CharSequence addLink(CharSequence description) { final SpannableStringBuilder message = new SpannableStringBuilder(); message.append(description); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java index 8617a8326283..d2d57087485c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java @@ -26,6 +26,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; import android.content.ComponentName; import android.graphics.Rect; +import android.hardware.biometrics.IBiometricSysuiReceiver; import android.hardware.biometrics.PromptInfo; import android.os.Bundle; import android.view.WindowInsetsController.Appearance; @@ -409,13 +410,20 @@ public class CommandQueueTest extends SysuiTestCase { @Test public void testShowAuthenticationDialog() { PromptInfo promptInfo = new PromptInfo(); - String packageName = "test"; + final IBiometricSysuiReceiver receiver = mock(IBiometricSysuiReceiver.class); + final int[] sensorIds = {1, 2}; + final boolean credentialAllowed = true; + final boolean requireConfirmation = true; + final int userId = 10; + final String packageName = "test"; final long operationId = 1; - mCommandQueue.showAuthenticationDialog(promptInfo, null /* receiver */, 1, true, 3, - packageName, operationId); + + mCommandQueue.showAuthenticationDialog(promptInfo, receiver, sensorIds, + credentialAllowed, requireConfirmation , userId, packageName, operationId); waitForIdleSync(); - verify(mCallbacks).showAuthenticationDialog(eq(promptInfo), eq(null), eq(1), eq(true), - eq(3), eq(packageName), eq(operationId)); + verify(mCallbacks).showAuthenticationDialog(eq(promptInfo), eq(receiver), eq(sensorIds), + eq(credentialAllowed), eq(requireConfirmation), eq(userId), eq(packageName), + eq(operationId)); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeSecurityController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeSecurityController.java index e8911a2f5d4e..c0722a459929 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeSecurityController.java +++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeSecurityController.java @@ -14,6 +14,8 @@ package com.android.systemui.utils.leaks; +import android.app.admin.DeviceAdminInfo; +import android.graphics.drawable.Drawable; import android.testing.LeakCheck; import com.android.systemui.statusbar.policy.SecurityController; @@ -109,4 +111,24 @@ public class FakeSecurityController extends BaseLeakChecker<SecurityControllerCa public void onUserSwitched(int newUserId) { } + + @Override + public boolean isParentalControlsEnabled() { + return false; + } + + @Override + public DeviceAdminInfo getDeviceAdminInfo() { + return null; + } + + @Override + public Drawable getIcon(DeviceAdminInfo info) { + return null; + } + + @Override + public CharSequence getLabel(DeviceAdminInfo info) { + return null; + } } diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp index 613d28b20b8e..5526c657b874 100644 --- a/packages/Tethering/Android.bp +++ b/packages/Tethering/Android.bp @@ -37,7 +37,6 @@ java_defaults { libs: [ "framework-statsd.stubs.module_lib", "framework-tethering.impl", - "framework-telephony-stubs", "framework-wifi", "unsupportedappusage", ], diff --git a/packages/Tethering/tests/unit/Android.bp b/packages/Tethering/tests/unit/Android.bp index ef556cf92392..3589725dcf50 100644 --- a/packages/Tethering/tests/unit/Android.bp +++ b/packages/Tethering/tests/unit/Android.bp @@ -59,7 +59,6 @@ java_defaults { "ext", "framework-minus-apex", "framework-res", - "framework-telephony-stubs", "framework-tethering.impl", "framework-wifi.stubs.module_lib", ], diff --git a/packages/overlays/DisplayCutoutEmulationHoleOverlay/res/values-bn/strings.xml b/packages/overlays/DisplayCutoutEmulationHoleOverlay/res/values-bn/strings.xml deleted file mode 100644 index 3e9c962f8946..000000000000 --- a/packages/overlays/DisplayCutoutEmulationHoleOverlay/res/values-bn/strings.xml +++ /dev/null @@ -1,21 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (C) 2020 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="display_cutout_emulation_overlay" msgid="7305489596221077240">"পাঞ্চ হোল কাট-আউট"</string> -</resources> diff --git a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java index 92b8608f4f6c..bd26d44bed6f 100644 --- a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java +++ b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java @@ -25,6 +25,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.AppGlobals; +import android.content.ClipData; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -296,11 +297,29 @@ final class RemoteAugmentedAutofillService dataset.getId(), clientState); try { final ArrayList<AutofillId> fieldIds = dataset.getFieldIds(); - final int size = fieldIds.size(); - final boolean hideHighlight = size == 1 - && fieldIds.get(0).equals(focusedId); - client.autofill(sessionId, fieldIds, dataset.getFieldValues(), - hideHighlight); + final ClipData content = dataset.getFieldContent(); + if (content != null) { + final AutofillId fieldId = fieldIds.get(0); + if (sDebug) { + Slog.d(TAG, "Calling client autofillContent(): " + + "id=" + fieldId + ", content=" + content); + } + client.autofillContent(sessionId, fieldId, content); + } else { + final int size = fieldIds.size(); + final boolean hideHighlight = size == 1 + && fieldIds.get(0).equals(focusedId); + if (sDebug) { + Slog.d(TAG, "Calling client autofill(): " + + "ids=" + fieldIds + + ", values=" + dataset.getFieldValues()); + } + client.autofill( + sessionId, + fieldIds, + dataset.getFieldValues(), + hideHighlight); + } inlineSuggestionsCallback.apply( InlineFillUi.emptyUi(focusedId)); } catch (RemoteException e) { diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index f596b072d713..0302b2251f10 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -47,6 +47,7 @@ import android.app.IAssistDataReceiver; import android.app.assist.AssistStructure; import android.app.assist.AssistStructure.AutofillOverlay; import android.app.assist.AssistStructure.ViewNode; +import android.content.ClipData; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -1493,11 +1494,12 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState Slog.d(TAG, "Auth result for augmented autofill: sessionId=" + id + ", authId=" + authId + ", dataset=" + dataset); } - if (dataset == null - || dataset.getFieldIds().size() != 1 - || dataset.getFieldIds().get(0) == null - || dataset.getFieldValues().size() != 1 - || dataset.getFieldValues().get(0) == null) { + final AutofillId fieldId = (dataset != null && dataset.getFieldIds().size() == 1) + ? dataset.getFieldIds().get(0) : null; + final AutofillValue value = (dataset != null && dataset.getFieldValues().size() == 1) + ? dataset.getFieldValues().get(0) : null; + final ClipData content = (dataset != null) ? dataset.getFieldContent() : null; + if (fieldId == null || (value == null && content == null)) { if (sDebug) { Slog.d(TAG, "Rejecting empty/invalid auth result"); } @@ -1505,10 +1507,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState removeSelfLocked(); return; } - final List<AutofillId> fieldIds = dataset.getFieldIds(); - final List<AutofillValue> autofillValues = dataset.getFieldValues(); - final AutofillId fieldId = fieldIds.get(0); - final AutofillValue value = autofillValues.get(0); // Update state to ensure that after filling the field here we don't end up firing another // autofill request that will end up showing the same suggestions to the user again. When @@ -1524,13 +1522,18 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState // Fill the value into the field. if (sDebug) { - Slog.d(TAG, "Filling after auth: fieldId=" + fieldId + ", value=" + value); + Slog.d(TAG, "Filling after auth: fieldId=" + fieldId + ", value=" + value + + ", content=" + content); } try { - mClient.autofill(id, fieldIds, autofillValues, true); + if (content != null) { + mClient.autofillContent(id, fieldId, content); + } else { + mClient.autofill(id, dataset.getFieldIds(), dataset.getFieldValues(), true); + } } catch (RemoteException e) { Slog.w(TAG, "Error filling after auth: fieldId=" + fieldId + ", value=" + value - + ", error=" + e); + + ", content=" + content, e); } // Clear the suggestions since the user already accepted one of them. diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java index 032820dc97f8..e32324941aef 100644 --- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java +++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java @@ -309,6 +309,7 @@ public class CompanionDeviceManagerService extends SystemService implements Bind mFindDeviceCallback = callback; mRequest = request; mCallingPackage = callingPackage; + request.setCallingPackage(callingPackage); callback.asBinder().linkToDeath(CompanionDeviceManagerService.this /* recipient */, 0); final long callingIdentity = Binder.clearCallingIdentity(); diff --git a/services/core/java/android/content/pm/TestUtilityService.java b/services/core/java/android/content/pm/TestUtilityService.java new file mode 100644 index 000000000000..426352b250f8 --- /dev/null +++ b/services/core/java/android/content/pm/TestUtilityService.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm; + +import android.os.IBinder; + +/** + * Utility methods for testing and debugging. + */ +public interface TestUtilityService { + /** + * Verifies validity of the token passed as a parameter to holdLock(). Throws an exception if + * the token is invalid. + */ + void verifyHoldLockToken(IBinder token); +} diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 6e5c0412985c..4a338b37e41f 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -1970,7 +1970,7 @@ public final class ActiveServices { } if ((flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) { - mAm.enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS, + mAm.enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS, "BIND_TREAT_LIKE_ACTIVITY"); } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 51cbfcf64322..112814c69d9b 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -208,6 +208,7 @@ import android.content.pm.ProviderInfoList; import android.content.pm.ResolveInfo; import android.content.pm.SELinuxUtil; import android.content.pm.ServiceInfo; +import android.content.pm.TestUtilityService; import android.content.pm.UserInfo; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; @@ -339,6 +340,7 @@ import com.android.server.SystemServiceManager; import com.android.server.ThreadPriorityBooster; import com.android.server.UserspaceRebootLogger; import com.android.server.Watchdog; +import com.android.server.am.LowMemDetector.MemFactor; import com.android.server.appop.AppOpsService; import com.android.server.compat.PlatformCompat; import com.android.server.contentcapture.ContentCaptureManagerInternal; @@ -1311,6 +1313,7 @@ public class ActivityManagerService extends IActivityManager.Stub PackageManagerInternal mPackageManagerInt; PermissionManagerServiceInternal mPermissionManagerInt; + private TestUtilityService mTestUtilityService; /** * Whether to force background check on all apps (for battery saver) or not. @@ -5784,6 +5787,14 @@ public class ActivityManagerService extends IActivityManager.Stub return mPermissionManagerInt; } + private TestUtilityService getTestUtilityServiceLocked() { + if (mTestUtilityService == null) { + mTestUtilityService = + LocalServices.getService(TestUtilityService.class); + } + return mTestUtilityService; + } + @Override public void appNotResponding(final String reason) { final int callingPid = Binder.getCallingPid(); @@ -8214,13 +8225,25 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override - public int getMemoryTrimLevel() { + public @MemFactor int getMemoryTrimLevel() { enforceNotIsolatedCaller("getMyMemoryState"); synchronized (this) { return mAppProfiler.getLastMemoryLevelLocked(); } } + void setMemFactorOverride(@MemFactor int level) { + synchronized (this) { + if (level == mAppProfiler.getLastMemoryLevelLocked()) { + return; + } + + mAppProfiler.setMemFactorOverrideLocked(level); + // Kick off an oom adj update since we forced a mem factor update. + updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE); + } + } + @Override public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, @@ -17343,11 +17366,12 @@ public class ActivityManagerService extends IActivityManager.Stub /** * Holds the AM lock for the specified amount of milliseconds. * Intended for use by the tests that need to imitate lock contention. - * Requires permission identity of the shell UID. + * The token should be obtained by + * {@link android.content.pm.PackageManager#getHoldLockToken()}. */ @Override - public void holdLock(int durationMs) { - enforceCallingPermission(Manifest.permission.INJECT_EVENTS, "holdLock"); + public void holdLock(IBinder token, int durationMs) { + getTestUtilityServiceLocked().verifyHoldLockToken(token); synchronized (this) { SystemClock.sleep(durationMs); diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 31e7106979f1..e3c071fe10e2 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -25,6 +25,12 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.view.Display.INVALID_DISPLAY; +import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_CRITICAL; +import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_LOW; +import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_MODERATE; +import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_NORMAL; +import static com.android.server.am.LowMemDetector.ADJ_MEM_FACTOR_NOTHING; + import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.ActivityTaskManager; @@ -92,6 +98,7 @@ import android.view.Display; import com.android.internal.compat.CompatibilityChangeConfig; import com.android.internal.util.HexDump; import com.android.internal.util.MemInfoReader; +import com.android.server.am.LowMemDetector.MemFactor; import com.android.server.compat.PlatformCompat; import java.io.BufferedReader; @@ -309,6 +316,8 @@ final class ActivityManagerShellCommand extends ShellCommand { return runCompat(pw); case "refresh-settings-cache": return runRefreshSettingsCache(); + case "memory-factor": + return runMemoryFactor(pw); default: return handleDefaultCommands(cmd); } @@ -3014,6 +3023,81 @@ final class ActivityManagerShellCommand extends ShellCommand { return -1; } + private int runSetMemoryFactor(PrintWriter pw) throws RemoteException { + final String levelArg = getNextArgRequired(); + @MemFactor int level = ADJ_MEM_FACTOR_NOTHING; + switch (levelArg) { + case "NORMAL": + level = ADJ_MEM_FACTOR_NORMAL; + break; + case "MODERATE": + level = ADJ_MEM_FACTOR_MODERATE; + break; + case "LOW": + level = ADJ_MEM_FACTOR_LOW; + break; + case "CRITICAL": + level = ADJ_MEM_FACTOR_CRITICAL; + break; + default: + try { + level = Integer.parseInt(levelArg); + } catch (NumberFormatException e) { + } + if (level < ADJ_MEM_FACTOR_NORMAL || level > ADJ_MEM_FACTOR_CRITICAL) { + getErrPrintWriter().println("Error: Unknown level option: " + levelArg); + return -1; + } + } + mInternal.setMemFactorOverride(level); + return 0; + } + + private int runShowMemoryFactor(PrintWriter pw) throws RemoteException { + final @MemFactor int level = mInternal.getMemoryTrimLevel(); + switch (level) { + case ADJ_MEM_FACTOR_NOTHING: + pw.println("<UNKNOWN>"); + break; + case ADJ_MEM_FACTOR_NORMAL: + pw.println("NORMAL"); + break; + case ADJ_MEM_FACTOR_MODERATE: + pw.println("MODERATE"); + break; + case ADJ_MEM_FACTOR_LOW: + pw.println("LOW"); + break; + case ADJ_MEM_FACTOR_CRITICAL: + pw.println("CRITICAL"); + break; + } + pw.flush(); + return 0; + } + + private int runResetMemoryFactor(PrintWriter pw) throws RemoteException { + mInternal.setMemFactorOverride(ADJ_MEM_FACTOR_NOTHING); + return 0; + } + + private int runMemoryFactor(PrintWriter pw) throws RemoteException { + mInternal.enforceCallingPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS, + "runMemoryFactor()"); + + final String op = getNextArgRequired(); + switch (op) { + case "set": + return runSetMemoryFactor(pw); + case "show": + return runShowMemoryFactor(pw); + case "reset": + return runResetMemoryFactor(pw); + default: + getErrPrintWriter().println("Error: unknown command '" + op + "'"); + return -1; + } + } private Resources getResources(PrintWriter pw) throws RemoteException { // system resources does not contain all the device configuration, construct it manually. @@ -3334,6 +3418,13 @@ final class ActivityManagerShellCommand extends ShellCommand { pw.println(" Removes all existing overrides for all changes for "); pw.println(" <PACKAGE_NAME> (back to default behaviour)."); pw.println(" It kills <PACKAGE_NAME> (to allow the toggle to take effect)."); + pw.println(" memory-factor [command] [...]: sub-commands for overriding memory pressure factor"); + pw.println(" set <NORMAL|MODERATE|LOW|CRITICAL>"); + pw.println(" Overrides memory pressure factor. May also supply a raw int level"); + pw.println(" show"); + pw.println(" Shows the existing memory pressure factor"); + pw.println(" reset"); + pw.println(" Removes existing override for memory pressure factor"); pw.println(); Intent.printIntentArgsHelp(pw, ""); } diff --git a/services/core/java/com/android/server/am/AppProfiler.java b/services/core/java/com/android/server/am/AppProfiler.java index 31ffb35f24b3..5e59a35fc4ee 100644 --- a/services/core/java/com/android/server/am/AppProfiler.java +++ b/services/core/java/com/android/server/am/AppProfiler.java @@ -20,11 +20,16 @@ import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT; import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL; import static android.os.Process.FIRST_APPLICATION_UID; +import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_CRITICAL; +import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_LOW; +import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_MODERATE; +import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_NORMAL; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PSS; import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PSS; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.am.LowMemDetector.ADJ_MEM_FACTOR_NOTHING; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH; import android.annotation.BroadcastBehavior; @@ -72,6 +77,7 @@ import com.android.internal.os.ProcessCpuTracker; import com.android.internal.util.DumpUtils; import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.MemInfoReader; +import com.android.server.am.LowMemDetector.MemFactor; import com.android.server.am.ProcessList.ProcStateMemTracker; import com.android.server.utils.PriorityDump; @@ -202,7 +208,10 @@ public class AppProfiler { * processes are going away for other reasons. */ @GuardedBy("mService") - private int mLastMemoryLevel = ProcessStats.ADJ_MEM_FACTOR_NORMAL; + private @MemFactor int mLastMemoryLevel = ADJ_MEM_FACTOR_NORMAL; + + @GuardedBy("mService") + private @MemFactor int mMemFactorOverride = ADJ_MEM_FACTOR_NOTHING; /** * The last total number of process we have, to determine if changes actually look @@ -851,7 +860,7 @@ public class AppProfiler { @GuardedBy("mService") boolean isLastMemoryLevelNormal() { - return mLastMemoryLevel <= ProcessStats.ADJ_MEM_FACTOR_NORMAL; + return mLastMemoryLevel <= ADJ_MEM_FACTOR_NORMAL; } @GuardedBy("mService") @@ -868,6 +877,11 @@ public class AppProfiler { } @GuardedBy("mService") + void setMemFactorOverrideLocked(@MemFactor int factor) { + mMemFactorOverride = factor; + } + + @GuardedBy("mService") boolean updateLowMemStateLocked(int numCached, int numEmpty, int numTrimming) { final int numOfLru = mService.mProcessList.getLruSizeLocked(); final long now = SystemClock.uptimeMillis(); @@ -885,28 +899,32 @@ public class AppProfiler { && numEmpty <= mService.mConstants.CUR_TRIM_EMPTY_PROCESSES) { final int numCachedAndEmpty = numCached + numEmpty; if (numCachedAndEmpty <= ProcessList.TRIM_CRITICAL_THRESHOLD) { - memFactor = ProcessStats.ADJ_MEM_FACTOR_CRITICAL; + memFactor = ADJ_MEM_FACTOR_CRITICAL; } else if (numCachedAndEmpty <= ProcessList.TRIM_LOW_THRESHOLD) { - memFactor = ProcessStats.ADJ_MEM_FACTOR_LOW; + memFactor = ADJ_MEM_FACTOR_LOW; } else { - memFactor = ProcessStats.ADJ_MEM_FACTOR_MODERATE; + memFactor = ADJ_MEM_FACTOR_MODERATE; } } else { - memFactor = ProcessStats.ADJ_MEM_FACTOR_NORMAL; + memFactor = ADJ_MEM_FACTOR_NORMAL; } } // We always allow the memory level to go up (better). We only allow it to go // down if we are in a state where that is allowed, *and* the total number of processes // has gone down since last time. if (DEBUG_OOM_ADJ) { - Slog.d(TAG_OOM_ADJ, "oom: memFactor=" + memFactor + Slog.d(TAG_OOM_ADJ, "oom: memFactor=" + memFactor + " override=" + mMemFactorOverride + " last=" + mLastMemoryLevel + " allowLow=" + mAllowLowerMemLevel + " numProcs=" + mService.mProcessList.getLruSizeLocked() + " last=" + mLastNumProcesses); } + boolean override; + if (override = (mMemFactorOverride != ADJ_MEM_FACTOR_NOTHING)) { + memFactor = mMemFactorOverride; + } if (memFactor > mLastMemoryLevel) { - if (!mAllowLowerMemLevel - || mService.mProcessList.getLruSizeLocked() >= mLastNumProcesses) { + if (!override && (!mAllowLowerMemLevel + || mService.mProcessList.getLruSizeLocked() >= mLastNumProcesses)) { memFactor = mLastMemoryLevel; if (DEBUG_OOM_ADJ) Slog.d(TAG_OOM_ADJ, "Keeping last mem factor!"); } @@ -924,17 +942,17 @@ public class AppProfiler { mService.mAtmInternal == null || !mService.mAtmInternal.isSleeping(), now); trackerMemFactor = mService.mProcessStats.getMemFactorLocked(); } - if (memFactor != ProcessStats.ADJ_MEM_FACTOR_NORMAL) { + if (memFactor != ADJ_MEM_FACTOR_NORMAL) { if (mLowRamStartTime == 0) { mLowRamStartTime = now; } int step = 0; int fgTrimLevel; switch (memFactor) { - case ProcessStats.ADJ_MEM_FACTOR_CRITICAL: + case ADJ_MEM_FACTOR_CRITICAL: fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL; break; - case ProcessStats.ADJ_MEM_FACTOR_LOW: + case ADJ_MEM_FACTOR_LOW: fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW; break; default: @@ -947,7 +965,7 @@ public class AppProfiler { if (mService.mAtmInternal.getPreviousProcess() != null) minFactor++; if (factor < minFactor) factor = minFactor; int curLevel = ComponentCallbacks2.TRIM_MEMORY_COMPLETE; - for (int i = numOfLru - 1; i >= 0; i--) { + for (int i = 0; i < numOfLru; i++) { ProcessRecord app = mService.mProcessList.mLruProcesses.get(i); if (allChanged || app.procStateChanged) { mService.setProcessTrackerStateLocked(app, trackerMemFactor, now); @@ -1032,7 +1050,7 @@ public class AppProfiler { mLowRamTimeSinceLastIdle += now - mLowRamStartTime; mLowRamStartTime = 0; } - for (int i = numOfLru - 1; i >= 0; i--) { + for (int i = 0; i < numOfLru; i++) { ProcessRecord app = mService.mProcessList.mLruProcesses.get(i); if (allChanged || app.procStateChanged) { mService.setProcessTrackerStateLocked(app, trackerMemFactor, now); @@ -1622,16 +1640,16 @@ public class AppProfiler { @GuardedBy("mService") void dumpLastMemoryLevelLocked(PrintWriter pw) { switch (mLastMemoryLevel) { - case ProcessStats.ADJ_MEM_FACTOR_NORMAL: + case ADJ_MEM_FACTOR_NORMAL: pw.println("normal)"); break; - case ProcessStats.ADJ_MEM_FACTOR_MODERATE: + case ADJ_MEM_FACTOR_MODERATE: pw.println("moderate)"); break; - case ProcessStats.ADJ_MEM_FACTOR_LOW: + case ADJ_MEM_FACTOR_LOW: pw.println("low)"); break; - case ProcessStats.ADJ_MEM_FACTOR_CRITICAL: + case ADJ_MEM_FACTOR_CRITICAL: pw.println("critical)"); break; default: diff --git a/services/core/java/com/android/server/am/LowMemDetector.java b/services/core/java/com/android/server/am/LowMemDetector.java index e82a207cdd59..8f791331f0cf 100644 --- a/services/core/java/com/android/server/am/LowMemDetector.java +++ b/services/core/java/com/android/server/am/LowMemDetector.java @@ -16,8 +16,19 @@ package com.android.server.am; +import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_CRITICAL; +import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_LOW; +import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_MODERATE; +import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_NORMAL; +import static com.android.internal.app.procstats.ProcessStats.ADJ_NOTHING; + +import android.annotation.IntDef; + import com.android.internal.annotations.GuardedBy; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * Detects low memory using PSI. * @@ -32,13 +43,20 @@ public final class LowMemDetector { private final Object mPressureStateLock = new Object(); @GuardedBy("mPressureStateLock") - private int mPressureState = MEM_PRESSURE_NONE; + private int mPressureState = ADJ_MEM_FACTOR_NORMAL; + + public static final int ADJ_MEM_FACTOR_NOTHING = ADJ_NOTHING; /* getPressureState return values */ - public static final int MEM_PRESSURE_NONE = 0; - public static final int MEM_PRESSURE_LOW = 1; - public static final int MEM_PRESSURE_MEDIUM = 2; - public static final int MEM_PRESSURE_HIGH = 3; + @IntDef(prefix = { "ADJ_MEM_FACTOR_" }, value = { + ADJ_MEM_FACTOR_NOTHING, + ADJ_MEM_FACTOR_NORMAL, + ADJ_MEM_FACTOR_MODERATE, + ADJ_MEM_FACTOR_LOW, + ADJ_MEM_FACTOR_CRITICAL, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface MemFactor{} LowMemDetector(ActivityManagerService am) { mAm = am; @@ -62,7 +80,7 @@ public final class LowMemDetector { * there should be conversion performed here to translate pressure state * into memFactor. */ - public int getMemFactor() { + public @MemFactor int getMemFactor() { synchronized (mPressureStateLock) { return mPressureState; } diff --git a/services/core/java/com/android/server/biometrics/AuthSession.java b/services/core/java/com/android/server/biometrics/AuthSession.java index 15dc95673790..3c18cd4ed231 100644 --- a/services/core/java/com/android/server/biometrics/AuthSession.java +++ b/services/core/java/com/android/server/biometrics/AuthSession.java @@ -44,6 +44,8 @@ import com.android.internal.util.FrameworkStatsLog; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; +import java.util.List; import java.util.Random; /** @@ -241,7 +243,8 @@ public final class AuthSession implements IBinder.DeathRecipient { mStatusBarService.showAuthenticationDialog( mPromptInfo, mSysuiReceiver, - 0 /* biometricModality */, + new int[0] /* sensorIds */, + true /* credentialAllowed */, false /* requireConfirmation */, mUserId, mOpPackageName, @@ -271,11 +274,16 @@ public final class AuthSession implements IBinder.DeathRecipient { try { // If any sensor requires confirmation, request it to be shown. final boolean requireConfirmation = isConfirmationRequiredByAnyEligibleSensor(); - final @BiometricAuthenticator.Modality int modality = - getEligibleModalities(); + + final int[] sensorIds = new int[mPreAuthInfo.eligibleSensors.size()]; + for (int i = 0; i < mPreAuthInfo.eligibleSensors.size(); i++) { + sensorIds[i] = mPreAuthInfo.eligibleSensors.get(i).id; + } + mStatusBarService.showAuthenticationDialog(mPromptInfo, mSysuiReceiver, - modality, + sensorIds, + mPreAuthInfo.shouldShowCredential(), requireConfirmation, mUserId, mOpPackageName, @@ -369,7 +377,8 @@ public final class AuthSession implements IBinder.DeathRecipient { mStatusBarService.showAuthenticationDialog( mPromptInfo, mSysuiReceiver, - 0 /* biometricModality */, + new int[0] /* sensorIds */, + true /* credentialAllowed */, false /* requireConfirmation */, mUserId, mOpPackageName, diff --git a/services/core/java/com/android/server/biometrics/PreAuthInfo.java b/services/core/java/com/android/server/biometrics/PreAuthInfo.java index 08a617134221..6905b3da9bc4 100644 --- a/services/core/java/com/android/server/biometrics/PreAuthInfo.java +++ b/services/core/java/com/android/server/biometrics/PreAuthInfo.java @@ -32,7 +32,6 @@ import android.os.RemoteException; import android.util.Pair; import android.util.Slog; -import com.android.internal.annotations.VisibleForTesting; import com.android.server.biometrics.sensors.LockoutTracker; import java.lang.annotation.Retention; @@ -356,6 +355,13 @@ class PreAuthInfo { } /** + * @return true if SystemUI should show the credential UI. + */ + boolean shouldShowCredential() { + return credentialRequested && credentialAvailable; + } + + /** * @return bitmask representing the modalities that are running or could be running for the * current session. */ diff --git a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java index a0eafb4fc93f..b7e188c73eab 100644 --- a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java +++ b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java @@ -392,6 +392,7 @@ class RadioModule { } catch (RemoteException ex) { Slog.e(TAG, "Failed closing announcement listener", ex); } + hwCloseHandle.value = null; } }; } diff --git a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java index 7e3c1ab50ad5..fe6e60f6159c 100644 --- a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java +++ b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java @@ -17,18 +17,26 @@ package com.android.server.devicestate; import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE; +import static android.Manifest.permission.CONTROL_DEVICE_STATE; import android.annotation.NonNull; import android.content.Context; +import android.content.pm.PackageManager; import android.hardware.devicestate.IDeviceStateManager; +import android.os.Binder; +import android.os.ResultReceiver; +import android.os.ShellCallback; import android.util.IntArray; import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.DumpUtils; import com.android.server.SystemService; import com.android.server.policy.DeviceStatePolicyImpl; +import java.io.FileDescriptor; +import java.io.PrintWriter; import java.util.Arrays; /** @@ -65,15 +73,20 @@ public final class DeviceStateManagerService extends SystemService { // The current committed device state. @GuardedBy("mLock") private int mCommittedState = INVALID_DEVICE_STATE; - // The device state that is currently pending callback from the policy to be committed. + // The device state that is currently awaiting callback from the policy to be committed. @GuardedBy("mLock") private int mPendingState = INVALID_DEVICE_STATE; // Whether or not the policy is currently waiting to be notified of the current pending state. @GuardedBy("mLock") private boolean mIsPolicyWaitingForState = false; // The device state that is currently requested and is next to be configured and committed. + // Can be overwritten by an override state value if requested. @GuardedBy("mLock") private int mRequestedState = INVALID_DEVICE_STATE; + // The most recently requested override state, or INVALID_DEVICE_STATE if no override is + // requested. + @GuardedBy("mLock") + private int mRequestedOverrideState = INVALID_DEVICE_STATE; public DeviceStateManagerService(@NonNull Context context) { this(context, new DeviceStatePolicyImpl()); @@ -97,7 +110,6 @@ public final class DeviceStateManagerService extends SystemService { * * @see #getPendingState() */ - @VisibleForTesting int getCommittedState() { synchronized (mLock) { return mCommittedState; @@ -119,13 +131,61 @@ public final class DeviceStateManagerService extends SystemService { * Returns the requested state. The service will configure the device to match the requested * state when possible. */ - @VisibleForTesting int getRequestedState() { synchronized (mLock) { return mRequestedState; } } + /** + * Overrides the current device state with the provided state. + * + * @return {@code true} if the override state is valid and supported, {@code false} otherwise. + */ + boolean setOverrideState(int overrideState) { + if (getContext().checkCallingOrSelfPermission(CONTROL_DEVICE_STATE) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Must hold permission " + CONTROL_DEVICE_STATE); + } + + synchronized (mLock) { + if (overrideState != INVALID_DEVICE_STATE && !isSupportedStateLocked(overrideState)) { + return false; + } + + mRequestedOverrideState = overrideState; + updatePendingStateLocked(); + } + + notifyPolicyIfNeeded(); + return true; + } + + /** + * Clears an override state set with {@link #setOverrideState(int)}. + */ + void clearOverrideState() { + setOverrideState(INVALID_DEVICE_STATE); + } + + /** + * Returns the current requested override state, or {@link #INVALID_DEVICE_STATE} is no override + * state is requested. + */ + int getOverrideState() { + synchronized (mLock) { + return mRequestedOverrideState; + } + } + + /** Returns the list of currently supported device states. */ + int[] getSupportedStates() { + synchronized (mLock) { + // Copy array to prevent external modification of internal state. + return Arrays.copyOf(mSupportedDeviceStates.toArray(), mSupportedDeviceStates.size()); + } + } + private void updateSupportedStates(int[] supportedDeviceStates) { // Must ensure sorted as isSupportedStateLocked() impl uses binary search. Arrays.sort(supportedDeviceStates, 0, supportedDeviceStates.length); @@ -135,11 +195,20 @@ public final class DeviceStateManagerService extends SystemService { if (mRequestedState != INVALID_DEVICE_STATE && !isSupportedStateLocked(mRequestedState)) { // The current requested state is no longer valid. We'll clear it here, though - // we won't actually update the current state with a call to - // updatePendingStateLocked() as doing so will not have any effect. + // we won't actually update the current state until a callback comes from the + // provider with the most recent state. mRequestedState = INVALID_DEVICE_STATE; } + if (mRequestedOverrideState != INVALID_DEVICE_STATE + && !isSupportedStateLocked(mRequestedOverrideState)) { + // The current override state is no longer valid. We'll clear it here and update + // the committed state if necessary. + mRequestedOverrideState = INVALID_DEVICE_STATE; + } + updatePendingStateLocked(); } + + notifyPolicyIfNeeded(); } /** @@ -168,27 +237,34 @@ public final class DeviceStateManagerService extends SystemService { } /** - * Tries to update the current configuring state with the current requested state. Must call + * Tries to update the current pending state with the current requested state. Must call * {@link #notifyPolicyIfNeeded()} to actually notify the policy that the state is being * changed. */ private void updatePendingStateLocked() { - if (mRequestedState == INVALID_DEVICE_STATE) { - // No currently requested state. + if (mPendingState != INVALID_DEVICE_STATE) { + // Have pending state, can not configure a new state until the state is committed. return; } - if (mPendingState != INVALID_DEVICE_STATE) { - // Have pending state, can not configure a new state until the state is committed. + int stateToConfigure; + if (mRequestedOverrideState != INVALID_DEVICE_STATE) { + stateToConfigure = mRequestedOverrideState; + } else { + stateToConfigure = mRequestedState; + } + + if (stateToConfigure == INVALID_DEVICE_STATE) { + // No currently requested state. return; } - if (mRequestedState == mCommittedState) { - // No need to notify the policy as the committed state matches the requested state. + if (stateToConfigure == mCommittedState) { + // The state requesting to be committed already matches the current committed state. return; } - mPendingState = mRequestedState; + mPendingState = stateToConfigure; mIsPolicyWaitingForState = true; } @@ -246,6 +322,21 @@ public final class DeviceStateManagerService extends SystemService { notifyPolicyIfNeeded(); } + private void dumpInternal(PrintWriter pw) { + pw.println("DEVICE STATE MANAGER (dumpsys device_state)"); + + synchronized (mLock) { + pw.println(" mCommittedState=" + toString(mCommittedState)); + pw.println(" mPendingState=" + toString(mPendingState)); + pw.println(" mRequestedState=" + toString(mRequestedState)); + pw.println(" mRequestedOverrideState=" + toString(mRequestedOverrideState)); + } + } + + private String toString(int state) { + return state == INVALID_DEVICE_STATE ? "(none)" : String.valueOf(state); + } + private final class DeviceStateProviderListener implements DeviceStateProvider.Listener { @Override public void onSupportedDeviceStatesChanged(int[] newDeviceStates) { @@ -271,6 +362,23 @@ public final class DeviceStateManagerService extends SystemService { /** Implementation of {@link IDeviceStateManager} published as a binder service. */ private final class BinderService extends IDeviceStateManager.Stub { + @Override // Binder call + public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, + String[] args, ShellCallback callback, ResultReceiver result) { + new DeviceStateManagerShellCommand(DeviceStateManagerService.this) + .exec(this, in, out, err, args, callback, result); + } + @Override // Binder call + public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) { + if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return; + + final long token = Binder.clearCallingIdentity(); + try { + dumpInternal(pw); + } finally { + Binder.restoreCallingIdentity(token); + } + } } } diff --git a/services/core/java/com/android/server/devicestate/DeviceStateManagerShellCommand.java b/services/core/java/com/android/server/devicestate/DeviceStateManagerShellCommand.java new file mode 100644 index 000000000000..cf3b297545dc --- /dev/null +++ b/services/core/java/com/android/server/devicestate/DeviceStateManagerShellCommand.java @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.devicestate; + +import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE; + +import android.os.ShellCommand; + +import java.io.PrintWriter; + +/** + * ShellCommands for {@link DeviceStateManagerService}. + * + * Use with {@code adb shell cmd device_state ...}. + */ +public class DeviceStateManagerShellCommand extends ShellCommand { + private final DeviceStateManagerService mInternal; + + public DeviceStateManagerShellCommand(DeviceStateManagerService service) { + mInternal = service; + } + + @Override + public int onCommand(String cmd) { + if (cmd == null) { + return handleDefaultCommands(cmd); + } + final PrintWriter pw = getOutPrintWriter(); + + switch (cmd) { + case "state": + return runState(pw); + case "print-states": + return runPrintStates(pw); + default: + return handleDefaultCommands(cmd); + } + } + + private void printState(PrintWriter pw) { + int committedState = mInternal.getCommittedState(); + int requestedState = mInternal.getRequestedState(); + int requestedOverrideState = mInternal.getOverrideState(); + + if (committedState == INVALID_DEVICE_STATE) { + pw.println("Device state: (invalid)"); + } else { + pw.println("Device state: " + committedState); + } + + if (requestedOverrideState != INVALID_DEVICE_STATE) { + pw.println("----------------------"); + if (requestedState == INVALID_DEVICE_STATE) { + pw.println("Base state: (invalid)"); + } else { + pw.println("Base state: " + requestedState); + } + pw.println("Override state: " + committedState); + } + } + + private int runState(PrintWriter pw) { + final String nextArg = getNextArg(); + if (nextArg == null) { + printState(pw); + } else if ("reset".equals(nextArg)) { + mInternal.clearOverrideState(); + } else { + int requestedState; + try { + requestedState = Integer.parseInt(nextArg); + } catch (NumberFormatException e) { + getErrPrintWriter().println("Error: requested state should be an integer"); + return -1; + } + + boolean success = mInternal.setOverrideState(requestedState); + if (!success) { + getErrPrintWriter().println("Error: failed to set override state. Run:"); + getErrPrintWriter().println(""); + getErrPrintWriter().println(" print-states"); + getErrPrintWriter().println(""); + getErrPrintWriter().println("to get the list of currently supported device states"); + return -1; + } + } + return 0; + } + + private int runPrintStates(PrintWriter pw) { + int[] states = mInternal.getSupportedStates(); + pw.print("Supported states: [ "); + for (int i = 0; i < states.length; i++) { + pw.print(states[i]); + if (i < states.length - 1) { + pw.print(", "); + } + } + pw.println(" ]"); + return 0; + } + + @Override + public void onHelp() { + PrintWriter pw = getOutPrintWriter(); + pw.println("Device state manager (device_state) commands:"); + pw.println(" help"); + pw.println(" Print this help text."); + pw.println(" state [reset|OVERRIDE_DEVICE_STATE]"); + pw.println(" Return or override device state."); + pw.println(" print-states"); + pw.println(" Return list of currently supported device states."); + } +} diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java index d4377e4870a5..fe6500e8942c 100644 --- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java +++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java @@ -130,6 +130,14 @@ final class DisplayDeviceInfo { public static final int FLAG_TRUSTED = 1 << 13; /** + * Flag: Indicates that the display should not be a part of the default {@link DisplayGroup} and + * instead be part of a new {@link DisplayGroup}. + * + * @hide + */ + public static final int FLAG_OWN_DISPLAY_GROUP = 1 << 14; + + /** * Touch attachment: Display does not receive touch. */ public static final int TOUCH_NONE = 0; diff --git a/services/core/java/com/android/server/display/DisplayGroup.java b/services/core/java/com/android/server/display/DisplayGroup.java new file mode 100644 index 000000000000..f2413edd1a3a --- /dev/null +++ b/services/core/java/com/android/server/display/DisplayGroup.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.display; + +import java.util.ArrayList; +import java.util.List; + +/** + * Represents a collection of {@link LogicalDisplay}s which act in unison for certain behaviors and + * operations. + */ +public class DisplayGroup { + + final List<LogicalDisplay> mDisplays = new ArrayList<>(); + + void addDisplay(LogicalDisplay display) { + if (!mDisplays.contains(display)) { + mDisplays.add(display); + } + } + + boolean removeDisplay(LogicalDisplay display) { + return mDisplays.remove(display); + } +} diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 60c83905ed9c..c4dfcf5c3165 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -23,6 +23,7 @@ import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW; 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; +import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS; @@ -2024,6 +2025,9 @@ public final class DisplayManagerService extends SystemService { if ((flags & VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY) != 0) { flags &= ~VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR; } + if ((flags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) { + flags &= ~VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP; + } if (projection != null) { try { @@ -2062,6 +2066,14 @@ public final class DisplayManagerService extends SystemService { } } + if (callingUid != Process.SYSTEM_UID + && (flags & VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP) != 0) { + if (!checkCallingPermission(ADD_TRUSTED_DISPLAY, "createVirtualDisplay()")) { + throw new SecurityException("Requires ADD_TRUSTED_DISPLAY permission to " + + "create a virtual display which is not in the default DisplayGroup."); + } + } + if ((flags & VIRTUAL_DISPLAY_FLAG_TRUSTED) == 0) { flags &= ~VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS; } diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java index 6597aa54d66b..86691848c363 100644 --- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java +++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java @@ -300,10 +300,16 @@ final class LocalDisplayAdapter extends DisplayAdapter { } } - // Check whether surface flinger spontaneously changed modes out from under us. - // Schedule traversals to ensure that the correct state is reapplied if necessary. + boolean activeModeChanged = false; + + // Check whether SurfaceFlinger or the display device changed the active mode out from + // under us. if (mActiveModeId != NO_DISPLAY_MODE_ID && mActiveModeId != activeRecord.mMode.getModeId()) { + Slog.d(TAG, "The active mode was changed from SurfaceFlinger or the display" + + "device."); + mActiveModeId = activeRecord.mMode.getModeId(); + activeModeChanged = true; sendTraversalRequestLocked(); } @@ -333,7 +339,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { boolean recordsChanged = records.size() != mSupportedModes.size() || modesAdded; // If the records haven't changed then we're done here. if (!recordsChanged) { - return false; + return activeModeChanged; } mSupportedModes.clear(); diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java index a17a294cd1d7..e35becc93be0 100644 --- a/services/core/java/com/android/server/display/LogicalDisplay.java +++ b/services/core/java/com/android/server/display/LogicalDisplay.java @@ -280,6 +280,9 @@ final class LogicalDisplay { if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_TRUSTED) != 0) { mBaseDisplayInfo.flags |= Display.FLAG_TRUSTED; } + if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP) != 0) { + mBaseDisplayInfo.flags |= Display.FLAG_OWN_DISPLAY_GROUP; + } Rect maskingInsets = getMaskingInsets(deviceInfo); int maskedWidth = deviceInfo.width - maskingInsets.left - maskingInsets.right; int maskedHeight = deviceInfo.height - maskingInsets.top - maskingInsets.bottom; diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java index fc3ba35c52ba..a843af5982b4 100644 --- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java +++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java @@ -35,6 +35,9 @@ import java.util.function.Consumer; * Responsible for creating {@link LogicalDisplay}s and associating them to the * {@link DisplayDevice} objects supplied through {@link DisplayAdapter.Listener}. * + * Additionally this class will keep track of which {@link DisplayGroup} each + * {@link LogicalDisplay} belongs to. + * * For devices with a single internal display, the mapping is done once and left * alone. For devices with multiple built-in displays, such as foldable devices, * {@link LogicalDisplay}s can be remapped to different {@link DisplayDevice}s. @@ -91,6 +94,9 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { new SparseArray<LogicalDisplay>(); private int mNextNonDefaultDisplayId = Display.DEFAULT_DISPLAY + 1; + /** A mapping from logical display id to display group. */ + private final SparseArray<DisplayGroup> mDisplayGroups = new SparseArray<>(); + private final DisplayDeviceRepository mDisplayDeviceRepo; private final PersistentDataStore mPersistentDataStore; private final Listener mListener; @@ -296,6 +302,15 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { mLogicalDisplays.put(displayId, display); + final DisplayGroup displayGroup; + if (isDefault || (deviceInfo.flags & DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP) != 0) { + displayGroup = new DisplayGroup(); + } else { + displayGroup = mDisplayGroups.get(Display.DEFAULT_DISPLAY); + } + displayGroup.addDisplay(display); + mDisplayGroups.append(displayId, displayGroup); + mListener.onLogicalDisplayEventLocked(display, LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_ADDED); } @@ -314,10 +329,31 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { display.updateLocked(mDisplayDeviceRepo); if (!display.isValidLocked()) { mLogicalDisplays.removeAt(i); + mDisplayGroups.removeReturnOld(displayId).removeDisplay(display); mListener.onLogicalDisplayEventLocked(display, LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_REMOVED); } else if (!mTempDisplayInfo.equals(display.getDisplayInfoLocked())) { + final int flags = display.getDisplayInfoLocked().flags; + final DisplayGroup defaultDisplayGroup = mDisplayGroups.get( + Display.DEFAULT_DISPLAY); + if ((flags & Display.FLAG_OWN_DISPLAY_GROUP) != 0) { + // The display should have its own DisplayGroup. + if (defaultDisplayGroup.removeDisplay(display)) { + final DisplayGroup displayGroup = new DisplayGroup(); + displayGroup.addDisplay(display); + mDisplayGroups.append(display.getDisplayIdLocked(), displayGroup); + } + } else { + // The display should be a part of the default DisplayGroup. + final DisplayGroup displayGroup = mDisplayGroups.get(displayId); + if (displayGroup != defaultDisplayGroup) { + displayGroup.removeDisplay(display); + defaultDisplayGroup.addDisplay(display); + mDisplayGroups.put(displayId, defaultDisplayGroup); + } + } + final String oldUniqueId = mTempDisplayInfo.uniqueId; final String newUniqueId = display.getDisplayInfoLocked().uniqueId; final int eventMsg = TextUtils.equals(oldUniqueId, newUniqueId) diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java index 210d2979c807..ff4717b7131b 100644 --- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java +++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java @@ -19,6 +19,7 @@ package com.android.server.display; 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_DESTROY_CONTENT_ON_REMOVAL; +import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT; @@ -27,6 +28,7 @@ import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SHOUL import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED; +import static com.android.server.display.DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP; import static com.android.server.display.DisplayDeviceInfo.FLAG_TRUSTED; import android.content.Context; @@ -386,6 +388,10 @@ public class VirtualDisplayAdapter extends DisplayAdapter { mInfo.flags &= ~DisplayDeviceInfo.FLAG_NEVER_BLANK; } else { mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY; + + if ((mFlags & VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP) != 0) { + mInfo.flags |= FLAG_OWN_DISPLAY_GROUP; + } } if ((mFlags & VIRTUAL_DISPLAY_FLAG_SECURE) != 0) { diff --git a/services/core/java/com/android/server/hdmi/Constants.java b/services/core/java/com/android/server/hdmi/Constants.java index 425fbc5687ec..6ff661b1637e 100644 --- a/services/core/java/com/android/server/hdmi/Constants.java +++ b/services/core/java/com/android/server/hdmi/Constants.java @@ -492,6 +492,15 @@ final class Constants { static final int DISABLED = 0; static final int ENABLED = 1; + @IntDef({ + VERSION_1_4, + VERSION_2_0 + }) + @interface CecVersion {} + static final int VERSION_1_3 = 0x04; + static final int VERSION_1_4 = 0x05; + static final int VERSION_2_0 = 0x06; + private Constants() { /* cannot be instantiated */ } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java index 28bd97e4843c..d4593afe18fe 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java @@ -128,7 +128,7 @@ public class HdmiCecMessageValidator { FixedLengthValidator oneByteValidator = new FixedLengthValidator(1); addValidationInfo(Constants.MESSAGE_CEC_VERSION, oneByteValidator, DEST_DIRECT); addValidationInfo(Constants.MESSAGE_SET_MENU_LANGUAGE, - new FixedLengthValidator(3), DEST_BROADCAST); + new AsciiValidator(3), DEST_BROADCAST); // TODO: Handle messages for the Deck Control. @@ -148,8 +148,8 @@ public class HdmiCecMessageValidator { maxLengthValidator, DEST_ALL | SRC_UNREGISTERED); // Messages for the OSD. - addValidationInfo(Constants.MESSAGE_SET_OSD_STRING, maxLengthValidator, DEST_DIRECT); - addValidationInfo(Constants.MESSAGE_SET_OSD_NAME, maxLengthValidator, DEST_DIRECT); + addValidationInfo(Constants.MESSAGE_SET_OSD_STRING, new OsdStringValidator(), DEST_DIRECT); + addValidationInfo(Constants.MESSAGE_SET_OSD_NAME, new AsciiValidator(1, 14), DEST_DIRECT); // Messages for the Device Menu Control. addValidationInfo(Constants.MESSAGE_MENU_REQUEST, oneByteValidator, DEST_DIRECT); @@ -299,6 +299,37 @@ public class HdmiCecMessageValidator { return (value >= min && value <= max); } + /** + * Check if the given value is a valid Display Control. A valid value is one which falls within + * the range description defined in CEC 1.4 Specification : Operand Descriptions (Section 17) + * + * @param value Display Control + * @return true if the Display Control is valid + */ + private boolean isValidDisplayControl(int value) { + value = value & 0xFF; + return (value == 0x00 || value == 0x40 || value == 0x80 || value == 0xC0); + } + + /** + * Check if the given params has valid ASCII characters. + * A valid ASCII character is a printable character. It should fall within range description + * defined in CEC 1.4 Specification : Operand Descriptions (Section 17) + * + * @param params parameter consisting of string + * @param offset Start offset of string + * @param maxLength Maximum length of string to be evaluated + * @return true if the given type is valid + */ + private boolean isValidAsciiString(byte[] params, int offset, int maxLength) { + for (int i = offset; i < params.length && i < maxLength; i++) { + if (!isWithinRange(params[i], 0x20, 0x7E)) { + return false; + } + } + return true; + } + private class PhysicalAddressValidator implements ParameterValidator { @Override public int isValid(byte[] params) { @@ -359,4 +390,55 @@ public class HdmiCecMessageValidator { || params[0] == 0x1F); } } + + /** + * Check if the given parameters represents printable characters. + * A valid parameter should lie within the range description of ASCII defined in CEC 1.4 + * Specification : Operand Descriptions (Section 17) + */ + private class AsciiValidator implements ParameterValidator { + private final int mMinLength; + private final int mMaxLength; + + AsciiValidator(int length) { + mMinLength = length; + mMaxLength = length; + } + + AsciiValidator(int minLength, int maxLength) { + mMinLength = minLength; + mMaxLength = maxLength; + } + + @Override + public int isValid(byte[] params) { + // If the length is longer than expected, we assume it's OK since the parameter can be + // extended in the future version. + if (params.length < mMinLength) { + return ERROR_PARAMETER_SHORT; + } + return toErrorCode(isValidAsciiString(params, 0, mMaxLength)); + } + } + + /** + * Check if the given parameters is valid OSD String. + * A valid parameter should lie within the range description of ASCII defined in CEC 1.4 + * Specification : Operand Descriptions (Section 17) + */ + private class OsdStringValidator implements ParameterValidator { + @Override + public int isValid(byte[] params) { + // If the length is longer than expected, we assume it's OK since the parameter can be + // extended in the future version. + if (params.length < 2) { + return ERROR_PARAMETER_SHORT; + } + return toErrorCode( + // Display Control + isValidDisplayControl(params[0]) + // OSD String + && isValidAsciiString(params, 1, 14)); + } + } } diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index ee86593916ae..b4a765e10fca 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -26,6 +26,7 @@ import static com.android.server.hdmi.Constants.OPTION_MHL_ENABLE; import static com.android.server.hdmi.Constants.OPTION_MHL_INPUT_SWITCHING; import static com.android.server.hdmi.Constants.OPTION_MHL_POWER_CHARGE; import static com.android.server.hdmi.Constants.OPTION_MHL_SERVICE_CONTROL; +import static com.android.server.hdmi.Constants.VERSION_1_4; import static com.android.server.power.ShutdownThread.SHUTDOWN_ACTION_PROPERTY; import android.annotation.Nullable; @@ -79,6 +80,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.DumpUtils; import com.android.internal.util.IndentingPrintWriter; import com.android.server.SystemService; +import com.android.server.hdmi.Constants.CecVersion; import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly; import com.android.server.hdmi.HdmiCecController.AllocateAddressCallback; import com.android.server.hdmi.HdmiCecLocalDevice.ActiveSource; @@ -373,6 +375,9 @@ public class HdmiControlService extends SystemService { @Nullable private Looper mIoLooper; + @CecVersion + private int mCecVersion = Constants.VERSION_1_4; + // Last input port before switching to the MHL port. Should switch back to this port // when the mobile device sends the request one touch play with off. // Gets invalidated if we go to other port/input. @@ -660,6 +665,7 @@ public class HdmiControlService extends SystemService { String[] settings = new String[] { Global.HDMI_CONTROL_ENABLED, Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED, + Global.HDMI_CEC_VERSION, Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED, Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED, Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED, @@ -688,6 +694,9 @@ public class HdmiControlService extends SystemService { case Global.HDMI_CONTROL_ENABLED: setControlEnabled(enabled); break; + case Global.HDMI_CEC_VERSION: + initializeCec(INITIATED_BY_ENABLE_CEC); + break; case Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED: setHdmiCecVolumeControlEnabledInternal(enabled); break; @@ -753,6 +762,12 @@ public class HdmiControlService extends SystemService { return Global.getInt(cr, key, toInt(defVal)) == ENABLED; } + @VisibleForTesting + int readIntSetting(String key, int defVal) { + ContentResolver cr = getContext().getContentResolver(); + return Global.getInt(cr, key, defVal); + } + void writeBooleanSetting(String key, boolean value) { ContentResolver cr = getContext().getContentResolver(); Global.putInt(cr, key, toInt(value)); @@ -783,6 +798,8 @@ public class HdmiControlService extends SystemService { private void initializeCec(int initiatedBy) { mAddressAllocated = false; + mCecVersion = readIntSetting(Global.HDMI_CEC_VERSION, VERSION_1_4); + mCecController.setOption(OptionKey.SYSTEM_CEC_CONTROL, true); mCecController.setLanguage(mMenuLanguage); initializeLocalDevices(initiatedBy); @@ -989,8 +1006,9 @@ public class HdmiControlService extends SystemService { /** * Returns version of CEC. */ + @CecVersion int getCecVersion() { - return mCecController.getVersion(); + return mCecVersion; } /** @@ -2204,6 +2222,7 @@ public class HdmiControlService extends SystemService { if (!DumpUtils.checkDumpPermission(getContext(), TAG, writer)) return; final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); + pw.println("mCecVersion: " + mCecVersion); pw.println("mProhibitMode: " + mProhibitMode); pw.println("mPowerStatus: " + mPowerStatus); diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 9947ecd42e31..047f1742f2ca 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -119,6 +119,7 @@ import android.text.style.SuggestionSpan; import android.util.ArrayMap; import android.util.ArraySet; import android.util.EventLog; +import android.util.IndentingPrintWriter; import android.util.Log; import android.util.LruCache; import android.util.Pair; @@ -161,7 +162,6 @@ import com.android.internal.os.HandlerCaller; import com.android.internal.os.SomeArgs; import com.android.internal.os.TransferPipe; import com.android.internal.util.DumpUtils; -import com.android.internal.util.IndentingPrintWriter; import com.android.internal.view.IInlineSuggestionsRequestCallback; import com.android.internal.view.IInlineSuggestionsResponseCallback; import com.android.internal.view.IInputContext; diff --git a/services/core/java/com/android/server/notification/ZenLog.java b/services/core/java/com/android/server/notification/ZenLog.java index 8f05636eed9c..f5d648910d90 100644 --- a/services/core/java/com/android/server/notification/ZenLog.java +++ b/services/core/java/com/android/server/notification/ZenLog.java @@ -39,7 +39,7 @@ public class ZenLog { // the ZenLog is *very* verbose, so be careful about setting this to true private static final boolean DEBUG = false; - private static final int SIZE = Build.IS_DEBUGGABLE ? 100 : 20; + private static final int SIZE = Build.IS_DEBUGGABLE ? 200 : 100; private static final long[] TIMES = new long[SIZE]; private static final int[] TYPES = new int[SIZE]; @@ -136,9 +136,14 @@ public class ZenLog { public static void traceConfig(String reason, ZenModeConfig oldConfig, ZenModeConfig newConfig) { - append(TYPE_CONFIG, reason - + "," + (newConfig != null ? newConfig.toString() : null) - + "," + ZenModeConfig.diff(oldConfig, newConfig)); + ZenModeConfig.Diff diff = ZenModeConfig.diff(oldConfig, newConfig); + if (diff.isEmpty()) { + append(TYPE_CONFIG, reason + " no changes"); + } else { + append(TYPE_CONFIG, reason + + ",\n" + (newConfig != null ? newConfig.toString() : null) + + ",\n" + ZenModeConfig.diff(oldConfig, newConfig)); + } } public static void traceDisableEffects(NotificationRecord record, String reason) { diff --git a/services/core/java/com/android/server/notification/ZenModeConditions.java b/services/core/java/com/android/server/notification/ZenModeConditions.java index 571f79915484..50b4d438984c 100644 --- a/services/core/java/com/android/server/notification/ZenModeConditions.java +++ b/services/core/java/com/android/server/notification/ZenModeConditions.java @@ -108,7 +108,7 @@ public class ZenModeConditions implements ConditionProviders.Callback { @Override public void onServiceAdded(ComponentName component) { if (DEBUG) Log.d(TAG, "onServiceAdded " + component); - mHelper.setConfig(mHelper.getConfig(), component, "zmc.onServiceAdded"); + mHelper.setConfig(mHelper.getConfig(), component, "zmc.onServiceAdded:" + component); } @Override diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java index 8eebf2a8d9d9..b679c0fbab83 100644 --- a/services/core/java/com/android/server/pm/LauncherAppsService.java +++ b/services/core/java/com/android/server/pm/LauncherAppsService.java @@ -16,6 +16,7 @@ package com.android.server.pm; +import static android.app.PendingIntent.FLAG_IMMUTABLE; import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK; import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT; import static android.content.pm.LauncherApps.FLAG_CACHE_BUBBLE_SHORTCUTS; @@ -32,6 +33,7 @@ import android.app.IApplicationThread; import android.app.PendingIntent; import android.app.admin.DevicePolicyManager; import android.app.usage.UsageStatsManagerInternal; +import android.content.ActivityNotFoundException; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -1018,6 +1020,32 @@ public class LauncherAppsService extends SystemService { } @Override + public PendingIntent getActivityLaunchIntent(ComponentName component, Bundle opts, + UserHandle user) { + if (!canAccessProfile(user.getIdentifier(), "Cannot start activity")) { + throw new ActivityNotFoundException("Activity could not be found"); + } + + final Intent launchIntent = getMainActivityLaunchIntent(component, user); + if (launchIntent == null) { + throw new SecurityException("Attempt to launch activity without " + + " category Intent.CATEGORY_LAUNCHER " + component); + } + + final long ident = Binder.clearCallingIdentity(); + try { + // If we reach here, we've verified that the caller has access to the profile and + // is launching an exported activity with CATEGORY_LAUNCHER so we can clear the + // calling identity to mirror the startActivityAsUser() call which does not validate + // the calling user + return PendingIntent.getActivityAsUser(mContext, 0 /* requestCode */, launchIntent, + FLAG_IMMUTABLE, opts, user); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @Override public void startActivityAsUser(IApplicationThread caller, String callingPackage, String callingFeatureId, ComponentName component, Rect sourceBounds, Bundle opts, UserHandle user) throws RemoteException { @@ -1025,9 +1053,24 @@ public class LauncherAppsService extends SystemService { return; } + Intent launchIntent = getMainActivityLaunchIntent(component, user); + if (launchIntent == null) { + throw new SecurityException("Attempt to launch activity without " + + " category Intent.CATEGORY_LAUNCHER " + component); + } + launchIntent.setSourceBounds(sourceBounds); + + mActivityTaskManagerInternal.startActivityAsUser(caller, callingPackage, + callingFeatureId, launchIntent, /* resultTo= */ null, + Intent.FLAG_ACTIVITY_NEW_TASK, opts, user.getIdentifier()); + } + + /** + * Returns the main activity launch intent for the given component package. + */ + private Intent getMainActivityLaunchIntent(ComponentName component, UserHandle user) { Intent launchIntent = new Intent(Intent.ACTION_MAIN); launchIntent.addCategory(Intent.CATEGORY_LAUNCHER); - launchIntent.setSourceBounds(sourceBounds); launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); launchIntent.setPackage(component.getPackageName()); @@ -1066,15 +1109,12 @@ public class LauncherAppsService extends SystemService { } } if (!canLaunch) { - throw new SecurityException("Attempt to launch activity without " - + " category Intent.CATEGORY_LAUNCHER " + component); + return null; } } finally { Binder.restoreCallingIdentity(ident); } - mActivityTaskManagerInternal.startActivityAsUser(caller, callingPackage, - callingFeatureId, launchIntent, /* resultTo= */ null, - Intent.FLAG_ACTIVITY_NEW_TASK, opts, user.getIdentifier()); + return launchIntent; } @Override diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 1896c9f08f83..652960c0f45a 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -222,6 +222,7 @@ import android.content.pm.SharedLibraryInfo; import android.content.pm.Signature; import android.content.pm.SigningInfo; import android.content.pm.SuspendDialogInfo; +import android.content.pm.TestUtilityService; import android.content.pm.UserInfo; import android.content.pm.VerifierDeviceIdentity; import android.content.pm.VerifierInfo; @@ -480,7 +481,7 @@ import java.util.function.Supplier; * </pre> */ public class PackageManagerService extends IPackageManager.Stub - implements PackageSender { + implements PackageSender, TestUtilityService { static final String TAG = "PackageManager"; public static final boolean DEBUG_SETTINGS = false; static final boolean DEBUG_PREFERRED = false; @@ -820,6 +821,7 @@ public class PackageManagerService extends IPackageManager.Stub boolean mPromoteSystemApps; private final PackageManagerInternal mPmInternal; + private final TestUtilityService mTestUtilityService; @GuardedBy("mLock") @@ -1193,6 +1195,7 @@ public class PackageManagerService extends IPackageManager.Stub public IPermissionManager permissionManagerService; public PendingPackageBroadcasts pendingPackageBroadcasts; public PackageManagerInternal pmInternal; + public TestUtilityService testUtilityService; public ProcessLoggingHandler processLoggingHandler; public ProtectedPackages protectedPackages; public @NonNull String requiredInstallerPackage; @@ -2957,6 +2960,7 @@ public class PackageManagerService extends IPackageManager.Stub mPendingBroadcasts = testParams.pendingPackageBroadcasts; mPermissionManagerService = testParams.permissionManagerService; mPmInternal = testParams.pmInternal; + mTestUtilityService = testParams.testUtilityService; mProcessLoggingHandler = testParams.processLoggingHandler; mProtectedPackages = testParams.protectedPackages; mSeparateProcesses = testParams.separateProcesses; @@ -3027,6 +3031,8 @@ public class PackageManagerService extends IPackageManager.Stub // Expose private service for system components to use. mPmInternal = new PackageManagerInternalImpl(); + LocalServices.addService(TestUtilityService.class, this); + mTestUtilityService = LocalServices.getService(TestUtilityService.class); LocalServices.addService(PackageManagerInternal.class, mPmInternal); mUserManager = injector.getUserManagerService(); mComponentResolver = injector.getComponentResolver(); @@ -13320,13 +13326,21 @@ public class PackageManagerService extends IPackageManager.Stub @Override public void setSystemAppHiddenUntilInstalled(String packageName, boolean hidden) { final int callingUid = Binder.getCallingUid(); - PackageManagerServiceUtils - .enforceSystemOrPhoneCaller("setSystemAppHiddenUntilInstalled", callingUid); + final boolean calledFromSystemOrPhone = callingUid == Process.PHONE_UID + || callingUid == Process.SYSTEM_UID; + if (!calledFromSystemOrPhone) { + mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS, + "setSystemAppHiddenUntilInstalled"); + } + synchronized (mLock) { final PackageSetting pkgSetting = mSettings.mPackages.get(packageName); if (pkgSetting == null || !pkgSetting.isSystem()) { return; } + if (pkgSetting.getPkg().isCoreApp() && !calledFromSystemOrPhone) { + throw new SecurityException("Only system or phone callers can modify core apps"); + } pkgSetting.getPkgState().setHiddenUntilInstalled(hidden); final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(packageName); if (disabledPs == null) { @@ -13339,14 +13353,22 @@ public class PackageManagerService extends IPackageManager.Stub @Override public boolean setSystemAppInstallState(String packageName, boolean installed, int userId) { final int callingUid = Binder.getCallingUid(); - PackageManagerServiceUtils - .enforceSystemOrPhoneCaller("setSystemAppInstallState", callingUid); + final boolean calledFromSystemOrPhone = callingUid == Process.PHONE_UID + || callingUid == Process.SYSTEM_UID; + if (!calledFromSystemOrPhone) { + mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS, + "setSystemAppHiddenUntilInstalled"); + } + synchronized (mLock) { final PackageSetting pkgSetting = mSettings.mPackages.get(packageName); // The target app should always be in system if (pkgSetting == null || !pkgSetting.isSystem()) { return false; } + if (pkgSetting.getPkg().isCoreApp() && !calledFromSystemOrPhone) { + throw new SecurityException("Only system or phone callers can modify core apps"); + } // Check if the install state is the same if (pkgSetting.getInstalled(userId) == installed) { return false; @@ -26366,9 +26388,39 @@ public class PackageManagerService extends IPackageManager.Stub } @Override - public void holdLock(int durationMs) { + public IBinder getHoldLockToken() { + if (!Build.IS_DEBUGGABLE) { + throw new SecurityException("getHoldLockToken requires a debuggable build"); + } + mContext.enforceCallingPermission( - Manifest.permission.INJECT_EVENTS, "holdLock requires shell identity"); + Manifest.permission.INJECT_EVENTS, + "getHoldLockToken requires INJECT_EVENTS permission"); + + final Binder token = new Binder(); + token.attachInterface(this, "holdLock:" + Binder.getCallingUid()); + return token; + } + + @Override + public void verifyHoldLockToken(IBinder token) { + if (!Build.IS_DEBUGGABLE) { + throw new SecurityException("holdLock requires a debuggable build"); + } + + if (token == null) { + throw new SecurityException("null holdLockToken"); + } + + if (token.queryLocalInterface("holdLock:" + Binder.getCallingUid()) != this) { + throw new SecurityException("Invalid holdLock() token"); + } + } + + @Override + public void holdLock(IBinder token, int durationMs) { + mTestUtilityService.verifyHoldLockToken(token); + synchronized (mLock) { SystemClock.sleep(durationMs); } diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java index 3bad3cb1d372..8dbd46482ae2 100644 --- a/services/core/java/com/android/server/pm/StagingManager.java +++ b/services/core/java/com/android/server/pm/StagingManager.java @@ -1059,19 +1059,26 @@ public class StagingManager { onPreRebootVerificationComplete(session); return; } - switch (msg.what) { - case MSG_PRE_REBOOT_VERIFICATION_START: - handlePreRebootVerification_Start(session); - break; - case MSG_PRE_REBOOT_VERIFICATION_APEX: - handlePreRebootVerification_Apex(session, rollbackId); - break; - case MSG_PRE_REBOOT_VERIFICATION_APK: - handlePreRebootVerification_Apk(session); - break; - case MSG_PRE_REBOOT_VERIFICATION_END: - handlePreRebootVerification_End(session); - break; + try { + switch (msg.what) { + case MSG_PRE_REBOOT_VERIFICATION_START: + handlePreRebootVerification_Start(session); + break; + case MSG_PRE_REBOOT_VERIFICATION_APEX: + handlePreRebootVerification_Apex(session, rollbackId); + break; + case MSG_PRE_REBOOT_VERIFICATION_APK: + handlePreRebootVerification_Apk(session); + break; + case MSG_PRE_REBOOT_VERIFICATION_END: + handlePreRebootVerification_End(session); + break; + } + } catch (Exception e) { + Slog.e(TAG, "Pre-reboot verification failed due to unhandled exception", e); + onPreRebootVerificationFailure(session, + SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, + "Pre-reboot verification failed due to unhandled exception: " + e); } } diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index a0344e27f96c..7f29cd94bfca 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -4458,7 +4458,7 @@ public class UserManagerService extends IUserManager.Stub { } } if (userInfo == null) { - throw new SecurityException("userId can only be the calling user or a managed " + throw new SecurityException("userId can only be the calling user or a " + "profile associated with this user"); } return userInfo.creationTime; diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index 55cb7f32e1b7..fb47ebbcaa07 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -706,12 +706,12 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D @Override public void showAuthenticationDialog(PromptInfo promptInfo, IBiometricSysuiReceiver receiver, - @BiometricAuthenticator.Modality int biometricModality, boolean requireConfirmation, + int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation, int userId, String opPackageName, long operationId) { enforceBiometricDialog(); if (mBar != null) { try { - mBar.showAuthenticationDialog(promptInfo, receiver, biometricModality, + mBar.showAuthenticationDialog(promptInfo, receiver, sensorIds, credentialAllowed, requireConfirmation, userId, opPackageName, operationId); } catch (RemoteException ex) { } diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 910a1a2c69b2..25b2523b1a3e 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -1195,7 +1195,12 @@ class ActivityStarter { } } - mService.onStartActivitySetDidAppSwitch(); + // Only allow app switching to be resumed if activity is not a restricted background + // activity, otherwise any background activity started in background task can stop + // home button protection mode. + if (!restrictedBgActivity) { + mService.onStartActivitySetDidAppSwitch(); + } mController.doPendingActivityLaunches(false); mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession, @@ -1260,6 +1265,20 @@ class ActivityStarter { return false; } + // Always allow home application to start activities. + if (mService.mHomeProcess != null && callingUid == mService.mHomeProcess.mUid) { + if (DEBUG_ACTIVITY_STARTS) { + Slog.d(TAG, "Activity start allowed for home app callingUid (" + callingUid + ")"); + } + return false; + } + + // App switching will be allowed if BAL app switching flag is not enabled, or if + // its app switching rule allows it. + // This is used to block background activity launch even if the app is still + // visible to user after user clicking home button. + final boolean appSwitchAllowed = mService.getBalAppSwitchesAllowed(); + // don't abort if the callingUid has a visible window or is a persistent system process final int callingUidProcState = mService.getUidState(callingUid); final boolean callingUidHasAnyVisibleWindow = @@ -1269,7 +1288,8 @@ class ActivityStarter { || callingUidProcState == ActivityManager.PROCESS_STATE_BOUND_TOP; final boolean isCallingUidPersistentSystemProcess = callingUidProcState <= ActivityManager.PROCESS_STATE_PERSISTENT_UI; - if (callingUidHasAnyVisibleWindow || isCallingUidPersistentSystemProcess) { + if ((appSwitchAllowed && callingUidHasAnyVisibleWindow) + || isCallingUidPersistentSystemProcess) { if (DEBUG_ACTIVITY_STARTS) { Slog.d(TAG, "Activity start allowed: callingUidHasAnyVisibleWindow = " + callingUid + ", isCallingUidPersistentSystemProcess = " @@ -1295,6 +1315,7 @@ class ActivityStarter { || realCallingUidProcState <= ActivityManager.PROCESS_STATE_PERSISTENT_UI; if (realCallingUid != callingUid) { // don't abort if the realCallingUid has a visible window + // TODO(b/171459802): We should check appSwitchAllowed also if (realCallingUidHasAnyVisibleWindow) { if (DEBUG_ACTIVITY_STARTS) { Slog.d(TAG, "Activity start allowed: realCallingUid (" + realCallingUid @@ -1376,7 +1397,7 @@ class ActivityStarter { // don't abort if the callerApp or other processes of that uid are allowed in any way if (callerApp != null) { // first check the original calling process - if (callerApp.areBackgroundActivityStartsAllowed()) { + if (callerApp.areBackgroundActivityStartsAllowed(appSwitchAllowed)) { if (DEBUG_ACTIVITY_STARTS) { Slog.d(TAG, "Background activity start allowed: callerApp process (pid = " + callerApp.getPid() + ", uid = " + callerAppUid + ") is allowed"); @@ -1389,7 +1410,8 @@ class ActivityStarter { if (uidProcesses != null) { for (int i = uidProcesses.size() - 1; i >= 0; i--) { final WindowProcessController proc = uidProcesses.valueAt(i); - if (proc != callerApp && proc.areBackgroundActivityStartsAllowed()) { + if (proc != callerApp + && proc.areBackgroundActivityStartsAllowed(appSwitchAllowed)) { if (DEBUG_ACTIVITY_STARTS) { Slog.d(TAG, "Background activity start allowed: process " + proc.getPid() diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index c582e6c8cb29..61b672d6777c 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -23,6 +23,7 @@ import static android.Manifest.permission.INTERACT_ACROSS_USERS; import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW; import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS; +import static android.Manifest.permission.MANAGE_ACTIVITY_TASKS; import static android.Manifest.permission.READ_FRAME_BUFFER; import static android.Manifest.permission.REMOVE_TASKS; import static android.Manifest.permission.START_TASKS_FROM_RECENTS; @@ -160,9 +161,11 @@ import android.app.WindowConfiguration; import android.app.admin.DevicePolicyCache; import android.app.assist.AssistContent; import android.app.assist.AssistStructure; +import android.app.compat.CompatChanges; import android.app.servertransaction.ClientTransaction; import android.app.servertransaction.EnterPipRequestedItem; import android.app.usage.UsageStatsManagerInternal; +import android.compat.annotation.ChangeId; import android.content.ActivityNotFoundException; import android.content.ComponentName; import android.content.ContentResolver; @@ -341,6 +344,12 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { /** This activity is being relaunched due to a free-resize operation. */ public static final int RELAUNCH_REASON_FREE_RESIZE = 2; + /** + * Apps are blocked from starting activities in the foreground after the user presses home. + */ + @ChangeId + public static final long BLOCK_ACTIVITY_STARTS_AFTER_HOME = 159433730L; + Context mContext; /** @@ -1596,7 +1605,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public void startRecentsActivity(Intent intent, long eventTime, @Nullable IRecentsAnimationRunner recentsAnimationRunner) { - enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "startRecentsActivity()"); + enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_TASKS, "startRecentsActivity()"); final int callingPid = Binder.getCallingPid(); final int callingUid = Binder.getCallingUid(); final long origId = Binder.clearCallingIdentity(); @@ -2182,7 +2191,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public RootTaskInfo getFocusedRootTaskInfo() throws RemoteException { - enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "getFocusedRootTaskInfo()"); + enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_TASKS, "getFocusedRootTaskInfo()"); final long ident = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { @@ -2199,7 +2208,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public void setFocusedRootTask(int taskId) { - mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "setFocusedRootTask()"); + enforceTaskPermission("setFocusedRootTask()"); ProtoLog.d(WM_DEBUG_FOCUS, "setFocusedRootTask: taskId=%d", taskId); final long callingId = Binder.clearCallingIdentity(); try { @@ -2221,7 +2230,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public void setFocusedTask(int taskId) { - mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "setFocusedTask()"); + enforceTaskPermission("setFocusedTask()"); ProtoLog.d(WM_DEBUG_FOCUS, "setFocusedTask: taskId=%d", taskId); final long callingId = Binder.clearCallingIdentity(); try { @@ -2243,7 +2252,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public void restartActivityProcessIfVisible(IBinder activityToken) { - mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "restartActivityProcess()"); + enforceTaskPermission("restartActivityProcess()"); final long callingId = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { @@ -2367,7 +2376,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public Rect getTaskBounds(int taskId) { - mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "getTaskBounds()"); + enforceTaskPermission("getTaskBounds()"); final long ident = Binder.clearCallingIdentity(); Rect rect = new Rect(); try { @@ -2394,7 +2403,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { public ActivityManager.TaskDescription getTaskDescription(int id) { synchronized (mGlobalLock) { enforceCallerIsRecentsOrHasPermission( - MANAGE_ACTIVITY_STACKS, "getTaskDescription()"); + MANAGE_ACTIVITY_TASKS, "getTaskDescription()"); final Task tr = mRootWindowContainer.anyTaskForId(id, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS); if (tr != null) { @@ -2409,7 +2418,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { return setTaskWindowingModeSplitScreenPrimary(taskId, toTop); } - enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "setTaskWindowingMode()"); + enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_TASKS, "setTaskWindowingMode()"); synchronized (mGlobalLock) { final long ident = Binder.clearCallingIdentity(); try { @@ -2626,8 +2635,35 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { throw new SecurityException(msg); } + /** + * Return true if app switch protection will be handled by background activity launch logic. + */ + boolean getBalAppSwitchesProtectionEnabled() { + return CompatChanges.isChangeEnabled(BLOCK_ACTIVITY_STARTS_AFTER_HOME); + } + + /** + * Return true if app switching is allowed. + */ + boolean getBalAppSwitchesAllowed() { + if (getBalAppSwitchesProtectionEnabled()) { + // Apps no longer able to start BAL again until app switching is resumed. + return mAppSwitchesAllowedTime == 0; + } else { + // Legacy behavior, BAL logic won't block app switching. + return true; + } + } + boolean checkAppSwitchAllowedLocked(int sourcePid, int sourceUid, int callingPid, int callingUid, String name) { + + // Background activity launch logic replaces app switching protection, so allow + // apps to start activity here now. + if (getBalAppSwitchesProtectionEnabled()) { + return true; + } + if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) { return true; } @@ -2766,7 +2802,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public void moveTaskToRootTask(int taskId, int rootTaskId, boolean toTop) { - enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "moveTaskToRootTask()"); + enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_TASKS, "moveTaskToRootTask()"); synchronized (mGlobalLock) { final long ident = Binder.clearCallingIdentity(); try { @@ -2805,7 +2841,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { */ @Override public boolean setTaskWindowingModeSplitScreenPrimary(int taskId, boolean toTop) { - enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, + enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_TASKS, "setTaskWindowingModeSplitScreenPrimary()"); synchronized (mGlobalLock) { final long ident = Binder.clearCallingIdentity(); @@ -2882,7 +2918,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { */ @Override public void removeRootTasksInWindowingModes(int[] windowingModes) { - enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, + enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_TASKS, "removeRootTasksInWindowingModes()"); synchronized (mGlobalLock) { @@ -2897,7 +2933,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public void removeRootTasksWithActivityTypes(int[] activityTypes) { - enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, + enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_TASKS, "removeRootTasksWithActivityTypes()"); synchronized (mGlobalLock) { @@ -2924,7 +2960,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public List<RootTaskInfo> getAllRootTaskInfos() { - enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "getAllRootTaskInfos()"); + enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_TASKS, "getAllRootTaskInfos()"); final long ident = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { @@ -2937,7 +2973,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public RootTaskInfo getRootTaskInfo(int windowingMode, int activityType) { - enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "getRootTaskInfo()"); + enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_TASKS, "getRootTaskInfo()"); final long ident = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { @@ -2950,7 +2986,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public List<RootTaskInfo> getAllRootTaskInfosOnDisplay(int displayId) { - enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, + enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_TASKS, "getAllRootTaskInfosOnDisplay()"); final long ident = Binder.clearCallingIdentity(); try { @@ -2965,7 +3001,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public RootTaskInfo getRootTaskInfoOnDisplay(int windowingMode, int activityType, int displayId) { - enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "getRootTaskInfoOnDisplay()"); + enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_TASKS, "getRootTaskInfoOnDisplay()"); final long ident = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { @@ -2978,7 +3014,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public void cancelRecentsAnimation(boolean restoreHomeRootTaskPosition) { - enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "cancelRecentsAnimation()"); + enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_TASKS, "cancelRecentsAnimation()"); final long callingUid = Binder.getCallingUid(); final long origId = Binder.clearCallingIdentity(); try { @@ -3006,7 +3042,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public void startSystemLockTaskMode(int taskId) { - mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "startSystemLockTaskMode"); + enforceTaskPermission("startSystemLockTaskMode"); // This makes inner call to look as if it was initiated by system. final long ident = Binder.clearCallingIdentity(); try { @@ -3037,7 +3073,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { */ @Override public void stopSystemLockTaskMode() throws RemoteException { - mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "stopSystemLockTaskMode"); + enforceTaskPermission("stopSystemLockTaskMode"); stopLockTaskModeInternal(null, true /* isSystemCaller */); } @@ -3371,7 +3407,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public boolean resizeTask(int taskId, Rect bounds, int resizeMode) { - mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "resizeTask()"); + enforceTaskPermission("resizeTask()"); final long ident = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { @@ -3545,7 +3581,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { /** Sets the task stack listener that gets callbacks when a task stack changes. */ @Override public void registerTaskStackListener(ITaskStackListener listener) { - enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, + enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_TASKS, "registerTaskStackListener()"); mTaskChangeNotificationController.registerTaskStackListener(listener); } @@ -3553,7 +3589,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { /** Unregister a task stack listener so that it stops receiving callbacks. */ @Override public void unregisterTaskStackListener(ITaskStackListener listener) { - enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, + enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_TASKS, "unregisterTaskStackListener()"); mTaskChangeNotificationController.unregisterTaskStackListener(listener); } @@ -3608,12 +3644,35 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } /** This can be called with or without the global lock held. */ - private void enforceCallerIsRecentsOrHasPermission(String permission, String func) { - if (!getRecentTasks().isCallerRecents(Binder.getCallingUid())) { + void enforceCallerIsRecentsOrHasPermission(String permission, String func) { + if (getRecentTasks().isCallerRecents(Binder.getCallingUid())) { + return; + } + + if (permission.equals(MANAGE_ACTIVITY_TASKS) || permission.equals(MANAGE_ACTIVITY_STACKS)) { + enforceTaskPermission(func); + } else { mAmInternal.enforceCallingPermission(permission, func); } } + static void enforceTaskPermission(String func) { + if (checkCallingPermission(MANAGE_ACTIVITY_TASKS) == PackageManager.PERMISSION_GRANTED) { + return; + } + + if (checkCallingPermission(MANAGE_ACTIVITY_STACKS) == PackageManager.PERMISSION_GRANTED) { + Slog.w(TAG, "MANAGE_ACTIVITY_STACKS is deprecated, " + + "please use alternative permission: MANAGE_ACTIVITY_TASKS"); + return; + } + + String msg = "Permission Denial: " + func + " from pid=" + Binder.getCallingPid() + ", uid=" + + Binder.getCallingUid() + " requires android.permission.MANAGE_ACTIVITY_TASKS"; + Slog.w(TAG, msg); + throw new SecurityException(msg); + } + @VisibleForTesting int checkGetTasksPermission(String permission, int pid, int uid) { return checkPermission(permission, pid, uid); @@ -3978,7 +4037,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public void suppressResizeConfigChanges(boolean suppress) throws RemoteException { - mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, + mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_TASKS, "suppressResizeConfigChanges()"); synchronized (mGlobalLock) { mSuppressResizeConfigChanges = suppress; @@ -3995,7 +4054,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { */ @Override public boolean moveTopActivityToPinnedRootTask(int rootTaskId, Rect bounds) { - enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, + enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_TASKS, "moveTopActivityToPinnedRootTask()"); synchronized (mGlobalLock) { if (!mSupportsPictureInPicture) { @@ -4180,7 +4239,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { public void resizePrimarySplitScreen(Rect dockedBounds, Rect tempDockedTaskBounds, Rect tempDockedTaskInsetBounds, Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds) { - enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "resizePrimarySplitScreen()"); + enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_TASKS, "resizePrimarySplitScreen()"); final long ident = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { @@ -4218,7 +4277,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public void setSplitScreenResizing(boolean resizing) { - enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "setSplitScreenResizing()"); + enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_TASKS, "setSplitScreenResizing()"); final long ident = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { @@ -4231,8 +4290,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public IWindowOrganizerController getWindowOrganizerController() { - mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, - "getWindowOrganizerController()"); + enforceTaskPermission("getWindowOrganizerController()"); return mWindowOrganizerController; } @@ -4373,7 +4431,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public void cancelTaskWindowTransition(int taskId) { - enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, + enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_TASKS, "cancelTaskWindowTransition()"); final long ident = Binder.clearCallingIdentity(); try { @@ -4647,7 +4705,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mAppSwitchesAllowedTime = SystemClock.uptimeMillis() + APP_SWITCH_DELAY_TIME; mLastStopAppSwitchesTime = SystemClock.uptimeMillis(); mDidAppSwitch = false; - getActivityStartController().schedulePendingActivityLaunches(APP_SWITCH_DELAY_TIME); + // If BAL app switching enabled, app switches are blocked not delayed. + if (!getBalAppSwitchesProtectionEnabled()) { + getActivityStartController().schedulePendingActivityLaunches(APP_SWITCH_DELAY_TIME); + } } } @@ -4774,8 +4835,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { */ @Override public void clearLaunchParamsForPackages(List<String> packageNames) { - mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, - "clearLaunchParamsForPackages"); + enforceTaskPermission("clearLaunchParamsForPackages"); synchronized (mGlobalLock) { for (int i = 0; i < packageNames.size(); ++i) { mStackSupervisor.mLaunchParamsPersister.removeRecordForPackage(packageNames.get(i)); @@ -4788,8 +4848,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { */ @Override public void requestPictureInPictureMode(IBinder token) throws RemoteException { - mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, - "requestPictureInPictureMode"); + enforceTaskPermission("requestPictureInPictureMode"); final long origId = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { @@ -6883,8 +6942,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public void startConfirmDeviceCredentialIntent(Intent intent, Bundle options) { - mAmInternal.enforceCallingPermission( - MANAGE_ACTIVITY_STACKS, "startConfirmDeviceCredentialIntent"); + enforceTaskPermission("startConfirmDeviceCredentialIntent"); synchronized (mGlobalLock) { final long ident = Binder.clearCallingIdentity(); diff --git a/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java b/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java index dd92f507a33d..667f3dc9d8d3 100644 --- a/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java +++ b/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java @@ -16,9 +16,6 @@ package com.android.server.wm; -import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS; - - import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER; import android.os.Binder; @@ -62,13 +59,13 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl mGlobalLock = atm.mGlobalLock; } - private void enforceStackPermission(String func) { - mService.mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, func); + private void enforceTaskPermission(String func) { + mService.enforceTaskPermission(func); } @Override public void registerOrganizer(IDisplayAreaOrganizer organizer, int feature) { - enforceStackPermission("registerOrganizer()"); + enforceTaskPermission("registerOrganizer()"); final long uid = Binder.getCallingUid(); final long origId = Binder.clearCallingIdentity(); try { @@ -100,7 +97,7 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl @Override public void unregisterOrganizer(IDisplayAreaOrganizer organizer) { - enforceStackPermission("unregisterTaskOrganizer()"); + enforceTaskPermission("unregisterTaskOrganizer()"); final long uid = Binder.getCallingUid(); final long origId = Binder.clearCallingIdentity(); try { diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 7641de5ab7b9..26c5d70a2c45 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -5467,7 +5467,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp return; } - if (animatingRecents != null && animatingRecents == mFixedRotationLaunchingApp) { + if (animatingRecents != null && animatingRecents == mFixedRotationLaunchingApp + && animatingRecents.isVisible()) { // The recents activity should be going to be invisible (switch to another app or // return to original top). Only clear the top launching record without finishing // the transform immediately because it won't affect display orientation. And before diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index baa26e62b3b5..7a42b0db0c52 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -55,7 +55,6 @@ import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW; import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON; import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; import static android.view.WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN; -import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; @@ -991,9 +990,7 @@ public class DisplayPolicy { "DisplayPolicy"); } if ((attrs.privateFlags & PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP) != 0) { - mContext.enforcePermission( - android.Manifest.permission.MANAGE_ACTIVITY_STACKS, callingPid, callingUid, - "DisplayPolicy"); + ActivityTaskManagerService.enforceTaskPermission("DisplayPolicy"); } switch (attrs.type) { diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java index 72ecf6be430d..2ea4b57d9de3 100644 --- a/services/core/java/com/android/server/wm/DragState.java +++ b/services/core/java/com/android/server/wm/DragState.java @@ -16,8 +16,6 @@ package com.android.server.wm; -import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS; -import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP; @@ -118,6 +116,10 @@ class DragState { * without having a WM lock. */ volatile boolean mAnimationCompleted = false; + /** + * The display on which the drag is happening. If it goes into a different display this will + * be updated. + */ DisplayContent mDisplayContent; @Nullable private ValueAnimator mAnimator; @@ -308,7 +310,9 @@ class DragState { // Pause rotations before a drag. ProtoLog.d(WM_DEBUG_ORIENTATION, "Pausing rotation during drag"); - mDisplayContent.getDisplayRotation().pause(); + mService.mRoot.forAllDisplays(dc -> { + dc.getDisplayRotation().pause(); + }); } void tearDown() { @@ -323,7 +327,9 @@ class DragState { // Resume rotations after a drag. ProtoLog.d(WM_DEBUG_ORIENTATION, "Resuming rotation after drag"); - mDisplayContent.getDisplayRotation().resume(); + mService.mRoot.forAllDisplays(dc -> { + dc.getDisplayRotation().resume(); + }); } } @@ -371,9 +377,9 @@ class DragState { Slog.d(TAG_WM, "broadcasting DRAG_STARTED at (" + touchX + ", " + touchY + ")"); } - mDisplayContent.forAllWindows(w -> { + mService.mRoot.forAllWindows(w -> { sendDragStartedLocked(w, touchX, touchY, mDataDescription, mData); - }, false /* traverseTopToBottom */ ); + }, false /* traverseTopToBottom */); } /* helper - send a ACTION_DRAG_STARTED event, if the diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java index c49690157c08..e90436ef3b91 100644 --- a/services/core/java/com/android/server/wm/LockTaskController.java +++ b/services/core/java/com/android/server/wm/LockTaskController.java @@ -430,7 +430,7 @@ public class LockTaskController { // instead of the app calling startLockTaskMode. In this case // {@link Task.mLockTaskUid} will be 0, so we compare the callingUid to the // {@link Task.effectiveUid} instead. Also caller with - // {@link MANAGE_ACTIVITY_STACKS} can stop any lock task. + // {@link MANAGE_ACTIVITY_TASKS} can stop any lock task. if (callingUid != task.mLockTaskUid && (task.mLockTaskUid != 0 || callingUid != task.effectiveUid)) { throw new SecurityException("Invalid uid, expected " + task.mLockTaskUid diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java index 72edb86283d2..6fbd35164874 100644 --- a/services/core/java/com/android/server/wm/Session.java +++ b/services/core/java/com/android/server/wm/Session.java @@ -20,7 +20,12 @@ import static android.Manifest.permission.DEVICE_POWER; import static android.Manifest.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS; import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW; import static android.Manifest.permission.START_TASKS_FROM_RECENTS; +import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.content.ClipDescription.MIMETYPE_APPLICATION_ACTIVITY; +import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT; +import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK; +import static android.content.Intent.EXTRA_SHORTCUT_ID; +import static android.content.Intent.EXTRA_TASK_ID; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; @@ -49,6 +54,7 @@ import android.os.Process; import android.os.RemoteException; import android.os.Trace; import android.os.UserHandle; +import android.text.TextUtils; import android.util.ArraySet; import android.util.MergedConfiguration; import android.util.Slog; @@ -297,18 +303,25 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { */ @VisibleForTesting public void validateAndResolveDragMimeTypeExtras(ClipData data, int callingUid) { + if (Binder.getCallingUid() == Process.SYSTEM_UID) { + throw new IllegalStateException("Need to validate before calling identify is cleared"); + } final ClipDescription desc = data != null ? data.getDescription() : null; if (desc == null) { return; } // Ensure that only one of the app mime types are set final boolean hasActivity = desc.hasMimeType(MIMETYPE_APPLICATION_ACTIVITY); - int appMimeTypeCount = (hasActivity ? 1 : 0); + final boolean hasShortcut = desc.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT); + final boolean hasTask = desc.hasMimeType(MIMETYPE_APPLICATION_TASK); + int appMimeTypeCount = (hasActivity ? 1 : 0) + + (hasShortcut ? 1 : 0) + + (hasTask ? 1 : 0); if (appMimeTypeCount == 0) { return; } else if (appMimeTypeCount > 1) { throw new IllegalArgumentException("Can not specify more than one of activity, " - + "or task mime types"); + + "shortcut, or task mime types"); } // Ensure that data is provided and that they are intents if (data.getItemCount() == 0) { @@ -344,6 +357,28 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { } finally { Binder.restoreCallingIdentity(origId); } + } else if (hasShortcut) { + mService.mAtmService.enforceCallerIsRecentsOrHasPermission(START_TASKS_FROM_RECENTS, + "performDrag"); + for (int i = 0; i < data.getItemCount(); i++) { + final Intent intent = data.getItemAt(i).getIntent(); + final UserHandle user = intent.getParcelableExtra(Intent.EXTRA_USER); + if (!intent.hasExtra(EXTRA_SHORTCUT_ID) + || TextUtils.isEmpty(intent.getStringExtra(EXTRA_SHORTCUT_ID)) + || user == null) { + throw new IllegalArgumentException("Clip item must include the shortcut id and " + + "the user to launch for."); + } + } + } else if (hasTask) { + mService.mAtmService.enforceCallerIsRecentsOrHasPermission(START_TASKS_FROM_RECENTS, + "performDrag"); + for (int i = 0; i < data.getItemCount(); i++) { + final Intent intent = data.getItemAt(i).getIntent(); + if (intent.getIntExtra(EXTRA_TASK_ID, INVALID_TASK_ID) == INVALID_TASK_ID) { + throw new IllegalArgumentException("Clip item must include the task id."); + } + } } } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 6ffd9a28c10a..5bc5b47d5cfc 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -149,6 +149,7 @@ import static com.android.server.wm.WindowContainerChildProto.TASK; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; +import static com.android.server.wm.WindowManagerService.MIN_TASK_LETTERBOX_ASPECT_RATIO; import static com.android.server.wm.WindowManagerService.dipToPixel; import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM; @@ -2960,6 +2961,14 @@ class Task extends WindowContainer<WindowContainer> { } } + // Override from config_letterboxAspectRatio or via ADB with set-letterbox-aspect-ratio. + final float letterboxAspectRatioOverride = mWmService.getTaskLetterboxAspectRatio(); + // Activity min/max aspect ratio restrictions will be respected by the activity-level + // letterboxing (size-compat mode). Therefore this override can control the maximum screen + // area that can be occupied by the app in the letterbox mode. + aspect = letterboxAspectRatioOverride > MIN_TASK_LETTERBOX_ASPECT_RATIO + ? letterboxAspectRatioOverride : aspect; + if (forcedOrientation == ORIENTATION_LANDSCAPE) { final int height = (int) Math.rint(parentWidth / aspect); final int top = parentBounds.centerY() - height / 2; @@ -5770,8 +5779,9 @@ class Task extends WindowContainer<WindowContainer> { boolean preserveWindows, boolean notifyClients) { mStackSupervisor.beginActivityVisibilityUpdate(); try { - mEnsureActivitiesVisibleHelper.process(starting, configChanges, preserveWindows, - notifyClients); + forAllLeafTasks(task -> task.mEnsureActivitiesVisibleHelper.process( + starting, configChanges, preserveWindows, notifyClients), + true /* traverseTopToBottom */); if (mTranslucentActivityWaiting != null && mUndrawnActivitiesBelowTopTranslucent.isEmpty()) { diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java index a70efbcf5500..2c39c2b4a98e 100644 --- a/services/core/java/com/android/server/wm/TaskOrganizerController.java +++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java @@ -16,7 +16,6 @@ package com.android.server.wm; -import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; @@ -293,8 +292,8 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { mGlobalLock = atm.mGlobalLock; } - private void enforceStackPermission(String func) { - mService.mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, func); + private void enforceTaskPermission(String func) { + mService.enforceTaskPermission(func); } /** @@ -310,7 +309,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { */ @Override public ParceledListSlice<TaskAppearedInfo> registerTaskOrganizer(ITaskOrganizer organizer) { - enforceStackPermission("registerTaskOrganizer()"); + enforceTaskPermission("registerTaskOrganizer()"); final int uid = Binder.getCallingUid(); final long origId = Binder.clearCallingIdentity(); try { @@ -355,7 +354,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { @Override public void unregisterTaskOrganizer(ITaskOrganizer organizer) { - enforceStackPermission("unregisterTaskOrganizer()"); + enforceTaskPermission("unregisterTaskOrganizer()"); final int uid = Binder.getCallingUid(); final long origId = Binder.clearCallingIdentity(); try { @@ -401,7 +400,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { @Override public void createRootTask(int displayId, int windowingMode, @Nullable IBinder launchCookie) { - enforceStackPermission("createRootTask()"); + enforceTaskPermission("createRootTask()"); final long origId = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { @@ -435,7 +434,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { @Override public boolean deleteRootTask(WindowContainerToken token) { - enforceStackPermission("deleteRootTask()"); + enforceTaskPermission("deleteRootTask()"); final long origId = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { @@ -529,7 +528,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { @Override public WindowContainerToken getImeTarget(int displayId) { - enforceStackPermission("getImeTarget()"); + enforceTaskPermission("getImeTarget()"); final long origId = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { @@ -552,7 +551,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { @Override public void setLaunchRoot(int displayId, @Nullable WindowContainerToken token) { - enforceStackPermission("setLaunchRoot()"); + enforceTaskPermission("setLaunchRoot()"); final long origId = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { @@ -586,7 +585,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { @Override public List<RunningTaskInfo> getChildTasks(WindowContainerToken parent, @Nullable int[] activityTypes) { - enforceStackPermission("getChildTasks()"); + enforceTaskPermission("getChildTasks()"); final long ident = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { @@ -627,7 +626,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { @Override public List<RunningTaskInfo> getRootTasks(int displayId, @Nullable int[] activityTypes) { - enforceStackPermission("getRootTasks()"); + enforceTaskPermission("getRootTasks()"); final long ident = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { @@ -657,7 +656,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { @Override public void setInterceptBackPressedOnTaskRoot(WindowContainerToken token, boolean interceptBackPressed) { - enforceStackPermission("setInterceptBackPressedOnTaskRoot()"); + enforceTaskPermission("setInterceptBackPressedOnTaskRoot()"); final long origId = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 0585679f7fbb..5bbd24918ec7 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -19,7 +19,6 @@ package com.android.server.wm; import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS; import static android.Manifest.permission.INPUT_CONSUMER; import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW; -import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS; import static android.Manifest.permission.MANAGE_APP_TOKENS; import static android.Manifest.permission.READ_FRAME_BUFFER; import static android.Manifest.permission.REGISTER_WINDOW_MANAGER_LISTENERS; @@ -153,6 +152,7 @@ import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; +import android.content.pm.TestUtilityService; import android.content.res.Configuration; import android.content.res.TypedArray; import android.database.ContentObserver; @@ -453,6 +453,14 @@ public class WindowManagerService extends IWindowManager.Stub /** System UI can create more window context... */ private static final int SYSTEM_UI_MULTIPLIER = 2; + /** + * Override of task letterbox aspect ratio that is set via ADB with + * set-task-letterbox-aspect-ratio or via {@link + * com.android.internal.R.dimen.config_taskLetterboxAspectRatio} will be ignored + * if it is <= this value. + */ + static final float MIN_TASK_LETTERBOX_ASPECT_RATIO = 1.0f; + final WindowManagerConstants mConstants; final WindowTracing mWindowTracing; @@ -564,6 +572,7 @@ public class WindowManagerService extends IWindowManager.Stub final AppOpsManager mAppOps; final PackageManagerInternal mPmInternal; + private final TestUtilityService mTestUtilityService; final DisplayWindowSettings mDisplayWindowSettings; @@ -960,6 +969,10 @@ public class WindowManagerService extends IWindowManager.Stub private boolean mAnimationsDisabled = false; boolean mPointerLocationEnabled = false; + // Aspect ratio of task level letterboxing, values <= MIN_TASK_LETTERBOX_ASPECT_RATIO will be + // ignored. + private float mTaskLetterboxAspectRatio; + final InputManagerService mInputManager; final DisplayManagerInternal mDisplayManagerInternal; final DisplayManager mDisplayManager; @@ -1188,6 +1201,8 @@ public class WindowManagerService extends IWindowManager.Stub com.android.internal.R.bool.config_perDisplayFocusEnabled); mAssistantOnTopOfDream = context.getResources().getBoolean( com.android.internal.R.bool.config_assistantOnTopOfDream); + mTaskLetterboxAspectRatio = context.getResources().getFloat( + com.android.internal.R.dimen.config_taskLetterboxAspectRatio); mInputManager = inputManager; // Must be before createDisplayContentLocked. mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class); @@ -1201,9 +1216,7 @@ public class WindowManagerService extends IWindowManager.Stub mAnimator = new WindowAnimator(this); mRoot = new RootWindowContainer(this); - mUseBLAST = DeviceConfig.getBoolean( - DeviceConfig.NAMESPACE_WINDOW_MANAGER_NATIVE_BOOT, - WM_USE_BLAST_ADAPTER_FLAG, false); + mUseBLAST = true; mSyncEngine = new BLASTSyncEngine(this); @@ -1265,6 +1278,7 @@ public class WindowManagerService extends IWindowManager.Stub mAppOps.startWatchingMode(AppOpsManager.OP_TOAST_WINDOW, null, opListener); mPmInternal = LocalServices.getService(PackageManagerInternal.class); + mTestUtilityService = LocalServices.getService(TestUtilityService.class); final IntentFilter suspendPackagesFilter = new IntentFilter(); suspendPackagesFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED); suspendPackagesFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED); @@ -3752,6 +3766,53 @@ public class WindowManagerService extends IWindowManager.Stub } } + /** + * Overrides the aspect ratio of task level letterboxing. If given value is <= {@link + * #MIN_TASK_LETTERBOX_ASPECT_RATIO}, both it and a value of {@link + * com.android.internal.R.dimen.config_taskLetterboxAspectRatio} will be ignored and + * the framework implementation will be used to determine the aspect ratio. + */ + void setTaskLetterboxAspectRatio(float aspectRatio) { + final long origId = Binder.clearCallingIdentity(); + try { + synchronized (mGlobalLock) { + mTaskLetterboxAspectRatio = aspectRatio; + } + } finally { + Binder.restoreCallingIdentity(origId); + } + } + + /** + * Resets the aspect ratio of task level letterboxing to {@link + * com.android.internal.R.dimen.config_taskLetterboxAspectRatio}. + */ + void resetTaskLetterboxAspectRatio() { + final long origId = Binder.clearCallingIdentity(); + try { + synchronized (mGlobalLock) { + mTaskLetterboxAspectRatio = mContext.getResources().getFloat( + com.android.internal.R.dimen.config_taskLetterboxAspectRatio); + } + } finally { + Binder.restoreCallingIdentity(origId); + } + } + + /** + * Gets the aspect ratio of task level letterboxing. + */ + float getTaskLetterboxAspectRatio() { + final long origId = Binder.clearCallingIdentity(); + try { + synchronized (mGlobalLock) { + return mTaskLetterboxAspectRatio; + } + } finally { + Binder.restoreCallingIdentity(origId); + } + } + @Override public void setIgnoreOrientationRequest(int displayId, boolean ignoreOrientationRequest) { mAtmInternal.enforceCallerIsRecentsOrHasPermission( @@ -3953,10 +4014,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void setDisplayWindowRotationController(IDisplayWindowRotationController controller) { - if (mContext.checkCallingOrSelfPermission(MANAGE_ACTIVITY_STACKS) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Must hold permission " + MANAGE_ACTIVITY_STACKS); - } + mAtmService.enforceTaskPermission("setDisplayWindowRotationController"); try { synchronized (mGlobalLock) { if (mDisplayRotationController != null) { @@ -4225,10 +4283,7 @@ public class WindowManagerService extends IWindowManager.Stub /** Registers a hierarchy listener that gets callbacks when the hierarchy changes. */ @Override public void registerDisplayWindowListener(IDisplayWindowListener listener) { - if (mContext.checkCallingOrSelfPermission(MANAGE_ACTIVITY_STACKS) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Must hold permission " + MANAGE_ACTIVITY_STACKS); - } + mAtmService.enforceTaskPermission("registerDisplayWindowListener"); final long ident = Binder.clearCallingIdentity(); try { mDisplayNotificationController.registerListener(listener); @@ -4240,10 +4295,7 @@ public class WindowManagerService extends IWindowManager.Stub /** Unregister a hierarchy listener so that it stops receiving callbacks. */ @Override public void unregisterDisplayWindowListener(IDisplayWindowListener listener) { - if (mContext.checkCallingOrSelfPermission(MANAGE_ACTIVITY_STACKS) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Must hold permission " + MANAGE_ACTIVITY_STACKS); - } + mAtmService.enforceTaskPermission("unregisterDisplayWindowListener"); mDisplayNotificationController.unregisterListener(listener); } @@ -6925,9 +6977,6 @@ public class WindowManagerService extends IWindowManager.Stub if (!checkCallingPermission(READ_FRAME_BUFFER, "requestScrollCapture()")) { throw new SecurityException("Requires READ_FRAME_BUFFER permission"); } - if (behindClient != null && !isWindowToken(behindClient)) { - throw new IllegalArgumentException("behindClient must be a window token"); - } final long token = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { @@ -8352,9 +8401,8 @@ public class WindowManagerService extends IWindowManager.Stub } @Override - public void holdLock(int durationMs) { - mContext.enforceCallingPermission( - Manifest.permission.INJECT_EVENTS, "holdLock requires shell identity"); + public void holdLock(IBinder token, int durationMs) { + mTestUtilityService.verifyHoldLockToken(token); synchronized (mGlobalLock) { SystemClock.sleep(durationMs); diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java index fe312e6b4c46..a3a9c1ce9219 100644 --- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java +++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java @@ -111,6 +111,10 @@ public class WindowManagerShellCommand extends ShellCommand { return runGetIgnoreOrientationRequest(pw); case "dump-visible-window-views": return runDumpVisibleWindowViews(pw); + case "set-task-letterbox-aspect-ratio": + return runSetTaskLetterboxAspectRatio(pw); + case "get-task-letterbox-aspect-ratio": + return runGetTaskLetterboxAspectRatio(pw); case "reset": return runReset(pw); default: @@ -509,6 +513,38 @@ public class WindowManagerShellCommand extends ShellCommand { return 0; } + private int runSetTaskLetterboxAspectRatio(PrintWriter pw) throws RemoteException { + final float aspectRatio; + try { + String arg = getNextArgRequired(); + if ("reset".equals(arg)) { + mInternal.resetTaskLetterboxAspectRatio(); + return 0; + } + aspectRatio = Float.parseFloat(arg); + } catch (NumberFormatException e) { + getErrPrintWriter().println("Error: bad aspect ratio format " + e); + return -1; + } catch (IllegalArgumentException e) { + getErrPrintWriter().println( + "Error: 'reset' or aspect ratio should be provided as an argument " + e); + return -1; + } + + mInternal.setTaskLetterboxAspectRatio(aspectRatio); + return 0; + } + + private int runGetTaskLetterboxAspectRatio(PrintWriter pw) throws RemoteException { + final float aspectRatio = mInternal.getTaskLetterboxAspectRatio(); + if (aspectRatio <= WindowManagerService.MIN_TASK_LETTERBOX_ASPECT_RATIO) { + pw.println("Letterbox aspect ratio is not set"); + } else { + pw.println("Letterbox aspect ratio is " + aspectRatio); + } + return 0; + } + private int runReset(PrintWriter pw) throws RemoteException { int displayId = getDisplayId(getNextArg()); @@ -533,6 +569,9 @@ public class WindowManagerShellCommand extends ShellCommand { // set-ignore-orientation-request mInterface.setIgnoreOrientationRequest(displayId, false /* ignoreOrientationRequest */); + // set-task-letterbox-aspect-ratio + mInternal.resetTaskLetterboxAspectRatio(); + pw.println("Reset all settings for displayId=" + displayId); return 0; } @@ -563,6 +602,12 @@ public class WindowManagerShellCommand extends ShellCommand { pw.println(" set-ignore-orientation-request [-d DISPLAY_ID] [true|1|false|0]"); pw.println(" get-ignore-orientation-request [-d DISPLAY_ID] "); pw.println(" If app requested orientation should be ignored."); + pw.println(" set-task-letterbox-aspect-ratio [reset|aspectRatio]"); + pw.println(" get-task-letterbox-aspect-ratio"); + pw.println(" Aspect ratio of task level letterboxing. If aspectRatio <= " + + WindowManagerService.MIN_TASK_LETTERBOX_ASPECT_RATIO); + pw.println(" both it and R.dimen.config_taskLetterboxAspectRatio will be ignored"); + pw.println(" and framework implementation will be used to determine aspect ratio."); pw.println(" reset [-d DISPLAY_ID]"); pw.println(" Reset all override settings."); if (!IS_USER) { diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index ae152d253d17..51857dcd323b 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -16,7 +16,6 @@ package com.android.server.wm; -import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS; import static android.Manifest.permission.READ_FRAME_BUFFER; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER; @@ -117,7 +116,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub @Override public IBinder startTransition(int type, @Nullable IBinder transitionToken, @Nullable WindowContainerTransaction t) { - enforceStackPermission("startTransition()"); + enforceTaskPermission("startTransition()"); final long ident = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { @@ -144,7 +143,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub public int finishTransition(@NonNull IBinder transitionToken, @Nullable WindowContainerTransaction t, @Nullable IWindowContainerTransactionCallback callback) { - enforceStackPermission("finishTransition()"); + enforceTaskPermission("finishTransition()"); final long ident = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { @@ -168,7 +167,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub private int applyTransaction(@NonNull WindowContainerTransaction t, @Nullable IWindowContainerTransactionCallback callback, @Nullable Transition transition) { - enforceStackPermission("applySyncTransaction()"); + enforceTaskPermission("applySyncTransaction()"); int syncId = -1; if (t == null) { throw new IllegalArgumentException( @@ -491,13 +490,13 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub @Override public ITaskOrganizerController getTaskOrganizerController() { - enforceStackPermission("getTaskOrganizerController()"); + enforceTaskPermission("getTaskOrganizerController()"); return mTaskOrganizerController; } @Override public IDisplayAreaOrganizerController getDisplayAreaOrganizerController() { - enforceStackPermission("getDisplayAreaOrganizerController()"); + enforceTaskPermission("getDisplayAreaOrganizerController()"); return mDisplayAreaOrganizerController; } @@ -573,7 +572,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub @Override public void registerTransitionPlayer(ITransitionPlayer player) { - enforceStackPermission("registerTransitionPlayer()"); + enforceTaskPermission("registerTransitionPlayer()"); final long ident = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { @@ -584,7 +583,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub } } - private void enforceStackPermission(String func) { - mService.mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, func); + private void enforceTaskPermission(String func) { + mService.enforceTaskPermission(func); } } diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java index 2e7905c64049..2d69dcbcfbd0 100644 --- a/services/core/java/com/android/server/wm/WindowProcessController.java +++ b/services/core/java/com/android/server/wm/WindowProcessController.java @@ -505,29 +505,33 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio } } - boolean areBackgroundActivityStartsAllowed() { - // allow if any activity in the caller has either started or finished very recently, and - // it must be started or finished after last stop app switches time. - final long now = SystemClock.uptimeMillis(); - if (now - mLastActivityLaunchTime < ACTIVITY_BG_START_GRACE_PERIOD_MS - || now - mLastActivityFinishTime < ACTIVITY_BG_START_GRACE_PERIOD_MS) { - // if activity is started and finished before stop app switch time, we should not - // let app to be able to start background activity even it's in grace period. - if (mLastActivityLaunchTime > mAtm.getLastStopAppSwitchesTime() - || mLastActivityFinishTime > mAtm.getLastStopAppSwitchesTime()) { + boolean areBackgroundActivityStartsAllowed(boolean appSwitchAllowed) { + // If app switching is not allowed, we ignore all the start activity grace period + // exception so apps cannot start itself in onPause() after pressing home button. + if (appSwitchAllowed) { + // allow if any activity in the caller has either started or finished very recently, and + // it must be started or finished after last stop app switches time. + final long now = SystemClock.uptimeMillis(); + if (now - mLastActivityLaunchTime < ACTIVITY_BG_START_GRACE_PERIOD_MS + || now - mLastActivityFinishTime < ACTIVITY_BG_START_GRACE_PERIOD_MS) { + // if activity is started and finished before stop app switch time, we should not + // let app to be able to start background activity even it's in grace period. + if (mLastActivityLaunchTime > mAtm.getLastStopAppSwitchesTime() + || mLastActivityFinishTime > mAtm.getLastStopAppSwitchesTime()) { + if (DEBUG_ACTIVITY_STARTS) { + Slog.d(TAG, "[WindowProcessController(" + mPid + + ")] Activity start allowed: within " + + ACTIVITY_BG_START_GRACE_PERIOD_MS + "ms grace period"); + } + return true; + } if (DEBUG_ACTIVITY_STARTS) { - Slog.d(TAG, "[WindowProcessController(" + mPid - + ")] Activity start allowed: within " - + ACTIVITY_BG_START_GRACE_PERIOD_MS + "ms grace period"); + Slog.d(TAG, "[WindowProcessController(" + mPid + ")] Activity start within " + + ACTIVITY_BG_START_GRACE_PERIOD_MS + + "ms grace period but also within stop app switch window"); } - return true; - } - if (DEBUG_ACTIVITY_STARTS) { - Slog.d(TAG, "[WindowProcessController(" + mPid + ")] Activity start within " - + ACTIVITY_BG_START_GRACE_PERIOD_MS - + "ms grace period but also within stop app switch window"); - } + } } // allow if the proc is instrumenting with background activity starts privs if (mInstrumentingWithBackgroundActivityStartPrivileges) { @@ -539,7 +543,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio return true; } // allow if the caller has an activity in any foreground task - if (hasActivityInVisibleTask()) { + if (appSwitchAllowed && hasActivityInVisibleTask()) { if (DEBUG_ACTIVITY_STARTS) { Slog.d(TAG, "[WindowProcessController(" + mPid + ")] Activity start allowed: process has activity in foreground task"); diff --git a/services/core/jni/com_android_server_am_BatteryStatsService.cpp b/services/core/jni/com_android_server_am_BatteryStatsService.cpp index d39c7a6fd8df..5d78f127f77f 100644 --- a/services/core/jni/com_android_server_am_BatteryStatsService.cpp +++ b/services/core/jni/com_android_server_am_BatteryStatsService.cpp @@ -17,7 +17,6 @@ #define LOG_TAG "BatteryStatsService" //#define LOG_NDEBUG 0 -#include <climits> #include <errno.h> #include <fcntl.h> #include <inttypes.h> @@ -28,6 +27,7 @@ #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> +#include <climits> #include <unordered_map> #include <utility> @@ -66,10 +66,9 @@ using IPowerV1_0 = android::hardware::power::V1_0::IPower; namespace android { -#define LAST_RESUME_REASON "/sys/kernel/wakeup_reasons/last_resume_reason" -#define MAX_REASON_SIZE 512 - static bool wakeup_init = false; +static std::mutex mReasonsMutex; +static std::vector<std::string> mWakeupReasons; static sem_t wakeup_sem; extern sp<ISuspendControlService> getSuspendControl(); @@ -115,9 +114,25 @@ struct PowerHalDeathRecipient : virtual public hardware::hidl_death_recipient { sp<PowerHalDeathRecipient> gDeathRecipient = new PowerHalDeathRecipient(); class WakeupCallback : public BnSuspendCallback { - public: - binder::Status notifyWakeup(bool success) override { +public: + binder::Status notifyWakeup(bool success, + const std::vector<std::string>& wakeupReasons) override { ALOGI("In wakeup_callback: %s", success ? "resumed from suspend" : "suspend aborted"); + bool reasonsCaptured = false; + { + std::unique_lock<std::mutex> reasonsLock(mReasonsMutex, std::defer_lock); + if (reasonsLock.try_lock() && mWakeupReasons.empty()) { + mWakeupReasons = std::move(wakeupReasons); + reasonsCaptured = true; + } + } + if (!reasonsCaptured) { + ALOGE("Failed to write wakeup reasons. Reasons dropped:"); + for (auto wakeupReason : wakeupReasons) { + ALOGE("\t%s", wakeupReason.c_str()); + } + } + int ret = sem_post(&wakeup_sem); if (ret < 0) { char buf[80]; @@ -157,8 +172,6 @@ static jint nativeWaitWakeup(JNIEnv *env, jobject clazz, jobject outBuf) // Wait for wakeup. ALOGV("Waiting for wakeup..."); - // TODO(b/116747600): device can suspend and wakeup after sem_wait() finishes and before wakeup - // reason is recorded, i.e. BatteryStats might occasionally miss wakeup events. int ret = sem_wait(&wakeup_sem); if (ret < 0) { char buf[80]; @@ -168,20 +181,27 @@ static jint nativeWaitWakeup(JNIEnv *env, jobject clazz, jobject outBuf) return 0; } - FILE *fp = fopen(LAST_RESUME_REASON, "r"); - if (fp == NULL) { - ALOGE("Failed to open %s", LAST_RESUME_REASON); - return -1; - } - char* mergedreason = (char*)env->GetDirectBufferAddress(outBuf); int remainreasonlen = (int)env->GetDirectBufferCapacity(outBuf); ALOGV("Reading wakeup reasons"); + std::vector<std::string> wakeupReasons; + { + std::unique_lock<std::mutex> reasonsLock(mReasonsMutex, std::defer_lock); + if (reasonsLock.try_lock() && !mWakeupReasons.empty()) { + wakeupReasons = std::move(mWakeupReasons); + mWakeupReasons.clear(); + } + } + + if (wakeupReasons.empty()) { + return 0; + } + char* mergedreasonpos = mergedreason; - char reasonline[128]; int i = 0; - while (fgets(reasonline, sizeof(reasonline), fp) != NULL) { + for (auto wakeupReason : wakeupReasons) { + auto reasonline = const_cast<char*>(wakeupReason.c_str()); char* pos = reasonline; char* endPos; int len; @@ -238,10 +258,6 @@ static jint nativeWaitWakeup(JNIEnv *env, jobject clazz, jobject outBuf) *mergedreasonpos = 0; } - if (fclose(fp) != 0) { - ALOGE("Failed to close %s", LAST_RESUME_REASON); - return -1; - } return mergedreasonpos - mergedreason; } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 411d8d60b7c4..9edd7fbbb84c 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -7894,7 +7894,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { // Current user has a managed-profile, but current user is not managed, so // rather than moving to finalized state, go back to unmanaged once // profile provisioning is complete. - if (newState == DevicePolicyManager.STATE_USER_UNMANAGED) { + if (newState == DevicePolicyManager.STATE_USER_PROFILE_FINALIZED) { return; } break; diff --git a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java index 0ab15017a2b4..c10b7b98bb5b 100644 --- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java @@ -252,6 +252,46 @@ public class LocalDisplayAdapterTest { } @Test + public void testAfterDisplayChange_ActiveModeIsUpdated() throws Exception { + SurfaceControl.DisplayConfig[] configs = new SurfaceControl.DisplayConfig[]{ + createFakeDisplayConfig(1920, 1080, 60f), + createFakeDisplayConfig(1920, 1080, 50f) + }; + FakeDisplay display = new FakeDisplay(PORT_A, configs, /* activeConfig */ 0); + setUpDisplay(display); + updateAvailableDisplays(); + mAdapter.registerLocked(); + waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS); + + assertThat(mListener.addedDisplays.size()).isEqualTo(1); + assertThat(mListener.changedDisplays).isEmpty(); + + DisplayDeviceInfo displayDeviceInfo = mListener.addedDisplays.get(0) + .getDisplayDeviceInfoLocked(); + + Display.Mode activeMode = getModeById(displayDeviceInfo, displayDeviceInfo.modeId); + assertThat(activeMode.matches(1920, 1080, 60f)).isTrue(); + + // Change the display + display.activeConfig = 1; + setUpDisplay(display); + mInjector.getTransmitter().sendHotplug(display, /* connected */ true); + waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS); + + assertThat(SurfaceControl.getActiveConfig(display.token)).isEqualTo(1); + + assertThat(mListener.addedDisplays.size()).isEqualTo(1); + assertThat(mListener.changedDisplays.size()).isEqualTo(1); + + DisplayDevice displayDevice = mListener.changedDisplays.get(0); + displayDevice.applyPendingDisplayDeviceInfoChangesLocked(); + displayDeviceInfo = displayDevice.getDisplayDeviceInfoLocked(); + + activeMode = getModeById(displayDeviceInfo, displayDeviceInfo.modeId); + assertThat(activeMode.matches(1920, 1080, 50f)).isTrue(); + } + + @Test public void testAfterDisplayChange_HdrCapabilitiesAreUpdated() throws Exception { FakeDisplay display = new FakeDisplay(PORT_A); Display.HdrCapabilities initialHdrCapabilities = new Display.HdrCapabilities(new int[0], 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 18bd6b17f340..79542084ac36 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java @@ -16,6 +16,7 @@ package com.android.server.job.controllers; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.inOrder; @@ -27,6 +28,7 @@ import static com.android.server.job.JobSchedulerService.ACTIVE_INDEX; import static com.android.server.job.JobSchedulerService.FREQUENT_INDEX; import static com.android.server.job.JobSchedulerService.NEVER_INDEX; import static com.android.server.job.JobSchedulerService.RARE_INDEX; +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; @@ -39,6 +41,7 @@ import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.never; @@ -68,6 +71,7 @@ import android.os.Handler; import android.os.Looper; import android.os.RemoteException; import android.os.SystemClock; +import android.provider.DeviceConfig; import android.util.SparseBooleanArray; import androidx.test.runner.AndroidJUnit4; @@ -78,6 +82,7 @@ import com.android.server.job.JobSchedulerService.Constants; import com.android.server.job.JobServiceContext; import com.android.server.job.JobStore; import com.android.server.job.controllers.QuotaController.ExecutionStats; +import com.android.server.job.controllers.QuotaController.QcConstants; import com.android.server.job.controllers.QuotaController.TimingSession; import com.android.server.usage.AppStandbyInternal; @@ -86,16 +91,19 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.ArgumentMatchers; import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoSession; import org.mockito.quality.Strictness; +import org.mockito.stubbing.Answer; import java.time.Clock; import java.time.Duration; import java.time.ZoneOffset; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.Executor; @RunWith(AndroidJUnit4.class) public class QuotaControllerTest { @@ -113,6 +121,7 @@ public class QuotaControllerTest { private QuotaController.QcConstants mQcConstants; private int mSourceUid; private IUidObserver mUidObserver; + DeviceConfig.Properties.Builder mDeviceConfigPropertiesBuilder; private MockitoSession mMockingSession; @Mock @@ -133,6 +142,7 @@ public class QuotaControllerTest { mMockingSession = mockitoSession() .initMocks(this) .strictness(Strictness.LENIENT) + .spyStatic(DeviceConfig.class) .mockStatic(LocalServices.class) .startMocking(); @@ -164,6 +174,18 @@ public class QuotaControllerTest { // Used in QuotaController.Handler. mJobStore = JobStore.initAndGetForTesting(mContext, mContext.getFilesDir()); when(mJobSchedulerService.getJobStore()).thenReturn(mJobStore); + // Used in QuotaController.QcConstants + doAnswer((Answer<Void>) invocationOnMock -> null) + .when(() -> DeviceConfig.addOnPropertiesChangedListener( + anyString(), any(Executor.class), + any(DeviceConfig.OnPropertiesChangedListener.class))); + mDeviceConfigPropertiesBuilder = + new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER); + doAnswer( + (Answer<DeviceConfig.Properties>) invocationOnMock + -> mDeviceConfigPropertiesBuilder.build()) + .when(() -> DeviceConfig.getProperties( + eq(DeviceConfig.NAMESPACE_JOB_SCHEDULER), ArgumentMatchers.<String>any())); // 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 @@ -285,7 +307,9 @@ public class QuotaControllerTest { private void trackJobs(JobStatus... jobs) { for (JobStatus job : jobs) { mJobStore.add(job); - mQuotaController.maybeStartTrackingJobLocked(job, null); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStartTrackingJobLocked(job, null); + } } } @@ -313,6 +337,22 @@ public class QuotaControllerTest { return new TimingSession(start, start + duration, count); } + private void setDeviceConfigLong(String key, long val) { + mDeviceConfigPropertiesBuilder.setLong(key, val); + synchronized (mQuotaController.mLock) { + mQuotaController.prepareForUpdatedConstantsLocked(); + mQcConstants.processConstantLocked(mDeviceConfigPropertiesBuilder.build(), key); + } + } + + private void setDeviceConfigInt(String key, int val) { + mDeviceConfigPropertiesBuilder.setInt(key, val); + synchronized (mQuotaController.mLock) { + mQuotaController.prepareForUpdatedConstantsLocked(); + mQcConstants.processConstantLocked(mDeviceConfigPropertiesBuilder.build(), key); + } + } + @Test public void testSaveTimingSession() { assertNull(mQuotaController.getTimingSessions(0, "com.android.test")); @@ -362,7 +402,9 @@ public class QuotaControllerTest { mQuotaController.saveTimingSession(0, "com.android.test", two); mQuotaController.saveTimingSession(0, "com.android.test", one); - mQuotaController.deleteObsoleteSessionsLocked(); + synchronized (mQuotaController.mLock) { + mQuotaController.deleteObsoleteSessionsLocked(); + } assertEquals(expected, mQuotaController.getTimingSessions(0, "com.android.test")); } @@ -396,15 +438,21 @@ public class QuotaControllerTest { expectedStats.sessionCountLimit = mQcConstants.MAX_SESSION_COUNT_RARE; final int uid = 10001; - mQuotaController.onAppRemovedLocked("com.android.test.remove", uid); + synchronized (mQuotaController.mLock) { + mQuotaController.onAppRemovedLocked("com.android.test.remove", uid); + } assertNull(mQuotaController.getTimingSessions(0, "com.android.test.remove")); assertEquals(expected, mQuotaController.getTimingSessions(0, "com.android.test.stay")); - assertEquals(expectedStats, - mQuotaController.getExecutionStatsLocked(0, "com.android.test.remove", RARE_INDEX)); - assertNotEquals(expectedStats, - mQuotaController.getExecutionStatsLocked(0, "com.android.test.stay", RARE_INDEX)); - - assertFalse(mQuotaController.getForegroundUids().get(uid)); + synchronized (mQuotaController.mLock) { + assertEquals(expectedStats, + mQuotaController.getExecutionStatsLocked( + 0, "com.android.test.remove", RARE_INDEX)); + assertNotEquals(expectedStats, + mQuotaController.getExecutionStatsLocked( + 0, "com.android.test.stay", RARE_INDEX)); + + assertFalse(mQuotaController.getForegroundUids().get(uid)); + } } @Test @@ -435,13 +483,15 @@ public class QuotaControllerTest { expectedStats.jobCountLimit = mQcConstants.MAX_JOB_COUNT_RARE; expectedStats.sessionCountLimit = mQcConstants.MAX_SESSION_COUNT_RARE; - mQuotaController.onUserRemovedLocked(0); - assertNull(mQuotaController.getTimingSessions(0, "com.android.test")); - assertEquals(expected, mQuotaController.getTimingSessions(10, "com.android.test")); - assertEquals(expectedStats, - mQuotaController.getExecutionStatsLocked(0, "com.android.test", RARE_INDEX)); - assertNotEquals(expectedStats, - mQuotaController.getExecutionStatsLocked(10, "com.android.test", RARE_INDEX)); + synchronized (mQuotaController.mLock) { + mQuotaController.onUserRemovedLocked(0); + assertNull(mQuotaController.getTimingSessions(0, "com.android.test")); + assertEquals(expected, mQuotaController.getTimingSessions(10, "com.android.test")); + assertEquals(expectedStats, + mQuotaController.getExecutionStatsLocked(0, "com.android.test", RARE_INDEX)); + assertNotEquals(expectedStats, + mQuotaController.getExecutionStatsLocked(10, "com.android.test", RARE_INDEX)); + } } @Test @@ -470,7 +520,9 @@ public class QuotaControllerTest { inputStats.sessionCountLimit = expectedStats.sessionCountLimit = 100; // Invalid time is now +24 hours since there are no sessions at all for the app. expectedStats.expirationTimeElapsed = now + 24 * HOUR_IN_MILLIS; - mQuotaController.updateExecutionStatsLocked(0, "com.android.test.not.run", inputStats); + synchronized (mQuotaController.mLock) { + mQuotaController.updateExecutionStatsLocked(0, "com.android.test.not.run", inputStats); + } assertEquals(expectedStats, inputStats); inputStats.windowSizeMs = expectedStats.windowSizeMs = MINUTE_IN_MILLIS; @@ -482,7 +534,9 @@ public class QuotaControllerTest { expectedStats.executionTimeInMaxPeriodMs = 22 * MINUTE_IN_MILLIS; expectedStats.bgJobCountInMaxPeriod = 15; expectedStats.sessionCountInWindow = 0; - mQuotaController.updateExecutionStatsLocked(0, "com.android.test", inputStats); + synchronized (mQuotaController.mLock) { + mQuotaController.updateExecutionStatsLocked(0, "com.android.test", inputStats); + } assertEquals(expectedStats, inputStats); inputStats.windowSizeMs = expectedStats.windowSizeMs = 3 * MINUTE_IN_MILLIS; @@ -493,7 +547,9 @@ public class QuotaControllerTest { expectedStats.executionTimeInMaxPeriodMs = 22 * MINUTE_IN_MILLIS; expectedStats.bgJobCountInMaxPeriod = 15; expectedStats.sessionCountInWindow = 1; - mQuotaController.updateExecutionStatsLocked(0, "com.android.test", inputStats); + synchronized (mQuotaController.mLock) { + mQuotaController.updateExecutionStatsLocked(0, "com.android.test", inputStats); + } assertEquals(expectedStats, inputStats); inputStats.windowSizeMs = expectedStats.windowSizeMs = 5 * MINUTE_IN_MILLIS; @@ -505,7 +561,9 @@ public class QuotaControllerTest { expectedStats.executionTimeInMaxPeriodMs = 22 * MINUTE_IN_MILLIS; expectedStats.bgJobCountInMaxPeriod = 15; expectedStats.sessionCountInWindow = 1; - mQuotaController.updateExecutionStatsLocked(0, "com.android.test", inputStats); + synchronized (mQuotaController.mLock) { + mQuotaController.updateExecutionStatsLocked(0, "com.android.test", inputStats); + } assertEquals(expectedStats, inputStats); inputStats.windowSizeMs = expectedStats.windowSizeMs = 49 * MINUTE_IN_MILLIS; @@ -517,7 +575,9 @@ public class QuotaControllerTest { expectedStats.executionTimeInMaxPeriodMs = 22 * MINUTE_IN_MILLIS; expectedStats.bgJobCountInMaxPeriod = 15; expectedStats.sessionCountInWindow = 1; - mQuotaController.updateExecutionStatsLocked(0, "com.android.test", inputStats); + synchronized (mQuotaController.mLock) { + mQuotaController.updateExecutionStatsLocked(0, "com.android.test", inputStats); + } assertEquals(expectedStats, inputStats); inputStats.windowSizeMs = expectedStats.windowSizeMs = 50 * MINUTE_IN_MILLIS; @@ -528,7 +588,9 @@ public class QuotaControllerTest { expectedStats.executionTimeInMaxPeriodMs = 22 * MINUTE_IN_MILLIS; expectedStats.bgJobCountInMaxPeriod = 15; expectedStats.sessionCountInWindow = 2; - mQuotaController.updateExecutionStatsLocked(0, "com.android.test", inputStats); + synchronized (mQuotaController.mLock) { + mQuotaController.updateExecutionStatsLocked(0, "com.android.test", inputStats); + } assertEquals(expectedStats, inputStats); inputStats.windowSizeMs = expectedStats.windowSizeMs = HOUR_IN_MILLIS; @@ -542,7 +604,9 @@ public class QuotaControllerTest { expectedStats.bgJobCountInMaxPeriod = 15; expectedStats.sessionCountInWindow = 3; expectedStats.inQuotaTimeElapsed = now + 11 * MINUTE_IN_MILLIS; - mQuotaController.updateExecutionStatsLocked(0, "com.android.test", inputStats); + synchronized (mQuotaController.mLock) { + mQuotaController.updateExecutionStatsLocked(0, "com.android.test", inputStats); + } assertEquals(expectedStats, inputStats); inputStats.windowSizeMs = expectedStats.windowSizeMs = 2 * HOUR_IN_MILLIS; @@ -556,7 +620,9 @@ public class QuotaControllerTest { expectedStats.bgJobCountInMaxPeriod = 15; expectedStats.sessionCountInWindow = 4; expectedStats.inQuotaTimeElapsed = now + 5 * MINUTE_IN_MILLIS; - mQuotaController.updateExecutionStatsLocked(0, "com.android.test", inputStats); + synchronized (mQuotaController.mLock) { + mQuotaController.updateExecutionStatsLocked(0, "com.android.test", inputStats); + } assertEquals(expectedStats, inputStats); inputStats.windowSizeMs = expectedStats.windowSizeMs = 3 * HOUR_IN_MILLIS; @@ -571,7 +637,9 @@ public class QuotaControllerTest { // App goes under job execution time limit in ~61 minutes, but will be under job count limit // in 65 minutes. expectedStats.inQuotaTimeElapsed = now + 65 * MINUTE_IN_MILLIS; - mQuotaController.updateExecutionStatsLocked(0, "com.android.test", inputStats); + synchronized (mQuotaController.mLock) { + mQuotaController.updateExecutionStatsLocked(0, "com.android.test", inputStats); + } assertEquals(expectedStats, inputStats); inputStats.windowSizeMs = expectedStats.windowSizeMs = 6 * HOUR_IN_MILLIS; @@ -584,7 +652,9 @@ public class QuotaControllerTest { expectedStats.bgJobCountInMaxPeriod = 15; expectedStats.sessionCountInWindow = 5; expectedStats.inQuotaTimeElapsed = now + 4 * HOUR_IN_MILLIS + 5 * MINUTE_IN_MILLIS; - mQuotaController.updateExecutionStatsLocked(0, "com.android.test", inputStats); + synchronized (mQuotaController.mLock) { + mQuotaController.updateExecutionStatsLocked(0, "com.android.test", inputStats); + } assertEquals(expectedStats, inputStats); // Make sure expirationTimeElapsed is set correctly when it's dependent on the max period. @@ -603,7 +673,9 @@ public class QuotaControllerTest { expectedStats.sessionCountInWindow = 5; expectedStats.inQuotaTimeElapsed = now + 6 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS + mQcConstants.IN_QUOTA_BUFFER_MS; - mQuotaController.updateExecutionStatsLocked(0, "com.android.test", inputStats); + synchronized (mQuotaController.mLock) { + mQuotaController.updateExecutionStatsLocked(0, "com.android.test", inputStats); + } assertEquals(expectedStats, inputStats); mQuotaController.getTimingSessions(0, "com.android.test") @@ -620,7 +692,9 @@ public class QuotaControllerTest { expectedStats.sessionCountInWindow = 5; expectedStats.inQuotaTimeElapsed = now + 6 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS + mQcConstants.IN_QUOTA_BUFFER_MS; - mQuotaController.updateExecutionStatsLocked(0, "com.android.test", inputStats); + synchronized (mQuotaController.mLock) { + mQuotaController.updateExecutionStatsLocked(0, "com.android.test", inputStats); + } assertEquals(expectedStats, inputStats); } @@ -641,18 +715,23 @@ public class QuotaControllerTest { for (int i = 1; i < mQcConstants.MAX_JOB_COUNT_RARE; ++i) { JobStatus jobStatus = createJobStatus("testUpdateExecutionStatsLocked_WithTimer", i); setStandbyBucket(RARE_INDEX, jobStatus); // 24 hour window - mQuotaController.maybeStartTrackingJobLocked(jobStatus, null); - mQuotaController.prepareForExecutionLocked(jobStatus); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStartTrackingJobLocked(jobStatus, null); + mQuotaController.prepareForExecutionLocked(jobStatus); + } advanceElapsedClock(7000); expectedStats.expirationTimeElapsed = sElapsedRealtimeClock.millis(); expectedStats.executionTimeInWindowMs = expectedStats.executionTimeInMaxPeriodMs = 7000 * i; expectedStats.bgJobCountInWindow = expectedStats.bgJobCountInMaxPeriod = i; - mQuotaController.updateExecutionStatsLocked(SOURCE_USER_ID, SOURCE_PACKAGE, inputStats); - assertEquals(expectedStats, inputStats); - assertTrue(mQuotaController.isWithinQuotaLocked(SOURCE_USER_ID, SOURCE_PACKAGE, - RARE_INDEX)); + synchronized (mQuotaController.mLock) { + mQuotaController.updateExecutionStatsLocked( + SOURCE_USER_ID, SOURCE_PACKAGE, inputStats); + assertEquals(expectedStats, inputStats); + assertTrue(mQuotaController.isWithinQuotaLocked( + SOURCE_USER_ID, SOURCE_PACKAGE, RARE_INDEX)); + } assertTrue("Job not ready: " + jobStatus, jobStatus.isReady()); } @@ -670,16 +749,21 @@ public class QuotaControllerTest { // Active timer is under quota, so out of quota due to old session. expectedStats.inQuotaTimeElapsed = sElapsedRealtimeClock.millis() + 18 * HOUR_IN_MILLIS + 10 * MINUTE_IN_MILLIS; - mQuotaController.updateExecutionStatsLocked(SOURCE_USER_ID, SOURCE_PACKAGE, inputStats); - assertEquals(expectedStats, inputStats); - assertFalse( - mQuotaController.isWithinQuotaLocked(SOURCE_USER_ID, SOURCE_PACKAGE, RARE_INDEX)); + synchronized (mQuotaController.mLock) { + mQuotaController.updateExecutionStatsLocked(SOURCE_USER_ID, SOURCE_PACKAGE, inputStats); + assertEquals(expectedStats, inputStats); + assertFalse( + mQuotaController.isWithinQuotaLocked( + SOURCE_USER_ID, SOURCE_PACKAGE, RARE_INDEX)); + } // Quota should be exceeded due to activity in active timer. JobStatus jobStatus = createJobStatus("testUpdateExecutionStatsLocked_WithTimer", 0); setStandbyBucket(RARE_INDEX, jobStatus); // 24 hour window - mQuotaController.maybeStartTrackingJobLocked(jobStatus, null); - mQuotaController.prepareForExecutionLocked(jobStatus); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStartTrackingJobLocked(jobStatus, null); + mQuotaController.prepareForExecutionLocked(jobStatus); + } advanceElapsedClock(10000); expectedStats.executionTimeInWindowMs += 10000; @@ -690,11 +774,14 @@ public class QuotaControllerTest { // time has passed since active timer. expectedStats.inQuotaTimeElapsed = sElapsedRealtimeClock.millis() + expectedStats.windowSizeMs; - mQuotaController.updateExecutionStatsLocked(SOURCE_USER_ID, SOURCE_PACKAGE, inputStats); - assertEquals(expectedStats, inputStats); - assertFalse( - mQuotaController.isWithinQuotaLocked(SOURCE_USER_ID, SOURCE_PACKAGE, RARE_INDEX)); - assertFalse("Job unexpectedly ready: " + jobStatus, jobStatus.isReady()); + synchronized (mQuotaController.mLock) { + mQuotaController.updateExecutionStatsLocked(SOURCE_USER_ID, SOURCE_PACKAGE, inputStats); + assertEquals(expectedStats, inputStats); + assertFalse( + mQuotaController.isWithinQuotaLocked( + SOURCE_USER_ID, SOURCE_PACKAGE, RARE_INDEX)); + assertFalse("Job unexpectedly ready: " + jobStatus, jobStatus.isReady()); + } } /** @@ -724,8 +811,10 @@ public class QuotaControllerTest { expectedStats.executionTimeInMaxPeriodMs = 33 * MINUTE_IN_MILLIS; expectedStats.bgJobCountInMaxPeriod = 20; expectedStats.sessionCountInWindow = 1; - assertEquals(expectedStats, - mQuotaController.getExecutionStatsLocked(0, "com.android.test", ACTIVE_INDEX)); + synchronized (mQuotaController.mLock) { + assertEquals(expectedStats, + mQuotaController.getExecutionStatsLocked(0, "com.android.test", ACTIVE_INDEX)); + } // Working expectedStats.windowSizeMs = 2 * HOUR_IN_MILLIS; @@ -739,8 +828,10 @@ public class QuotaControllerTest { expectedStats.sessionCountInWindow = 2; expectedStats.inQuotaTimeElapsed = now + 3 * MINUTE_IN_MILLIS + mQcConstants.IN_QUOTA_BUFFER_MS; - assertEquals(expectedStats, - mQuotaController.getExecutionStatsLocked(0, "com.android.test", WORKING_INDEX)); + synchronized (mQuotaController.mLock) { + assertEquals(expectedStats, + mQuotaController.getExecutionStatsLocked(0, "com.android.test", WORKING_INDEX)); + } // Frequent expectedStats.windowSizeMs = 8 * HOUR_IN_MILLIS; @@ -754,8 +845,11 @@ public class QuotaControllerTest { expectedStats.sessionCountInWindow = 3; expectedStats.inQuotaTimeElapsed = now + 6 * HOUR_IN_MILLIS + 3 * MINUTE_IN_MILLIS + mQcConstants.IN_QUOTA_BUFFER_MS; - assertEquals(expectedStats, - mQuotaController.getExecutionStatsLocked(0, "com.android.test", FREQUENT_INDEX)); + synchronized (mQuotaController.mLock) { + assertEquals(expectedStats, + mQuotaController.getExecutionStatsLocked( + 0, "com.android.test", FREQUENT_INDEX)); + } // Rare expectedStats.windowSizeMs = 24 * HOUR_IN_MILLIS; @@ -769,8 +863,10 @@ public class QuotaControllerTest { expectedStats.sessionCountInWindow = 4; expectedStats.inQuotaTimeElapsed = now + 22 * HOUR_IN_MILLIS + 3 * MINUTE_IN_MILLIS + mQcConstants.IN_QUOTA_BUFFER_MS; - assertEquals(expectedStats, - mQuotaController.getExecutionStatsLocked(0, "com.android.test", RARE_INDEX)); + synchronized (mQuotaController.mLock) { + assertEquals(expectedStats, + mQuotaController.getExecutionStatsLocked(0, "com.android.test", RARE_INDEX)); + } } /** @@ -797,32 +893,41 @@ public class QuotaControllerTest { expectedStats.executionTimeInMaxPeriodMs = MINUTE_IN_MILLIS; expectedStats.bgJobCountInMaxPeriod = 2; expectedStats.sessionCountInWindow = 1; - assertEquals(expectedStats, - mQuotaController.getExecutionStatsLocked(0, "com.android.test", ACTIVE_INDEX)); + synchronized (mQuotaController.mLock) { + assertEquals(expectedStats, + mQuotaController.getExecutionStatsLocked(0, "com.android.test", ACTIVE_INDEX)); + } // Working expectedStats.windowSizeMs = 2 * HOUR_IN_MILLIS; expectedStats.jobCountLimit = mQcConstants.MAX_JOB_COUNT_WORKING; expectedStats.sessionCountLimit = mQcConstants.MAX_SESSION_COUNT_WORKING; expectedStats.expirationTimeElapsed = 2 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS; - assertEquals(expectedStats, - mQuotaController.getExecutionStatsLocked(0, "com.android.test", WORKING_INDEX)); + synchronized (mQuotaController.mLock) { + assertEquals(expectedStats, + mQuotaController.getExecutionStatsLocked(0, "com.android.test", WORKING_INDEX)); + } // Frequent expectedStats.windowSizeMs = 8 * HOUR_IN_MILLIS; expectedStats.jobCountLimit = mQcConstants.MAX_JOB_COUNT_FREQUENT; expectedStats.sessionCountLimit = mQcConstants.MAX_SESSION_COUNT_FREQUENT; expectedStats.expirationTimeElapsed = 8 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS; - assertEquals(expectedStats, - mQuotaController.getExecutionStatsLocked(0, "com.android.test", FREQUENT_INDEX)); + synchronized (mQuotaController.mLock) { + assertEquals(expectedStats, + mQuotaController.getExecutionStatsLocked( + 0, "com.android.test", FREQUENT_INDEX)); + } // Rare expectedStats.windowSizeMs = 24 * HOUR_IN_MILLIS; expectedStats.jobCountLimit = mQcConstants.MAX_JOB_COUNT_RARE; expectedStats.sessionCountLimit = mQcConstants.MAX_SESSION_COUNT_RARE; expectedStats.expirationTimeElapsed = 24 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS; - assertEquals(expectedStats, - mQuotaController.getExecutionStatsLocked(0, "com.android.test", RARE_INDEX)); + synchronized (mQuotaController.mLock) { + assertEquals(expectedStats, + mQuotaController.getExecutionStatsLocked(0, "com.android.test", RARE_INDEX)); + } } /** @@ -858,111 +963,123 @@ public class QuotaControllerTest { advanceElapsedClock(40 * MINUTE_IN_MILLIS); } - mQcConstants.TIMING_SESSION_COALESCING_DURATION_MS = 0; - mQcConstants.updateConstants(); - - mQuotaController.invalidateAllExecutionStatsLocked(); - assertEquals(0, mQuotaController.getExecutionStatsLocked( - 0, "com.android.test", ACTIVE_INDEX).sessionCountInWindow); - assertEquals(32, mQuotaController.getExecutionStatsLocked( - 0, "com.android.test", WORKING_INDEX).sessionCountInWindow); - assertEquals(128, mQuotaController.getExecutionStatsLocked( - 0, "com.android.test", FREQUENT_INDEX).sessionCountInWindow); - assertEquals(160, mQuotaController.getExecutionStatsLocked( - 0, "com.android.test", RARE_INDEX).sessionCountInWindow); - - mQcConstants.TIMING_SESSION_COALESCING_DURATION_MS = 500; - mQcConstants.updateConstants(); - - mQuotaController.invalidateAllExecutionStatsLocked(); - assertEquals(0, mQuotaController.getExecutionStatsLocked( - 0, "com.android.test", ACTIVE_INDEX).sessionCountInWindow); - assertEquals(22, mQuotaController.getExecutionStatsLocked( - 0, "com.android.test", WORKING_INDEX).sessionCountInWindow); - assertEquals(88, mQuotaController.getExecutionStatsLocked( - 0, "com.android.test", FREQUENT_INDEX).sessionCountInWindow); - assertEquals(110, mQuotaController.getExecutionStatsLocked( - 0, "com.android.test", RARE_INDEX).sessionCountInWindow); - - mQcConstants.TIMING_SESSION_COALESCING_DURATION_MS = 1000; - mQcConstants.updateConstants(); - - mQuotaController.invalidateAllExecutionStatsLocked(); - assertEquals(0, mQuotaController.getExecutionStatsLocked( - 0, "com.android.test", ACTIVE_INDEX).sessionCountInWindow); - assertEquals(22, mQuotaController.getExecutionStatsLocked( - 0, "com.android.test", WORKING_INDEX).sessionCountInWindow); - assertEquals(88, mQuotaController.getExecutionStatsLocked( - 0, "com.android.test", FREQUENT_INDEX).sessionCountInWindow); - assertEquals(110, mQuotaController.getExecutionStatsLocked( - 0, "com.android.test", RARE_INDEX).sessionCountInWindow); - - mQcConstants.TIMING_SESSION_COALESCING_DURATION_MS = 5 * SECOND_IN_MILLIS; - mQcConstants.updateConstants(); - - mQuotaController.invalidateAllExecutionStatsLocked(); - assertEquals(0, mQuotaController.getExecutionStatsLocked( - 0, "com.android.test", ACTIVE_INDEX).sessionCountInWindow); - assertEquals(14, mQuotaController.getExecutionStatsLocked( - 0, "com.android.test", WORKING_INDEX).sessionCountInWindow); - assertEquals(56, mQuotaController.getExecutionStatsLocked( - 0, "com.android.test", FREQUENT_INDEX).sessionCountInWindow); - assertEquals(70, mQuotaController.getExecutionStatsLocked( - 0, "com.android.test", RARE_INDEX).sessionCountInWindow); - - mQcConstants.TIMING_SESSION_COALESCING_DURATION_MS = MINUTE_IN_MILLIS; - mQcConstants.updateConstants(); - - mQuotaController.invalidateAllExecutionStatsLocked(); - assertEquals(0, mQuotaController.getExecutionStatsLocked( - 0, "com.android.test", ACTIVE_INDEX).sessionCountInWindow); - assertEquals(4, mQuotaController.getExecutionStatsLocked( - 0, "com.android.test", WORKING_INDEX).sessionCountInWindow); - assertEquals(16, mQuotaController.getExecutionStatsLocked( - 0, "com.android.test", FREQUENT_INDEX).sessionCountInWindow); - assertEquals(20, mQuotaController.getExecutionStatsLocked( - 0, "com.android.test", RARE_INDEX).sessionCountInWindow); - - mQcConstants.TIMING_SESSION_COALESCING_DURATION_MS = 5 * MINUTE_IN_MILLIS; - mQcConstants.updateConstants(); - - mQuotaController.invalidateAllExecutionStatsLocked(); - assertEquals(0, mQuotaController.getExecutionStatsLocked( - 0, "com.android.test", ACTIVE_INDEX).sessionCountInWindow); - assertEquals(2, mQuotaController.getExecutionStatsLocked( - 0, "com.android.test", WORKING_INDEX).sessionCountInWindow); - assertEquals(8, mQuotaController.getExecutionStatsLocked( - 0, "com.android.test", FREQUENT_INDEX).sessionCountInWindow); - assertEquals(10, mQuotaController.getExecutionStatsLocked( - 0, "com.android.test", RARE_INDEX).sessionCountInWindow); - - mQcConstants.TIMING_SESSION_COALESCING_DURATION_MS = 15 * MINUTE_IN_MILLIS; - mQcConstants.updateConstants(); - - mQuotaController.invalidateAllExecutionStatsLocked(); - assertEquals(0, mQuotaController.getExecutionStatsLocked( - 0, "com.android.test", ACTIVE_INDEX).sessionCountInWindow); - assertEquals(2, mQuotaController.getExecutionStatsLocked( - 0, "com.android.test", WORKING_INDEX).sessionCountInWindow); - assertEquals(8, mQuotaController.getExecutionStatsLocked( - 0, "com.android.test", FREQUENT_INDEX).sessionCountInWindow); - assertEquals(10, mQuotaController.getExecutionStatsLocked( - 0, "com.android.test", RARE_INDEX).sessionCountInWindow); + setDeviceConfigLong(QcConstants.KEY_TIMING_SESSION_COALESCING_DURATION_MS, 0); + + synchronized (mQuotaController.mLock) { + mQuotaController.invalidateAllExecutionStatsLocked(); + assertEquals(0, mQuotaController.getExecutionStatsLocked( + 0, "com.android.test", ACTIVE_INDEX).sessionCountInWindow); + assertEquals(32, mQuotaController.getExecutionStatsLocked( + 0, "com.android.test", WORKING_INDEX).sessionCountInWindow); + assertEquals(128, mQuotaController.getExecutionStatsLocked( + 0, "com.android.test", FREQUENT_INDEX).sessionCountInWindow); + assertEquals(160, mQuotaController.getExecutionStatsLocked( + 0, "com.android.test", RARE_INDEX).sessionCountInWindow); + } + + setDeviceConfigLong(QcConstants.KEY_TIMING_SESSION_COALESCING_DURATION_MS, 500); + + synchronized (mQuotaController.mLock) { + mQuotaController.invalidateAllExecutionStatsLocked(); + assertEquals(0, mQuotaController.getExecutionStatsLocked( + 0, "com.android.test", ACTIVE_INDEX).sessionCountInWindow); + assertEquals(22, mQuotaController.getExecutionStatsLocked( + 0, "com.android.test", WORKING_INDEX).sessionCountInWindow); + assertEquals(88, mQuotaController.getExecutionStatsLocked( + 0, "com.android.test", FREQUENT_INDEX).sessionCountInWindow); + assertEquals(110, mQuotaController.getExecutionStatsLocked( + 0, "com.android.test", RARE_INDEX).sessionCountInWindow); + } + + setDeviceConfigLong(QcConstants.KEY_TIMING_SESSION_COALESCING_DURATION_MS, 1000); + + synchronized (mQuotaController.mLock) { + mQuotaController.invalidateAllExecutionStatsLocked(); + assertEquals(0, mQuotaController.getExecutionStatsLocked( + 0, "com.android.test", ACTIVE_INDEX).sessionCountInWindow); + assertEquals(22, mQuotaController.getExecutionStatsLocked( + 0, "com.android.test", WORKING_INDEX).sessionCountInWindow); + assertEquals(88, mQuotaController.getExecutionStatsLocked( + 0, "com.android.test", FREQUENT_INDEX).sessionCountInWindow); + assertEquals(110, mQuotaController.getExecutionStatsLocked( + 0, "com.android.test", RARE_INDEX).sessionCountInWindow); + } + + setDeviceConfigLong(QcConstants.KEY_TIMING_SESSION_COALESCING_DURATION_MS, + 5 * SECOND_IN_MILLIS); + + synchronized (mQuotaController.mLock) { + mQuotaController.invalidateAllExecutionStatsLocked(); + assertEquals(0, mQuotaController.getExecutionStatsLocked( + 0, "com.android.test", ACTIVE_INDEX).sessionCountInWindow); + assertEquals(14, mQuotaController.getExecutionStatsLocked( + 0, "com.android.test", WORKING_INDEX).sessionCountInWindow); + assertEquals(56, mQuotaController.getExecutionStatsLocked( + 0, "com.android.test", FREQUENT_INDEX).sessionCountInWindow); + assertEquals(70, mQuotaController.getExecutionStatsLocked( + 0, "com.android.test", RARE_INDEX).sessionCountInWindow); + } + + setDeviceConfigLong(QcConstants.KEY_TIMING_SESSION_COALESCING_DURATION_MS, + MINUTE_IN_MILLIS); + + synchronized (mQuotaController.mLock) { + mQuotaController.invalidateAllExecutionStatsLocked(); + assertEquals(0, mQuotaController.getExecutionStatsLocked( + 0, "com.android.test", ACTIVE_INDEX).sessionCountInWindow); + assertEquals(4, mQuotaController.getExecutionStatsLocked( + 0, "com.android.test", WORKING_INDEX).sessionCountInWindow); + assertEquals(16, mQuotaController.getExecutionStatsLocked( + 0, "com.android.test", FREQUENT_INDEX).sessionCountInWindow); + assertEquals(20, mQuotaController.getExecutionStatsLocked( + 0, "com.android.test", RARE_INDEX).sessionCountInWindow); + } + + setDeviceConfigLong(QcConstants.KEY_TIMING_SESSION_COALESCING_DURATION_MS, + 5 * MINUTE_IN_MILLIS); + + synchronized (mQuotaController.mLock) { + mQuotaController.invalidateAllExecutionStatsLocked(); + assertEquals(0, mQuotaController.getExecutionStatsLocked( + 0, "com.android.test", ACTIVE_INDEX).sessionCountInWindow); + assertEquals(2, mQuotaController.getExecutionStatsLocked( + 0, "com.android.test", WORKING_INDEX).sessionCountInWindow); + assertEquals(8, mQuotaController.getExecutionStatsLocked( + 0, "com.android.test", FREQUENT_INDEX).sessionCountInWindow); + assertEquals(10, mQuotaController.getExecutionStatsLocked( + 0, "com.android.test", RARE_INDEX).sessionCountInWindow); + } + + setDeviceConfigLong(QcConstants.KEY_TIMING_SESSION_COALESCING_DURATION_MS, + 15 * MINUTE_IN_MILLIS); + + synchronized (mQuotaController.mLock) { + mQuotaController.invalidateAllExecutionStatsLocked(); + assertEquals(0, mQuotaController.getExecutionStatsLocked( + 0, "com.android.test", ACTIVE_INDEX).sessionCountInWindow); + assertEquals(2, mQuotaController.getExecutionStatsLocked( + 0, "com.android.test", WORKING_INDEX).sessionCountInWindow); + assertEquals(8, mQuotaController.getExecutionStatsLocked( + 0, "com.android.test", FREQUENT_INDEX).sessionCountInWindow); + assertEquals(10, mQuotaController.getExecutionStatsLocked( + 0, "com.android.test", RARE_INDEX).sessionCountInWindow); + } // QuotaController caps the duration at 15 minutes, so there shouldn't be any difference // between an hour and 15 minutes. - mQcConstants.TIMING_SESSION_COALESCING_DURATION_MS = HOUR_IN_MILLIS; - mQcConstants.updateConstants(); - - mQuotaController.invalidateAllExecutionStatsLocked(); - assertEquals(0, mQuotaController.getExecutionStatsLocked( - 0, "com.android.test", ACTIVE_INDEX).sessionCountInWindow); - assertEquals(2, mQuotaController.getExecutionStatsLocked( - 0, "com.android.test", WORKING_INDEX).sessionCountInWindow); - assertEquals(8, mQuotaController.getExecutionStatsLocked( - 0, "com.android.test", FREQUENT_INDEX).sessionCountInWindow); - assertEquals(10, mQuotaController.getExecutionStatsLocked( - 0, "com.android.test", RARE_INDEX).sessionCountInWindow); + setDeviceConfigLong(QcConstants.KEY_TIMING_SESSION_COALESCING_DURATION_MS, HOUR_IN_MILLIS); + + synchronized (mQuotaController.mLock) { + mQuotaController.invalidateAllExecutionStatsLocked(); + assertEquals(0, mQuotaController.getExecutionStatsLocked( + 0, "com.android.test", ACTIVE_INDEX).sessionCountInWindow); + assertEquals(2, mQuotaController.getExecutionStatsLocked( + 0, "com.android.test", WORKING_INDEX).sessionCountInWindow); + assertEquals(8, mQuotaController.getExecutionStatsLocked( + 0, "com.android.test", FREQUENT_INDEX).sessionCountInWindow); + assertEquals(10, mQuotaController.getExecutionStatsLocked( + 0, "com.android.test", RARE_INDEX).sessionCountInWindow); + } } /** @@ -982,20 +1099,25 @@ public class QuotaControllerTest { createTimingSession(now - (2 * HOUR_IN_MILLIS), 10 * MINUTE_IN_MILLIS, 5)); mQuotaController.saveTimingSession(0, "com.android.test", createTimingSession(now - (6 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5)); - final ExecutionStats originalStatsActive = mQuotaController.getExecutionStatsLocked(0, - "com.android.test", ACTIVE_INDEX); - final ExecutionStats originalStatsWorking = mQuotaController.getExecutionStatsLocked(0, - "com.android.test", WORKING_INDEX); - final ExecutionStats originalStatsFrequent = mQuotaController.getExecutionStatsLocked(0, - "com.android.test", FREQUENT_INDEX); - final ExecutionStats originalStatsRare = mQuotaController.getExecutionStatsLocked(0, - "com.android.test", RARE_INDEX); + final ExecutionStats originalStatsActive; + final ExecutionStats originalStatsWorking; + final ExecutionStats originalStatsFrequent; + final ExecutionStats originalStatsRare; + synchronized (mQuotaController.mLock) { + originalStatsActive = mQuotaController.getExecutionStatsLocked( + 0, "com.android.test", ACTIVE_INDEX); + originalStatsWorking = mQuotaController.getExecutionStatsLocked( + 0, "com.android.test", WORKING_INDEX); + originalStatsFrequent = mQuotaController.getExecutionStatsLocked( + 0, "com.android.test", FREQUENT_INDEX); + originalStatsRare = mQuotaController.getExecutionStatsLocked( + 0, "com.android.test", RARE_INDEX); + } // Advance clock so that the working stats shouldn't be the same. advanceElapsedClock(MINUTE_IN_MILLIS); // Change frequent bucket size so that the stats need to be recalculated. - mQcConstants.WINDOW_SIZE_FREQUENT_MS = 6 * HOUR_IN_MILLIS; - mQcConstants.updateConstants(); + setDeviceConfigLong(QcConstants.KEY_WINDOW_SIZE_FREQUENT_MS, 6 * HOUR_IN_MILLIS); ExecutionStats expectedStats = new ExecutionStats(); expectedStats.windowSizeMs = originalStatsActive.windowSizeMs; @@ -1008,8 +1130,11 @@ public class QuotaControllerTest { expectedStats.bgJobCountInMaxPeriod = originalStatsActive.bgJobCountInMaxPeriod; expectedStats.sessionCountInWindow = originalStatsActive.sessionCountInWindow; expectedStats.inQuotaTimeElapsed = originalStatsActive.inQuotaTimeElapsed; - final ExecutionStats newStatsActive = mQuotaController.getExecutionStatsLocked(0, - "com.android.test", ACTIVE_INDEX); + final ExecutionStats newStatsActive; + synchronized (mQuotaController.mLock) { + newStatsActive = mQuotaController.getExecutionStatsLocked( + 0, "com.android.test", ACTIVE_INDEX); + } // Stats for the same bucket should use the same object. assertTrue(originalStatsActive == newStatsActive); assertEquals(expectedStats, newStatsActive); @@ -1022,8 +1147,11 @@ public class QuotaControllerTest { expectedStats.bgJobCountInWindow = originalStatsWorking.bgJobCountInWindow; expectedStats.sessionCountInWindow = originalStatsWorking.sessionCountInWindow; expectedStats.inQuotaTimeElapsed = originalStatsWorking.inQuotaTimeElapsed; - final ExecutionStats newStatsWorking = mQuotaController.getExecutionStatsLocked(0, - "com.android.test", WORKING_INDEX); + final ExecutionStats newStatsWorking; + synchronized (mQuotaController.mLock) { + newStatsWorking = mQuotaController.getExecutionStatsLocked( + 0, "com.android.test", WORKING_INDEX); + } assertTrue(originalStatsWorking == newStatsWorking); assertNotEquals(expectedStats, newStatsWorking); @@ -1035,8 +1163,11 @@ public class QuotaControllerTest { expectedStats.bgJobCountInWindow = originalStatsFrequent.bgJobCountInWindow; expectedStats.sessionCountInWindow = originalStatsFrequent.sessionCountInWindow; expectedStats.inQuotaTimeElapsed = originalStatsFrequent.inQuotaTimeElapsed; - final ExecutionStats newStatsFrequent = mQuotaController.getExecutionStatsLocked(0, - "com.android.test", FREQUENT_INDEX); + final ExecutionStats newStatsFrequent; + synchronized (mQuotaController.mLock) { + newStatsFrequent = mQuotaController.getExecutionStatsLocked( + 0, "com.android.test", FREQUENT_INDEX); + } assertTrue(originalStatsFrequent == newStatsFrequent); assertNotEquals(expectedStats, newStatsFrequent); @@ -1048,8 +1179,11 @@ public class QuotaControllerTest { expectedStats.bgJobCountInWindow = originalStatsRare.bgJobCountInWindow; expectedStats.sessionCountInWindow = originalStatsRare.sessionCountInWindow; expectedStats.inQuotaTimeElapsed = originalStatsRare.inQuotaTimeElapsed; - final ExecutionStats newStatsRare = mQuotaController.getExecutionStatsLocked(0, - "com.android.test", RARE_INDEX); + final ExecutionStats newStatsRare; + synchronized (mQuotaController.mLock) { + newStatsRare = mQuotaController.getExecutionStatsLocked( + 0, "com.android.test", RARE_INDEX); + } assertTrue(originalStatsRare == newStatsRare); assertEquals(expectedStats, newStatsRare); } @@ -1063,26 +1197,36 @@ public class QuotaControllerTest { job.setStandbyBucket(RARE_INDEX); setCharging(); - assertEquals(JobServiceContext.EXECUTING_TIMESLICE_MILLIS, - mQuotaController.getMaxJobExecutionTimeMsLocked((job))); + synchronized (mQuotaController.mLock) { + assertEquals(JobServiceContext.EXECUTING_TIMESLICE_MILLIS, + mQuotaController.getMaxJobExecutionTimeMsLocked((job))); + } setDischarging(); setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE); - assertEquals(JobServiceContext.EXECUTING_TIMESLICE_MILLIS, - mQuotaController.getMaxJobExecutionTimeMsLocked((job))); + synchronized (mQuotaController.mLock) { + assertEquals(JobServiceContext.EXECUTING_TIMESLICE_MILLIS, + mQuotaController.getMaxJobExecutionTimeMsLocked((job))); + } // Top-started job setProcessState(ActivityManager.PROCESS_STATE_TOP); - mQuotaController.maybeStartTrackingJobLocked(job, null); - mQuotaController.prepareForExecutionLocked(job); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStartTrackingJobLocked(job, null); + mQuotaController.prepareForExecutionLocked(job); + } setProcessState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND); - assertEquals(JobServiceContext.EXECUTING_TIMESLICE_MILLIS, - mQuotaController.getMaxJobExecutionTimeMsLocked((job))); - mQuotaController.maybeStopTrackingJobLocked(job, null, false); + synchronized (mQuotaController.mLock) { + assertEquals(JobServiceContext.EXECUTING_TIMESLICE_MILLIS, + mQuotaController.getMaxJobExecutionTimeMsLocked((job))); + mQuotaController.maybeStopTrackingJobLocked(job, null, false); + } setProcessState(ActivityManager.PROCESS_STATE_RECEIVER); - assertEquals(7 * MINUTE_IN_MILLIS, - mQuotaController.getMaxJobExecutionTimeMsLocked(job)); + synchronized (mQuotaController.mLock) { + assertEquals(7 * MINUTE_IN_MILLIS, + mQuotaController.getMaxJobExecutionTimeMsLocked(job)); + } } /** @@ -1108,30 +1252,46 @@ public class QuotaControllerTest { createTimingSession(now - (9 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5)); setStandbyBucket(RARE_INDEX); - assertEquals(30 * SECOND_IN_MILLIS, - mQuotaController.getRemainingExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE)); - assertEquals(MINUTE_IN_MILLIS, - mQuotaController.getTimeUntilQuotaConsumedLocked(SOURCE_USER_ID, SOURCE_PACKAGE)); + synchronized (mQuotaController.mLock) { + assertEquals(30 * SECOND_IN_MILLIS, + mQuotaController.getRemainingExecutionTimeLocked( + SOURCE_USER_ID, SOURCE_PACKAGE)); + assertEquals(MINUTE_IN_MILLIS, + mQuotaController.getTimeUntilQuotaConsumedLocked( + SOURCE_USER_ID, SOURCE_PACKAGE)); + } setStandbyBucket(FREQUENT_INDEX); - assertEquals(MINUTE_IN_MILLIS, - mQuotaController.getRemainingExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE)); - assertEquals(MINUTE_IN_MILLIS, - mQuotaController.getTimeUntilQuotaConsumedLocked(SOURCE_USER_ID, SOURCE_PACKAGE)); + synchronized (mQuotaController.mLock) { + assertEquals(MINUTE_IN_MILLIS, + mQuotaController.getRemainingExecutionTimeLocked( + SOURCE_USER_ID, SOURCE_PACKAGE)); + assertEquals(MINUTE_IN_MILLIS, + mQuotaController.getTimeUntilQuotaConsumedLocked( + SOURCE_USER_ID, SOURCE_PACKAGE)); + } setStandbyBucket(WORKING_INDEX); - assertEquals(5 * MINUTE_IN_MILLIS, - mQuotaController.getRemainingExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE)); - assertEquals(7 * MINUTE_IN_MILLIS, - mQuotaController.getTimeUntilQuotaConsumedLocked(SOURCE_USER_ID, SOURCE_PACKAGE)); + synchronized (mQuotaController.mLock) { + assertEquals(5 * MINUTE_IN_MILLIS, + mQuotaController.getRemainingExecutionTimeLocked( + SOURCE_USER_ID, SOURCE_PACKAGE)); + assertEquals(7 * MINUTE_IN_MILLIS, + mQuotaController.getTimeUntilQuotaConsumedLocked( + SOURCE_USER_ID, SOURCE_PACKAGE)); + } // ACTIVE window = allowed time, so jobs can essentially run non-stop until they reach the // max execution time. setStandbyBucket(ACTIVE_INDEX); - assertEquals(7 * MINUTE_IN_MILLIS, - mQuotaController.getRemainingExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE)); - assertEquals(mQcConstants.MAX_EXECUTION_TIME_MS - 9 * MINUTE_IN_MILLIS, - mQuotaController.getTimeUntilQuotaConsumedLocked(SOURCE_USER_ID, SOURCE_PACKAGE)); + synchronized (mQuotaController.mLock) { + assertEquals(7 * MINUTE_IN_MILLIS, + mQuotaController.getRemainingExecutionTimeLocked( + SOURCE_USER_ID, SOURCE_PACKAGE)); + assertEquals(mQcConstants.MAX_EXECUTION_TIME_MS - 9 * MINUTE_IN_MILLIS, + mQuotaController.getTimeUntilQuotaConsumedLocked( + SOURCE_USER_ID, SOURCE_PACKAGE)); + } } /** @@ -1146,11 +1306,15 @@ public class QuotaControllerTest { now - (24 * HOUR_IN_MILLIS + 8 * MINUTE_IN_MILLIS), 4 * HOUR_IN_MILLIS, 5)); setStandbyBucket(WORKING_INDEX); - assertEquals(8 * MINUTE_IN_MILLIS, - mQuotaController.getRemainingExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE)); - // Max time will phase out, so should use bucket limit. - assertEquals(10 * MINUTE_IN_MILLIS, - mQuotaController.getTimeUntilQuotaConsumedLocked(SOURCE_USER_ID, SOURCE_PACKAGE)); + synchronized (mQuotaController.mLock) { + assertEquals(8 * MINUTE_IN_MILLIS, + mQuotaController.getRemainingExecutionTimeLocked( + SOURCE_USER_ID, SOURCE_PACKAGE)); + // Max time will phase out, so should use bucket limit. + assertEquals(10 * MINUTE_IN_MILLIS, + mQuotaController.getTimeUntilQuotaConsumedLocked( + SOURCE_USER_ID, SOURCE_PACKAGE)); + } mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE).clear(); // Close to boundary. @@ -1159,10 +1323,14 @@ public class QuotaControllerTest { 4 * HOUR_IN_MILLIS - 5 * MINUTE_IN_MILLIS, 5)); setStandbyBucket(WORKING_INDEX); - assertEquals(5 * MINUTE_IN_MILLIS, - mQuotaController.getRemainingExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE)); - assertEquals(10 * MINUTE_IN_MILLIS, - mQuotaController.getTimeUntilQuotaConsumedLocked(SOURCE_USER_ID, SOURCE_PACKAGE)); + synchronized (mQuotaController.mLock) { + assertEquals(5 * MINUTE_IN_MILLIS, + mQuotaController.getRemainingExecutionTimeLocked( + SOURCE_USER_ID, SOURCE_PACKAGE)); + assertEquals(10 * MINUTE_IN_MILLIS, + mQuotaController.getTimeUntilQuotaConsumedLocked( + SOURCE_USER_ID, SOURCE_PACKAGE)); + } mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE).clear(); // Far from boundary. @@ -1171,10 +1339,14 @@ public class QuotaControllerTest { now - (20 * HOUR_IN_MILLIS), 4 * HOUR_IN_MILLIS - 3 * MINUTE_IN_MILLIS, 5)); setStandbyBucket(WORKING_INDEX); - assertEquals(3 * MINUTE_IN_MILLIS, - mQuotaController.getRemainingExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE)); - assertEquals(3 * MINUTE_IN_MILLIS, - mQuotaController.getTimeUntilQuotaConsumedLocked(SOURCE_USER_ID, SOURCE_PACKAGE)); + synchronized (mQuotaController.mLock) { + assertEquals(3 * MINUTE_IN_MILLIS, + mQuotaController.getRemainingExecutionTimeLocked( + SOURCE_USER_ID, SOURCE_PACKAGE)); + assertEquals(3 * MINUTE_IN_MILLIS, + mQuotaController.getTimeUntilQuotaConsumedLocked( + SOURCE_USER_ID, SOURCE_PACKAGE)); + } } /** @@ -1196,13 +1368,17 @@ public class QuotaControllerTest { createTimingSession( now - (8 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5)); - // Both max and bucket time have 8 minutes left. - assertEquals(8 * MINUTE_IN_MILLIS, - mQuotaController.getRemainingExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE)); - // Max time essentially free. Bucket time has 2 min phase out plus original 8 minute - // window time. - assertEquals(10 * MINUTE_IN_MILLIS, - mQuotaController.getTimeUntilQuotaConsumedLocked(SOURCE_USER_ID, SOURCE_PACKAGE)); + synchronized (mQuotaController.mLock) { + // Both max and bucket time have 8 minutes left. + assertEquals(8 * MINUTE_IN_MILLIS, + mQuotaController.getRemainingExecutionTimeLocked( + SOURCE_USER_ID, SOURCE_PACKAGE)); + // Max time essentially free. Bucket time has 2 min phase out plus original 8 minute + // window time. + assertEquals(10 * MINUTE_IN_MILLIS, + mQuotaController.getTimeUntilQuotaConsumedLocked( + SOURCE_USER_ID, SOURCE_PACKAGE)); + } mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE).clear(); // Overlap boundary. @@ -1218,23 +1394,32 @@ public class QuotaControllerTest { createTimingSession( now - (8 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5)); - // Both max and bucket time have 8 minutes left. - assertEquals(8 * MINUTE_IN_MILLIS, - mQuotaController.getRemainingExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE)); - // Max time only has one minute phase out. Bucket time has 2 minute phase out. - assertEquals(9 * MINUTE_IN_MILLIS, - mQuotaController.getTimeUntilQuotaConsumedLocked(SOURCE_USER_ID, SOURCE_PACKAGE)); + synchronized (mQuotaController.mLock) { + // Both max and bucket time have 8 minutes left. + assertEquals(8 * MINUTE_IN_MILLIS, + mQuotaController.getRemainingExecutionTimeLocked( + SOURCE_USER_ID, SOURCE_PACKAGE)); + // Max time only has one minute phase out. Bucket time has 2 minute phase out. + assertEquals(9 * MINUTE_IN_MILLIS, + mQuotaController.getTimeUntilQuotaConsumedLocked( + SOURCE_USER_ID, SOURCE_PACKAGE)); + } } @Test public void testIsWithinQuotaLocked_NeverApp() { - assertFalse(mQuotaController.isWithinQuotaLocked(0, "com.android.test.never", NEVER_INDEX)); + synchronized (mQuotaController.mLock) { + assertFalse( + mQuotaController.isWithinQuotaLocked(0, "com.android.test.never", NEVER_INDEX)); + } } @Test public void testIsWithinQuotaLocked_Charging() { setCharging(); - assertTrue(mQuotaController.isWithinQuotaLocked(0, "com.android.test", RARE_INDEX)); + synchronized (mQuotaController.mLock) { + assertTrue(mQuotaController.isWithinQuotaLocked(0, "com.android.test", RARE_INDEX)); + } } @Test @@ -1246,7 +1431,9 @@ public class QuotaControllerTest { mQuotaController.saveTimingSession(0, "com.android.test", createTimingSession(now - (5 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5)); mQuotaController.incrementJobCount(0, "com.android.test", 5); - assertTrue(mQuotaController.isWithinQuotaLocked(0, "com.android.test", WORKING_INDEX)); + synchronized (mQuotaController.mLock) { + assertTrue(mQuotaController.isWithinQuotaLocked(0, "com.android.test", WORKING_INDEX)); + } } @Test @@ -1259,15 +1446,19 @@ public class QuotaControllerTest { mQuotaController.saveTimingSession(0, "com.android.test.spam", createTimingSession(now - (5 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, jobCount)); mQuotaController.incrementJobCount(0, "com.android.test.spam", jobCount); - assertFalse(mQuotaController.isWithinQuotaLocked(0, "com.android.test.spam", - WORKING_INDEX)); + synchronized (mQuotaController.mLock) { + assertFalse(mQuotaController.isWithinQuotaLocked( + 0, "com.android.test.spam", WORKING_INDEX)); + } mQuotaController.saveTimingSession(0, "com.android.test.frequent", createTimingSession(now - (2 * HOUR_IN_MILLIS), 15 * MINUTE_IN_MILLIS, 2000)); mQuotaController.saveTimingSession(0, "com.android.test.frequent", createTimingSession(now - (HOUR_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 500)); - assertFalse(mQuotaController.isWithinQuotaLocked(0, "com.android.test.frequent", - FREQUENT_INDEX)); + synchronized (mQuotaController.mLock) { + assertFalse(mQuotaController.isWithinQuotaLocked( + 0, "com.android.test.frequent", FREQUENT_INDEX)); + } } @Test @@ -1281,7 +1472,9 @@ public class QuotaControllerTest { mQuotaController.saveTimingSession(0, "com.android.test", createTimingSession(now - (5 * MINUTE_IN_MILLIS), 4 * MINUTE_IN_MILLIS, 5)); mQuotaController.incrementJobCount(0, "com.android.test", 5); - assertFalse(mQuotaController.isWithinQuotaLocked(0, "com.android.test", WORKING_INDEX)); + synchronized (mQuotaController.mLock) { + assertFalse(mQuotaController.isWithinQuotaLocked(0, "com.android.test", WORKING_INDEX)); + } } @Test @@ -1294,7 +1487,9 @@ public class QuotaControllerTest { mQuotaController.saveTimingSession(0, "com.android.test", createTimingSession(now - (5 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, jobCount)); mQuotaController.incrementJobCount(0, "com.android.test", jobCount); - assertFalse(mQuotaController.isWithinQuotaLocked(0, "com.android.test", WORKING_INDEX)); + synchronized (mQuotaController.mLock) { + assertFalse(mQuotaController.isWithinQuotaLocked(0, "com.android.test", WORKING_INDEX)); + } } @Test @@ -1306,32 +1501,42 @@ public class QuotaControllerTest { setStandbyBucket(ACTIVE_INDEX, jobStatus); setProcessState(ActivityManager.PROCESS_STATE_BACKUP); - mQuotaController.maybeStartTrackingJobLocked(jobStatus, null); - mQuotaController.prepareForExecutionLocked(jobStatus); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStartTrackingJobLocked(jobStatus, null); + mQuotaController.prepareForExecutionLocked(jobStatus); + } for (int i = 0; i < 20; ++i) { advanceElapsedClock(SECOND_IN_MILLIS); setProcessState(ActivityManager.PROCESS_STATE_SERVICE); setProcessState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND); } - mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false); + } advanceElapsedClock(15 * SECOND_IN_MILLIS); - mQuotaController.maybeStartTrackingJobLocked(jobStatus, null); - mQuotaController.prepareForExecutionLocked(jobStatus); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStartTrackingJobLocked(jobStatus, null); + mQuotaController.prepareForExecutionLocked(jobStatus); + } for (int i = 0; i < 20; ++i) { advanceElapsedClock(SECOND_IN_MILLIS); setProcessState(ActivityManager.PROCESS_STATE_SERVICE); setProcessState(ActivityManager.PROCESS_STATE_RECEIVER); } - mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false); + } advanceElapsedClock(10 * MINUTE_IN_MILLIS + 30 * SECOND_IN_MILLIS); - assertEquals(2, mQuotaController.getExecutionStatsLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, ACTIVE_INDEX).jobCountInRateLimitingWindow); - assertTrue(mQuotaController.isWithinQuotaLocked(jobStatus)); - assertTrue(jobStatus.isReady()); + synchronized (mQuotaController.mLock) { + assertEquals(2, mQuotaController.getExecutionStatsLocked( + SOURCE_USER_ID, SOURCE_PACKAGE, ACTIVE_INDEX).jobCountInRateLimitingWindow); + assertTrue(mQuotaController.isWithinQuotaLocked(jobStatus)); + assertTrue(jobStatus.isReady()); + } } @Test @@ -1368,44 +1573,54 @@ public class QuotaControllerTest { doReturn(new String[]{fgChangerPkgName}) .when(packageManager).getPackagesForUid(fgChangerUid); - mQuotaController.maybeStartTrackingJobLocked(unaffected, null); - mQuotaController.prepareForExecutionLocked(unaffected); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStartTrackingJobLocked(unaffected, null); + mQuotaController.prepareForExecutionLocked(unaffected); - mQuotaController.maybeStartTrackingJobLocked(fgStateChanger, null); - mQuotaController.prepareForExecutionLocked(fgStateChanger); + mQuotaController.maybeStartTrackingJobLocked(fgStateChanger, null); + mQuotaController.prepareForExecutionLocked(fgStateChanger); + } for (int i = 0; i < 20; ++i) { advanceElapsedClock(SECOND_IN_MILLIS); setProcessState(ActivityManager.PROCESS_STATE_TOP, fgChangerUid); setProcessState(ActivityManager.PROCESS_STATE_TOP_SLEEPING, fgChangerUid); } - mQuotaController.maybeStopTrackingJobLocked(fgStateChanger, null, false); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStopTrackingJobLocked(fgStateChanger, null, false); + } advanceElapsedClock(15 * SECOND_IN_MILLIS); - mQuotaController.maybeStartTrackingJobLocked(fgStateChanger, null); - mQuotaController.prepareForExecutionLocked(fgStateChanger); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStartTrackingJobLocked(fgStateChanger, null); + mQuotaController.prepareForExecutionLocked(fgStateChanger); + } for (int i = 0; i < 20; ++i) { advanceElapsedClock(SECOND_IN_MILLIS); setProcessState(ActivityManager.PROCESS_STATE_TOP, fgChangerUid); setProcessState(ActivityManager.PROCESS_STATE_TOP_SLEEPING, fgChangerUid); } - mQuotaController.maybeStopTrackingJobLocked(fgStateChanger, null, false); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStopTrackingJobLocked(fgStateChanger, null, false); - mQuotaController.maybeStopTrackingJobLocked(unaffected, null, false); + mQuotaController.maybeStopTrackingJobLocked(unaffected, null, false); - assertTrue(mQuotaController.isWithinQuotaLocked(unaffected)); - assertTrue(unaffected.isReady()); - assertFalse(mQuotaController.isWithinQuotaLocked(fgStateChanger)); - assertFalse(fgStateChanger.isReady()); + assertTrue(mQuotaController.isWithinQuotaLocked(unaffected)); + assertTrue(unaffected.isReady()); + assertFalse(mQuotaController.isWithinQuotaLocked(fgStateChanger)); + assertFalse(fgStateChanger.isReady()); + } assertEquals(1, mQuotaController.getTimingSessions(SOURCE_USER_ID, unaffectedPkgName).size()); assertEquals(42, mQuotaController.getTimingSessions(SOURCE_USER_ID, fgChangerPkgName).size()); - for (int i = ACTIVE_INDEX; i < RARE_INDEX; ++i) { - assertEquals(42, mQuotaController.getExecutionStatsLocked( - SOURCE_USER_ID, fgChangerPkgName, i).jobCountInRateLimitingWindow); - assertEquals(1, mQuotaController.getExecutionStatsLocked( - SOURCE_USER_ID, unaffectedPkgName, i).jobCountInRateLimitingWindow); + synchronized (mQuotaController.mLock) { + for (int i = ACTIVE_INDEX; i < RARE_INDEX; ++i) { + assertEquals(42, mQuotaController.getExecutionStatsLocked( + SOURCE_USER_ID, fgChangerPkgName, i).jobCountInRateLimitingWindow); + assertEquals(1, mQuotaController.getExecutionStatsLocked( + SOURCE_USER_ID, unaffectedPkgName, i).jobCountInRateLimitingWindow); + } } } @@ -1413,11 +1628,10 @@ public class QuotaControllerTest { public void testIsWithinQuotaLocked_TimingSession() { setDischarging(); final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); - mQcConstants.MAX_SESSION_COUNT_RARE = 3; - mQcConstants.MAX_SESSION_COUNT_FREQUENT = 4; - mQcConstants.MAX_SESSION_COUNT_WORKING = 5; - mQcConstants.MAX_SESSION_COUNT_ACTIVE = 6; - mQcConstants.updateConstants(); + setDeviceConfigInt(QcConstants.KEY_MAX_SESSION_COUNT_RARE, 3); + setDeviceConfigInt(QcConstants.KEY_MAX_SESSION_COUNT_FREQUENT, 4); + setDeviceConfigInt(QcConstants.KEY_MAX_SESSION_COUNT_WORKING, 5); + setDeviceConfigInt(QcConstants.KEY_MAX_SESSION_COUNT_ACTIVE, 6); for (int i = 0; i < 7; ++i) { mQuotaController.saveTimingSession(0, "com.android.test", @@ -1425,25 +1639,30 @@ public class QuotaControllerTest { 2)); mQuotaController.incrementJobCount(0, "com.android.test", 2); - assertEquals("Rare has incorrect quota status with " + (i + 1) + " sessions", - i < 2, - mQuotaController.isWithinQuotaLocked(0, "com.android.test", RARE_INDEX)); - assertEquals("Frequent has incorrect quota status with " + (i + 1) + " sessions", - i < 3, - mQuotaController.isWithinQuotaLocked(0, "com.android.test", FREQUENT_INDEX)); - assertEquals("Working has incorrect quota status with " + (i + 1) + " sessions", - i < 4, - mQuotaController.isWithinQuotaLocked(0, "com.android.test", WORKING_INDEX)); - assertEquals("Active has incorrect quota status with " + (i + 1) + " sessions", - i < 5, - mQuotaController.isWithinQuotaLocked(0, "com.android.test", ACTIVE_INDEX)); + synchronized (mQuotaController.mLock) { + assertEquals("Rare has incorrect quota status with " + (i + 1) + " sessions", + i < 2, + mQuotaController.isWithinQuotaLocked(0, "com.android.test", RARE_INDEX)); + assertEquals("Frequent has incorrect quota status with " + (i + 1) + " sessions", + i < 3, + mQuotaController.isWithinQuotaLocked( + 0, "com.android.test", FREQUENT_INDEX)); + assertEquals("Working has incorrect quota status with " + (i + 1) + " sessions", + i < 4, + mQuotaController.isWithinQuotaLocked(0, "com.android.test", WORKING_INDEX)); + assertEquals("Active has incorrect quota status with " + (i + 1) + " sessions", + i < 5, + mQuotaController.isWithinQuotaLocked(0, "com.android.test", ACTIVE_INDEX)); + } } } @Test public void testMaybeScheduleCleanupAlarmLocked() { // No sessions saved yet. - mQuotaController.maybeScheduleCleanupAlarmLocked(); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeScheduleCleanupAlarmLocked(); + } verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_CLEANUP), any(), any()); // Test with only one timing session saved. @@ -1451,7 +1670,9 @@ public class QuotaControllerTest { final long end = now - (6 * HOUR_IN_MILLIS - 5 * MINUTE_IN_MILLIS); mQuotaController.saveTimingSession(0, "com.android.test", new TimingSession(now - 6 * HOUR_IN_MILLIS, end, 1)); - mQuotaController.maybeScheduleCleanupAlarmLocked(); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeScheduleCleanupAlarmLocked(); + } verify(mAlarmManager, times(1)) .set(anyInt(), eq(end + 24 * HOUR_IN_MILLIS), eq(TAG_CLEANUP), any(), any()); @@ -1460,7 +1681,9 @@ public class QuotaControllerTest { createTimingSession(now - 3 * HOUR_IN_MILLIS, MINUTE_IN_MILLIS, 1)); mQuotaController.saveTimingSession(0, "com.android.test", createTimingSession(now - HOUR_IN_MILLIS, 3 * MINUTE_IN_MILLIS, 1)); - mQuotaController.maybeScheduleCleanupAlarmLocked(); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeScheduleCleanupAlarmLocked(); + } verify(mAlarmManager, times(1)) .set(anyInt(), eq(end + 24 * HOUR_IN_MILLIS), eq(TAG_CLEANUP), any(), any()); } @@ -1477,8 +1700,10 @@ public class QuotaControllerTest { setProcessState(ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND); // No sessions saved yet. - mQuotaController.maybeScheduleStartAlarmLocked(SOURCE_USER_ID, SOURCE_PACKAGE, - standbyBucket); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeScheduleStartAlarmLocked( + SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket); + } verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any()); final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); @@ -1491,27 +1716,35 @@ public class QuotaControllerTest { createTimingSession(now - 12 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, 1)); mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE, createTimingSession(now - 7 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, 1)); - mQuotaController.maybeScheduleStartAlarmLocked(SOURCE_USER_ID, SOURCE_PACKAGE, - standbyBucket); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeScheduleStartAlarmLocked( + SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket); + } verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any()); mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE, createTimingSession(now - 2 * HOUR_IN_MILLIS, 55 * MINUTE_IN_MILLIS, 1)); - mQuotaController.maybeScheduleStartAlarmLocked(SOURCE_USER_ID, SOURCE_PACKAGE, - standbyBucket); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeScheduleStartAlarmLocked( + SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket); + } verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any()); JobStatus jobStatus = createJobStatus("testMaybeScheduleStartAlarmLocked_Active", 1); setStandbyBucket(standbyBucket, jobStatus); - mQuotaController.maybeStartTrackingJobLocked(jobStatus, null); - mQuotaController.prepareForExecutionLocked(jobStatus); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStartTrackingJobLocked(jobStatus, null); + mQuotaController.prepareForExecutionLocked(jobStatus); + } advanceElapsedClock(5 * MINUTE_IN_MILLIS); - // Timer has only been going for 5 minutes in the past 10 minutes, which is under the window - // size limit, but the total execution time for the past 24 hours is 6 hours, so the job no - // longer has quota. - assertEquals(0, mQuotaController.getRemainingExecutionTimeLocked(jobStatus)); - mQuotaController.maybeScheduleStartAlarmLocked(SOURCE_USER_ID, SOURCE_PACKAGE, - standbyBucket); + synchronized (mQuotaController.mLock) { + // Timer has only been going for 5 minutes in the past 10 minutes, which is under the + // window size limit, but the total execution time for the past 24 hours is 6 hours, so + // the job no longer has quota. + assertEquals(0, mQuotaController.getRemainingExecutionTimeLocked(jobStatus)); + mQuotaController.maybeScheduleStartAlarmLocked( + SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket); + } verify(mAlarmManager, times(1)).set(anyInt(), eq(expectedAlarmTime), eq(TAG_QUOTA_CHECK), any(), any()); } @@ -1526,15 +1759,19 @@ public class QuotaControllerTest { // Working set window size is 2 hours. final int standbyBucket = WORKING_INDEX; - // No sessions saved yet. - mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket); + synchronized (mQuotaController.mLock) { + // No sessions saved yet. + mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket); + } verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any()); // Test with timing sessions out of window. final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); mQuotaController.saveTimingSession(0, "com.android.test", createTimingSession(now - 10 * HOUR_IN_MILLIS, 5 * MINUTE_IN_MILLIS, 1)); - mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket); + } verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any()); // Test with timing sessions in window but still in quota. @@ -1544,7 +1781,9 @@ public class QuotaControllerTest { end - MINUTE_IN_MILLIS + 2 * HOUR_IN_MILLIS + mQcConstants.IN_QUOTA_BUFFER_MS; mQuotaController.saveTimingSession(0, "com.android.test", new TimingSession(now - 2 * HOUR_IN_MILLIS, end, 1)); - mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket); + } verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any()); // Add some more sessions, but still in quota. @@ -1552,18 +1791,24 @@ public class QuotaControllerTest { createTimingSession(now - HOUR_IN_MILLIS, MINUTE_IN_MILLIS, 1)); mQuotaController.saveTimingSession(0, "com.android.test", createTimingSession(now - (50 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 1)); - mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket); + } verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any()); // Test when out of quota. mQuotaController.saveTimingSession(0, "com.android.test", createTimingSession(now - 30 * MINUTE_IN_MILLIS, 5 * MINUTE_IN_MILLIS, 1)); - mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket); + } verify(mAlarmManager, times(1)) .set(anyInt(), eq(expectedAlarmTime), eq(TAG_QUOTA_CHECK), any(), any()); // Alarm already scheduled, so make sure it's not scheduled again. - mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket); + } verify(mAlarmManager, times(1)) .set(anyInt(), eq(expectedAlarmTime), eq(TAG_QUOTA_CHECK), any(), any()); } @@ -1579,14 +1824,18 @@ public class QuotaControllerTest { final int standbyBucket = FREQUENT_INDEX; // No sessions saved yet. - mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket); + } verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any()); // Test with timing sessions out of window. final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); mQuotaController.saveTimingSession(0, "com.android.test", createTimingSession(now - 10 * HOUR_IN_MILLIS, 5 * MINUTE_IN_MILLIS, 1)); - mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket); + } verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any()); // Test with timing sessions in window but still in quota. @@ -1594,7 +1843,9 @@ public class QuotaControllerTest { final long expectedAlarmTime = start + 8 * HOUR_IN_MILLIS + mQcConstants.IN_QUOTA_BUFFER_MS; mQuotaController.saveTimingSession(0, "com.android.test", createTimingSession(start, 5 * MINUTE_IN_MILLIS, 1)); - mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket); + } verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any()); // Add some more sessions, but still in quota. @@ -1602,18 +1853,24 @@ public class QuotaControllerTest { createTimingSession(now - 3 * HOUR_IN_MILLIS, MINUTE_IN_MILLIS, 1)); mQuotaController.saveTimingSession(0, "com.android.test", createTimingSession(now - HOUR_IN_MILLIS, 3 * MINUTE_IN_MILLIS, 1)); - mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket); + } verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any()); // Test when out of quota. mQuotaController.saveTimingSession(0, "com.android.test", createTimingSession(now - HOUR_IN_MILLIS, MINUTE_IN_MILLIS, 1)); - mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket); + } verify(mAlarmManager, times(1)) .set(anyInt(), eq(expectedAlarmTime), eq(TAG_QUOTA_CHECK), any(), any()); // Alarm already scheduled, so make sure it's not scheduled again. - mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket); + } verify(mAlarmManager, times(1)) .set(anyInt(), eq(expectedAlarmTime), eq(TAG_QUOTA_CHECK), any(), any()); } @@ -1629,18 +1886,21 @@ public class QuotaControllerTest { final int standbyBucket = RARE_INDEX; // Prevent timing session throttling from affecting the test. - mQcConstants.MAX_SESSION_COUNT_RARE = 50; - mQcConstants.updateConstants(); + setDeviceConfigInt(QcConstants.KEY_MAX_SESSION_COUNT_RARE, 50); // No sessions saved yet. - mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket); + } verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any()); // Test with timing sessions out of window. final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); mQuotaController.saveTimingSession(0, "com.android.test", createTimingSession(now - 25 * HOUR_IN_MILLIS, 5 * MINUTE_IN_MILLIS, 1)); - mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket); + } verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any()); // Test with timing sessions in window but still in quota. @@ -1652,7 +1912,9 @@ public class QuotaControllerTest { + mQcConstants.IN_QUOTA_BUFFER_MS; mQuotaController.saveTimingSession(0, "com.android.test", createTimingSession(start, 5 * MINUTE_IN_MILLIS, 1)); - mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket); + } verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any()); // Add some more sessions, but still in quota. @@ -1660,18 +1922,24 @@ public class QuotaControllerTest { createTimingSession(now - 3 * HOUR_IN_MILLIS, MINUTE_IN_MILLIS, 1)); mQuotaController.saveTimingSession(0, "com.android.test", createTimingSession(now - HOUR_IN_MILLIS, 3 * MINUTE_IN_MILLIS, 1)); - mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket); + } verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any()); // Test when out of quota. mQuotaController.saveTimingSession(0, "com.android.test", createTimingSession(now - HOUR_IN_MILLIS, 2 * MINUTE_IN_MILLIS, 1)); - mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket); + } verify(mAlarmManager, times(1)) .set(anyInt(), eq(expectedAlarmTime), eq(TAG_QUOTA_CHECK), any(), any()); // Alarm already scheduled, so make sure it's not scheduled again. - mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket); + } verify(mAlarmManager, times(1)) .set(anyInt(), eq(expectedAlarmTime), eq(TAG_QUOTA_CHECK), any(), any()); } @@ -1703,7 +1971,9 @@ public class QuotaControllerTest { InOrder inOrder = inOrder(mAlarmManager); // Start in ACTIVE bucket. - mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", ACTIVE_INDEX); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", ACTIVE_INDEX); + } inOrder.verify(mAlarmManager, never()) .set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any()); inOrder.verify(mAlarmManager, never()).cancel(any(AlarmManager.OnAlarmListener.class)); @@ -1712,34 +1982,46 @@ public class QuotaControllerTest { final long expectedWorkingAlarmTime = outOfQuotaTime + (2 * HOUR_IN_MILLIS) + mQcConstants.IN_QUOTA_BUFFER_MS; - mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", WORKING_INDEX); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", WORKING_INDEX); + } inOrder.verify(mAlarmManager, times(1)) .set(anyInt(), eq(expectedWorkingAlarmTime), eq(TAG_QUOTA_CHECK), any(), any()); final long expectedFrequentAlarmTime = outOfQuotaTime + (8 * HOUR_IN_MILLIS) + mQcConstants.IN_QUOTA_BUFFER_MS; - mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", FREQUENT_INDEX); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", FREQUENT_INDEX); + } inOrder.verify(mAlarmManager, times(1)) .set(anyInt(), eq(expectedFrequentAlarmTime), eq(TAG_QUOTA_CHECK), any(), any()); final long expectedRareAlarmTime = outOfQuotaTime + (24 * HOUR_IN_MILLIS) + mQcConstants.IN_QUOTA_BUFFER_MS; - mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", RARE_INDEX); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", RARE_INDEX); + } inOrder.verify(mAlarmManager, times(1)) .set(anyInt(), eq(expectedRareAlarmTime), eq(TAG_QUOTA_CHECK), any(), any()); // And back up again. - mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", FREQUENT_INDEX); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", FREQUENT_INDEX); + } inOrder.verify(mAlarmManager, times(1)) .set(anyInt(), eq(expectedFrequentAlarmTime), eq(TAG_QUOTA_CHECK), any(), any()); - mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", WORKING_INDEX); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", WORKING_INDEX); + } inOrder.verify(mAlarmManager, times(1)) .set(anyInt(), eq(expectedWorkingAlarmTime), eq(TAG_QUOTA_CHECK), any(), any()); - mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", ACTIVE_INDEX); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", ACTIVE_INDEX); + } inOrder.verify(mAlarmManager, never()) .set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any()); inOrder.verify(mAlarmManager, times(1)).cancel(any(AlarmManager.OnAlarmListener.class)); @@ -1749,28 +2031,34 @@ public class QuotaControllerTest { public void testMaybeScheduleStartAlarmLocked_JobCount_RateLimitingWindow() { // Set rate limiting period different from allowed time to confirm code sets based on // the former. - mQcConstants.ALLOWED_TIME_PER_PERIOD_MS = 10 * MINUTE_IN_MILLIS; - mQcConstants.RATE_LIMITING_WINDOW_MS = 5 * MINUTE_IN_MILLIS; - mQcConstants.updateConstants(); + setDeviceConfigLong(QcConstants.KEY_ALLOWED_TIME_PER_PERIOD_MS, 10 * MINUTE_IN_MILLIS); + setDeviceConfigLong(QcConstants.KEY_RATE_LIMITING_WINDOW_MS, 5 * MINUTE_IN_MILLIS); final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); final int standbyBucket = WORKING_INDEX; - ExecutionStats stats = mQuotaController.getExecutionStatsLocked(SOURCE_USER_ID, - SOURCE_PACKAGE, standbyBucket); + ExecutionStats stats; + synchronized (mQuotaController.mLock) { + stats = mQuotaController.getExecutionStatsLocked( + SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket); + } stats.jobCountInRateLimitingWindow = mQcConstants.MAX_JOB_COUNT_PER_RATE_LIMITING_WINDOW + 2; // Invalid time in the past, so the count shouldn't be used. stats.jobRateLimitExpirationTimeElapsed = now - 5 * MINUTE_IN_MILLIS / 2; - mQuotaController.maybeScheduleStartAlarmLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeScheduleStartAlarmLocked( + SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket); + } verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any()); // Valid time in the future, so the count should be used. stats.jobRateLimitExpirationTimeElapsed = now + 5 * MINUTE_IN_MILLIS / 2; final long expectedWorkingAlarmTime = stats.jobRateLimitExpirationTimeElapsed; - mQuotaController.maybeScheduleStartAlarmLocked( - SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeScheduleStartAlarmLocked( + SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket); + } verify(mAlarmManager, times(1)) .set(anyInt(), eq(expectedWorkingAlarmTime), eq(TAG_QUOTA_CHECK), any(), any()); } @@ -1790,8 +2078,9 @@ public class QuotaControllerTest { @Test public void testMaybeScheduleStartAlarmLocked_SmallRollingQuota_UpdatedBufferSize() { // Make sure any new value is used correctly. - mQcConstants.IN_QUOTA_BUFFER_MS *= 2; - mQcConstants.updateConstants(); + setDeviceConfigLong(QcConstants.KEY_IN_QUOTA_BUFFER_MS, + mQcConstants.IN_QUOTA_BUFFER_MS * 2); + runTestMaybeScheduleStartAlarmLocked_SmallRollingQuota_AllowedTimeCheck(); mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE).clear(); runTestMaybeScheduleStartAlarmLocked_SmallRollingQuota_MaxTimeCheck(); @@ -1800,8 +2089,9 @@ public class QuotaControllerTest { @Test public void testMaybeScheduleStartAlarmLocked_SmallRollingQuota_UpdatedAllowedTime() { // Make sure any new value is used correctly. - mQcConstants.ALLOWED_TIME_PER_PERIOD_MS /= 2; - mQcConstants.updateConstants(); + setDeviceConfigLong(QcConstants.KEY_ALLOWED_TIME_PER_PERIOD_MS, + mQcConstants.ALLOWED_TIME_PER_PERIOD_MS / 2); + runTestMaybeScheduleStartAlarmLocked_SmallRollingQuota_AllowedTimeCheck(); mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE).clear(); runTestMaybeScheduleStartAlarmLocked_SmallRollingQuota_MaxTimeCheck(); @@ -1810,8 +2100,9 @@ public class QuotaControllerTest { @Test public void testMaybeScheduleStartAlarmLocked_SmallRollingQuota_UpdatedMaxTime() { // Make sure any new value is used correctly. - mQcConstants.MAX_EXECUTION_TIME_MS /= 2; - mQcConstants.updateConstants(); + setDeviceConfigLong(QcConstants.KEY_MAX_EXECUTION_TIME_MS, + mQcConstants.MAX_EXECUTION_TIME_MS / 2); + runTestMaybeScheduleStartAlarmLocked_SmallRollingQuota_AllowedTimeCheck(); mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE).clear(); runTestMaybeScheduleStartAlarmLocked_SmallRollingQuota_MaxTimeCheck(); @@ -1820,10 +2111,13 @@ public class QuotaControllerTest { @Test public void testMaybeScheduleStartAlarmLocked_SmallRollingQuota_UpdatedEverything() { // Make sure any new value is used correctly. - mQcConstants.IN_QUOTA_BUFFER_MS *= 2; - mQcConstants.ALLOWED_TIME_PER_PERIOD_MS /= 2; - mQcConstants.MAX_EXECUTION_TIME_MS /= 2; - mQcConstants.updateConstants(); + setDeviceConfigLong(QcConstants.KEY_IN_QUOTA_BUFFER_MS, + mQcConstants.IN_QUOTA_BUFFER_MS * 2); + setDeviceConfigLong(QcConstants.KEY_ALLOWED_TIME_PER_PERIOD_MS, + mQcConstants.ALLOWED_TIME_PER_PERIOD_MS / 2); + setDeviceConfigLong(QcConstants.KEY_MAX_EXECUTION_TIME_MS, + mQcConstants.MAX_EXECUTION_TIME_MS / 2); + runTestMaybeScheduleStartAlarmLocked_SmallRollingQuota_AllowedTimeCheck(); mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE).clear(); runTestMaybeScheduleStartAlarmLocked_SmallRollingQuota_MaxTimeCheck(); @@ -1852,8 +2146,10 @@ public class QuotaControllerTest { // is 2 hours + (QUOTA_BUFFER_MS - contributionMs) after the start of the second session. final long expectedAlarmTime = now - HOUR_IN_MILLIS + 2 * HOUR_IN_MILLIS + (mQcConstants.IN_QUOTA_BUFFER_MS - contributionMs); - mQuotaController.maybeScheduleStartAlarmLocked(SOURCE_USER_ID, SOURCE_PACKAGE, - standbyBucket); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeScheduleStartAlarmLocked( + SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket); + } verify(mAlarmManager, times(1)) .set(anyInt(), eq(expectedAlarmTime), eq(TAG_QUOTA_CHECK), any(), any()); } @@ -1883,35 +2179,40 @@ public class QuotaControllerTest { final long expectedAlarmTime = now - 20 * HOUR_IN_MILLIS + 24 * HOUR_IN_MILLIS + (mQcConstants.IN_QUOTA_BUFFER_MS - contributionMs); - mQuotaController.maybeScheduleStartAlarmLocked(SOURCE_USER_ID, SOURCE_PACKAGE, - standbyBucket); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeScheduleStartAlarmLocked( + SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket); + } verify(mAlarmManager, times(1)) .set(anyInt(), eq(expectedAlarmTime), eq(TAG_QUOTA_CHECK), any(), any()); } @Test public void testConstantsUpdating_ValidValues() { - mQcConstants.ALLOWED_TIME_PER_PERIOD_MS = 5 * MINUTE_IN_MILLIS; - mQcConstants.IN_QUOTA_BUFFER_MS = 2 * MINUTE_IN_MILLIS; - mQcConstants.WINDOW_SIZE_ACTIVE_MS = 15 * MINUTE_IN_MILLIS; - mQcConstants.WINDOW_SIZE_WORKING_MS = 30 * MINUTE_IN_MILLIS; - mQcConstants.WINDOW_SIZE_FREQUENT_MS = 45 * MINUTE_IN_MILLIS; - mQcConstants.WINDOW_SIZE_RARE_MS = 60 * MINUTE_IN_MILLIS; - mQcConstants.MAX_EXECUTION_TIME_MS = 3 * HOUR_IN_MILLIS; - mQcConstants.MAX_JOB_COUNT_ACTIVE = 5000; - mQcConstants.MAX_JOB_COUNT_WORKING = 4000; - mQcConstants.MAX_JOB_COUNT_FREQUENT = 3000; - mQcConstants.MAX_JOB_COUNT_RARE = 2000; - mQcConstants.RATE_LIMITING_WINDOW_MS = 15 * MINUTE_IN_MILLIS; - mQcConstants.MAX_JOB_COUNT_PER_RATE_LIMITING_WINDOW = 500; - mQcConstants.MAX_SESSION_COUNT_ACTIVE = 500; - mQcConstants.MAX_SESSION_COUNT_WORKING = 400; - mQcConstants.MAX_SESSION_COUNT_FREQUENT = 300; - mQcConstants.MAX_SESSION_COUNT_RARE = 200; - mQcConstants.MAX_SESSION_COUNT_PER_RATE_LIMITING_WINDOW = 50; - mQcConstants.TIMING_SESSION_COALESCING_DURATION_MS = 10 * SECOND_IN_MILLIS; - - mQcConstants.updateConstants(); + setDeviceConfigLong(QcConstants.KEY_ALLOWED_TIME_PER_PERIOD_MS, 5 * MINUTE_IN_MILLIS); + setDeviceConfigLong(QcConstants.KEY_IN_QUOTA_BUFFER_MS, 2 * MINUTE_IN_MILLIS); + setDeviceConfigLong(QcConstants.KEY_WINDOW_SIZE_ACTIVE_MS, 15 * MINUTE_IN_MILLIS); + setDeviceConfigLong(QcConstants.KEY_WINDOW_SIZE_WORKING_MS, 30 * MINUTE_IN_MILLIS); + setDeviceConfigLong(QcConstants.KEY_WINDOW_SIZE_FREQUENT_MS, 45 * MINUTE_IN_MILLIS); + setDeviceConfigLong(QcConstants.KEY_WINDOW_SIZE_RARE_MS, 60 * MINUTE_IN_MILLIS); + setDeviceConfigLong(QcConstants.KEY_WINDOW_SIZE_RESTRICTED_MS, 120 * MINUTE_IN_MILLIS); + setDeviceConfigLong(QcConstants.KEY_MAX_EXECUTION_TIME_MS, 3 * HOUR_IN_MILLIS); + setDeviceConfigInt(QcConstants.KEY_MAX_JOB_COUNT_ACTIVE, 5000); + setDeviceConfigInt(QcConstants.KEY_MAX_JOB_COUNT_WORKING, 4000); + setDeviceConfigInt(QcConstants.KEY_MAX_JOB_COUNT_FREQUENT, 3000); + setDeviceConfigInt(QcConstants.KEY_MAX_JOB_COUNT_RARE, 2000); + setDeviceConfigInt(QcConstants.KEY_MAX_JOB_COUNT_RESTRICTED, 2000); + setDeviceConfigLong(QcConstants.KEY_RATE_LIMITING_WINDOW_MS, 15 * MINUTE_IN_MILLIS); + setDeviceConfigInt(QcConstants.KEY_MAX_JOB_COUNT_PER_RATE_LIMITING_WINDOW, 500); + setDeviceConfigInt(QcConstants.KEY_MAX_SESSION_COUNT_ACTIVE, 500); + setDeviceConfigInt(QcConstants.KEY_MAX_SESSION_COUNT_WORKING, 400); + setDeviceConfigInt(QcConstants.KEY_MAX_SESSION_COUNT_FREQUENT, 300); + setDeviceConfigInt(QcConstants.KEY_MAX_SESSION_COUNT_RARE, 200); + setDeviceConfigInt(QcConstants.KEY_MAX_SESSION_COUNT_RESTRICTED, 100); + setDeviceConfigInt(QcConstants.KEY_MAX_SESSION_COUNT_PER_RATE_LIMITING_WINDOW, 50); + setDeviceConfigLong(QcConstants.KEY_TIMING_SESSION_COALESCING_DURATION_MS, + 10 * SECOND_IN_MILLIS); + setDeviceConfigLong(QcConstants.KEY_MIN_QUOTA_CHECK_DELAY_MS, 7 * MINUTE_IN_MILLIS); assertEquals(5 * MINUTE_IN_MILLIS, mQuotaController.getAllowedTimePerPeriodMs()); assertEquals(2 * MINUTE_IN_MILLIS, mQuotaController.getInQuotaBufferMs()); @@ -1920,6 +2221,8 @@ public class QuotaControllerTest { assertEquals(45 * MINUTE_IN_MILLIS, mQuotaController.getBucketWindowSizes()[FREQUENT_INDEX]); assertEquals(60 * MINUTE_IN_MILLIS, mQuotaController.getBucketWindowSizes()[RARE_INDEX]); + assertEquals(120 * MINUTE_IN_MILLIS, + mQuotaController.getBucketWindowSizes()[RESTRICTED_INDEX]); assertEquals(3 * HOUR_IN_MILLIS, mQuotaController.getMaxExecutionTimeMs()); assertEquals(15 * MINUTE_IN_MILLIS, mQuotaController.getRateLimitingWindowMs()); assertEquals(500, mQuotaController.getMaxJobCountPerRateLimitingWindow()); @@ -1927,39 +2230,44 @@ public class QuotaControllerTest { assertEquals(4000, mQuotaController.getBucketMaxJobCounts()[WORKING_INDEX]); assertEquals(3000, mQuotaController.getBucketMaxJobCounts()[FREQUENT_INDEX]); assertEquals(2000, mQuotaController.getBucketMaxJobCounts()[RARE_INDEX]); + assertEquals(2000, mQuotaController.getBucketMaxJobCounts()[RESTRICTED_INDEX]); assertEquals(50, mQuotaController.getMaxSessionCountPerRateLimitingWindow()); assertEquals(500, mQuotaController.getBucketMaxSessionCounts()[ACTIVE_INDEX]); assertEquals(400, mQuotaController.getBucketMaxSessionCounts()[WORKING_INDEX]); assertEquals(300, mQuotaController.getBucketMaxSessionCounts()[FREQUENT_INDEX]); assertEquals(200, mQuotaController.getBucketMaxSessionCounts()[RARE_INDEX]); + assertEquals(100, mQuotaController.getBucketMaxSessionCounts()[RESTRICTED_INDEX]); assertEquals(10 * SECOND_IN_MILLIS, mQuotaController.getTimingSessionCoalescingDurationMs()); + assertEquals(7 * MINUTE_IN_MILLIS, mQuotaController.getMinQuotaCheckDelayMs()); } @Test public void testConstantsUpdating_InvalidValues() { // Test negatives/too low. - mQcConstants.ALLOWED_TIME_PER_PERIOD_MS = -MINUTE_IN_MILLIS; - mQcConstants.IN_QUOTA_BUFFER_MS = -MINUTE_IN_MILLIS; - mQcConstants.WINDOW_SIZE_ACTIVE_MS = -MINUTE_IN_MILLIS; - mQcConstants.WINDOW_SIZE_WORKING_MS = -MINUTE_IN_MILLIS; - mQcConstants.WINDOW_SIZE_FREQUENT_MS = -MINUTE_IN_MILLIS; - mQcConstants.WINDOW_SIZE_RARE_MS = -MINUTE_IN_MILLIS; - mQcConstants.MAX_EXECUTION_TIME_MS = -MINUTE_IN_MILLIS; - mQcConstants.MAX_JOB_COUNT_ACTIVE = -1; - mQcConstants.MAX_JOB_COUNT_WORKING = 1; - mQcConstants.MAX_JOB_COUNT_FREQUENT = 1; - mQcConstants.MAX_JOB_COUNT_RARE = 1; - mQcConstants.RATE_LIMITING_WINDOW_MS = 15 * SECOND_IN_MILLIS; - mQcConstants.MAX_JOB_COUNT_PER_RATE_LIMITING_WINDOW = 0; - mQcConstants.MAX_SESSION_COUNT_ACTIVE = -1; - mQcConstants.MAX_SESSION_COUNT_WORKING = 0; - mQcConstants.MAX_SESSION_COUNT_FREQUENT = -3; - mQcConstants.MAX_SESSION_COUNT_RARE = 0; - mQcConstants.MAX_SESSION_COUNT_PER_RATE_LIMITING_WINDOW = 0; - mQcConstants.TIMING_SESSION_COALESCING_DURATION_MS = -1; - - mQcConstants.updateConstants(); + setDeviceConfigLong(QcConstants.KEY_ALLOWED_TIME_PER_PERIOD_MS, -MINUTE_IN_MILLIS); + setDeviceConfigLong(QcConstants.KEY_IN_QUOTA_BUFFER_MS, -MINUTE_IN_MILLIS); + setDeviceConfigLong(QcConstants.KEY_WINDOW_SIZE_ACTIVE_MS, -MINUTE_IN_MILLIS); + setDeviceConfigLong(QcConstants.KEY_WINDOW_SIZE_WORKING_MS, -MINUTE_IN_MILLIS); + setDeviceConfigLong(QcConstants.KEY_WINDOW_SIZE_FREQUENT_MS, -MINUTE_IN_MILLIS); + setDeviceConfigLong(QcConstants.KEY_WINDOW_SIZE_RARE_MS, -MINUTE_IN_MILLIS); + setDeviceConfigLong(QcConstants.KEY_WINDOW_SIZE_RESTRICTED_MS, -MINUTE_IN_MILLIS); + setDeviceConfigLong(QcConstants.KEY_MAX_EXECUTION_TIME_MS, -MINUTE_IN_MILLIS); + setDeviceConfigInt(QcConstants.KEY_MAX_JOB_COUNT_ACTIVE, -1); + setDeviceConfigInt(QcConstants.KEY_MAX_JOB_COUNT_WORKING, 1); + setDeviceConfigInt(QcConstants.KEY_MAX_JOB_COUNT_FREQUENT, 1); + setDeviceConfigInt(QcConstants.KEY_MAX_JOB_COUNT_RARE, 1); + setDeviceConfigInt(QcConstants.KEY_MAX_JOB_COUNT_RESTRICTED, -1); + setDeviceConfigLong(QcConstants.KEY_RATE_LIMITING_WINDOW_MS, 15 * SECOND_IN_MILLIS); + setDeviceConfigInt(QcConstants.KEY_MAX_JOB_COUNT_PER_RATE_LIMITING_WINDOW, 0); + setDeviceConfigInt(QcConstants.KEY_MAX_SESSION_COUNT_ACTIVE, -1); + setDeviceConfigInt(QcConstants.KEY_MAX_SESSION_COUNT_WORKING, 0); + setDeviceConfigInt(QcConstants.KEY_MAX_SESSION_COUNT_FREQUENT, -3); + setDeviceConfigInt(QcConstants.KEY_MAX_SESSION_COUNT_RARE, 0); + setDeviceConfigInt(QcConstants.KEY_MAX_SESSION_COUNT_RESTRICTED, -5); + setDeviceConfigInt(QcConstants.KEY_MAX_SESSION_COUNT_PER_RATE_LIMITING_WINDOW, 0); + setDeviceConfigLong(QcConstants.KEY_TIMING_SESSION_COALESCING_DURATION_MS, -1); + setDeviceConfigLong(QcConstants.KEY_MIN_QUOTA_CHECK_DELAY_MS, -1); assertEquals(MINUTE_IN_MILLIS, mQuotaController.getAllowedTimePerPeriodMs()); assertEquals(0, mQuotaController.getInQuotaBufferMs()); @@ -1967,6 +2275,7 @@ public class QuotaControllerTest { assertEquals(MINUTE_IN_MILLIS, mQuotaController.getBucketWindowSizes()[WORKING_INDEX]); assertEquals(MINUTE_IN_MILLIS, mQuotaController.getBucketWindowSizes()[FREQUENT_INDEX]); assertEquals(MINUTE_IN_MILLIS, mQuotaController.getBucketWindowSizes()[RARE_INDEX]); + assertEquals(MINUTE_IN_MILLIS, mQuotaController.getBucketWindowSizes()[RESTRICTED_INDEX]); assertEquals(HOUR_IN_MILLIS, mQuotaController.getMaxExecutionTimeMs()); assertEquals(30 * SECOND_IN_MILLIS, mQuotaController.getRateLimitingWindowMs()); assertEquals(10, mQuotaController.getMaxJobCountPerRateLimitingWindow()); @@ -1974,35 +2283,37 @@ public class QuotaControllerTest { assertEquals(10, mQuotaController.getBucketMaxJobCounts()[WORKING_INDEX]); assertEquals(10, mQuotaController.getBucketMaxJobCounts()[FREQUENT_INDEX]); assertEquals(10, mQuotaController.getBucketMaxJobCounts()[RARE_INDEX]); + assertEquals(10, mQuotaController.getBucketMaxJobCounts()[RESTRICTED_INDEX]); assertEquals(10, mQuotaController.getMaxSessionCountPerRateLimitingWindow()); assertEquals(1, mQuotaController.getBucketMaxSessionCounts()[ACTIVE_INDEX]); assertEquals(1, mQuotaController.getBucketMaxSessionCounts()[WORKING_INDEX]); assertEquals(1, mQuotaController.getBucketMaxSessionCounts()[FREQUENT_INDEX]); assertEquals(1, mQuotaController.getBucketMaxSessionCounts()[RARE_INDEX]); + assertEquals(0, mQuotaController.getBucketMaxSessionCounts()[RESTRICTED_INDEX]); assertEquals(0, mQuotaController.getTimingSessionCoalescingDurationMs()); + assertEquals(0, mQuotaController.getMinQuotaCheckDelayMs()); // Invalid configurations. // In_QUOTA_BUFFER should never be greater than ALLOWED_TIME_PER_PERIOD - mQcConstants.ALLOWED_TIME_PER_PERIOD_MS = 2 * MINUTE_IN_MILLIS; - mQcConstants.IN_QUOTA_BUFFER_MS = 5 * MINUTE_IN_MILLIS; - - mQcConstants.updateConstants(); + setDeviceConfigLong(QcConstants.KEY_ALLOWED_TIME_PER_PERIOD_MS, 2 * MINUTE_IN_MILLIS); + setDeviceConfigLong(QcConstants.KEY_IN_QUOTA_BUFFER_MS, 5 * MINUTE_IN_MILLIS); assertTrue(mQuotaController.getInQuotaBufferMs() <= mQuotaController.getAllowedTimePerPeriodMs()); // Test larger than a day. Controller should cap at one day. - mQcConstants.ALLOWED_TIME_PER_PERIOD_MS = 25 * HOUR_IN_MILLIS; - mQcConstants.IN_QUOTA_BUFFER_MS = 25 * HOUR_IN_MILLIS; - mQcConstants.WINDOW_SIZE_ACTIVE_MS = 25 * HOUR_IN_MILLIS; - mQcConstants.WINDOW_SIZE_WORKING_MS = 25 * HOUR_IN_MILLIS; - mQcConstants.WINDOW_SIZE_FREQUENT_MS = 25 * HOUR_IN_MILLIS; - mQcConstants.WINDOW_SIZE_RARE_MS = 25 * HOUR_IN_MILLIS; - mQcConstants.MAX_EXECUTION_TIME_MS = 25 * HOUR_IN_MILLIS; - mQcConstants.RATE_LIMITING_WINDOW_MS = 25 * HOUR_IN_MILLIS; - mQcConstants.TIMING_SESSION_COALESCING_DURATION_MS = 25 * HOUR_IN_MILLIS; - - mQcConstants.updateConstants(); + setDeviceConfigLong(QcConstants.KEY_ALLOWED_TIME_PER_PERIOD_MS, 25 * HOUR_IN_MILLIS); + setDeviceConfigLong(QcConstants.KEY_IN_QUOTA_BUFFER_MS, 25 * HOUR_IN_MILLIS); + setDeviceConfigLong(QcConstants.KEY_WINDOW_SIZE_ACTIVE_MS, 25 * HOUR_IN_MILLIS); + setDeviceConfigLong(QcConstants.KEY_WINDOW_SIZE_WORKING_MS, 25 * HOUR_IN_MILLIS); + setDeviceConfigLong(QcConstants.KEY_WINDOW_SIZE_FREQUENT_MS, 25 * HOUR_IN_MILLIS); + setDeviceConfigLong(QcConstants.KEY_WINDOW_SIZE_RARE_MS, 25 * HOUR_IN_MILLIS); + setDeviceConfigLong(QcConstants.KEY_WINDOW_SIZE_RESTRICTED_MS, 30 * 24 * HOUR_IN_MILLIS); + setDeviceConfigLong(QcConstants.KEY_MAX_EXECUTION_TIME_MS, 25 * HOUR_IN_MILLIS); + setDeviceConfigLong(QcConstants.KEY_RATE_LIMITING_WINDOW_MS, 25 * HOUR_IN_MILLIS); + setDeviceConfigLong(QcConstants.KEY_TIMING_SESSION_COALESCING_DURATION_MS, + 25 * HOUR_IN_MILLIS); + setDeviceConfigLong(QcConstants.KEY_MIN_QUOTA_CHECK_DELAY_MS, 25 * HOUR_IN_MILLIS); assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getAllowedTimePerPeriodMs()); assertEquals(5 * MINUTE_IN_MILLIS, mQuotaController.getInQuotaBufferMs()); @@ -2010,10 +2321,13 @@ public class QuotaControllerTest { assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getBucketWindowSizes()[WORKING_INDEX]); assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getBucketWindowSizes()[FREQUENT_INDEX]); assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getBucketWindowSizes()[RARE_INDEX]); + assertEquals(7 * 24 * HOUR_IN_MILLIS, + mQuotaController.getBucketWindowSizes()[RESTRICTED_INDEX]); assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getMaxExecutionTimeMs()); assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getRateLimitingWindowMs()); assertEquals(15 * MINUTE_IN_MILLIS, mQuotaController.getTimingSessionCoalescingDurationMs()); + assertEquals(15 * MINUTE_IN_MILLIS, mQuotaController.getMinQuotaCheckDelayMs()); } /** Tests that TimingSessions aren't saved when the device is charging. */ @@ -2022,13 +2336,19 @@ public class QuotaControllerTest { setCharging(); JobStatus jobStatus = createJobStatus("testTimerTracking_Charging", 1); - mQuotaController.maybeStartTrackingJobLocked(jobStatus, null); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStartTrackingJobLocked(jobStatus, null); + } assertNull(mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE)); - mQuotaController.prepareForExecutionLocked(jobStatus); + synchronized (mQuotaController.mLock) { + mQuotaController.prepareForExecutionLocked(jobStatus); + } advanceElapsedClock(5 * SECOND_IN_MILLIS); - mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false); + } assertNull(mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE)); } @@ -2039,41 +2359,63 @@ public class QuotaControllerTest { setProcessState(ActivityManager.PROCESS_STATE_BACKUP); JobStatus jobStatus = createJobStatus("testTimerTracking_Discharging", 1); - mQuotaController.maybeStartTrackingJobLocked(jobStatus, null); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStartTrackingJobLocked(jobStatus, null); + } assertNull(mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE)); List<TimingSession> expected = new ArrayList<>(); long start = JobSchedulerService.sElapsedRealtimeClock.millis(); - mQuotaController.prepareForExecutionLocked(jobStatus); + synchronized (mQuotaController.mLock) { + mQuotaController.prepareForExecutionLocked(jobStatus); + } advanceElapsedClock(5 * SECOND_IN_MILLIS); - mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false); + } expected.add(createTimingSession(start, 5 * SECOND_IN_MILLIS, 1)); assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE)); // Test overlapping jobs. JobStatus jobStatus2 = createJobStatus("testTimerTracking_Discharging", 2); - mQuotaController.maybeStartTrackingJobLocked(jobStatus2, null); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStartTrackingJobLocked(jobStatus2, null); + } JobStatus jobStatus3 = createJobStatus("testTimerTracking_Discharging", 3); - mQuotaController.maybeStartTrackingJobLocked(jobStatus3, null); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStartTrackingJobLocked(jobStatus3, null); + } advanceElapsedClock(SECOND_IN_MILLIS); start = JobSchedulerService.sElapsedRealtimeClock.millis(); - mQuotaController.maybeStartTrackingJobLocked(jobStatus, null); - mQuotaController.prepareForExecutionLocked(jobStatus); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStartTrackingJobLocked(jobStatus, null); + mQuotaController.prepareForExecutionLocked(jobStatus); + } advanceElapsedClock(10 * SECOND_IN_MILLIS); - mQuotaController.prepareForExecutionLocked(jobStatus2); + synchronized (mQuotaController.mLock) { + mQuotaController.prepareForExecutionLocked(jobStatus2); + } advanceElapsedClock(10 * SECOND_IN_MILLIS); - mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false); + } advanceElapsedClock(10 * SECOND_IN_MILLIS); - mQuotaController.prepareForExecutionLocked(jobStatus3); + synchronized (mQuotaController.mLock) { + mQuotaController.prepareForExecutionLocked(jobStatus3); + } advanceElapsedClock(20 * SECOND_IN_MILLIS); - mQuotaController.maybeStopTrackingJobLocked(jobStatus3, null, false); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStopTrackingJobLocked(jobStatus3, null, false); + } advanceElapsedClock(10 * SECOND_IN_MILLIS); - mQuotaController.maybeStopTrackingJobLocked(jobStatus2, null, false); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStopTrackingJobLocked(jobStatus2, null, false); + } expected.add(createTimingSession(start, MINUTE_IN_MILLIS, 3)); assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE)); } @@ -2087,11 +2429,17 @@ public class QuotaControllerTest { setProcessState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND); JobStatus jobStatus = createJobStatus("testTimerTracking_ChargingAndDischarging", 1); - mQuotaController.maybeStartTrackingJobLocked(jobStatus, null); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStartTrackingJobLocked(jobStatus, null); + } JobStatus jobStatus2 = createJobStatus("testTimerTracking_ChargingAndDischarging", 2); - mQuotaController.maybeStartTrackingJobLocked(jobStatus2, null); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStartTrackingJobLocked(jobStatus2, null); + } JobStatus jobStatus3 = createJobStatus("testTimerTracking_ChargingAndDischarging", 3); - mQuotaController.maybeStartTrackingJobLocked(jobStatus3, null); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStartTrackingJobLocked(jobStatus3, null); + } assertNull(mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE)); List<TimingSession> expected = new ArrayList<>(); @@ -2099,12 +2447,16 @@ public class QuotaControllerTest { // should be counted. setCharging(); - mQuotaController.prepareForExecutionLocked(jobStatus); + synchronized (mQuotaController.mLock) { + mQuotaController.prepareForExecutionLocked(jobStatus); + } advanceElapsedClock(10 * SECOND_IN_MILLIS); setDischarging(); long start = JobSchedulerService.sElapsedRealtimeClock.millis(); advanceElapsedClock(10 * SECOND_IN_MILLIS); - mQuotaController.maybeStopTrackingJobLocked(jobStatus, jobStatus, true); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStopTrackingJobLocked(jobStatus, jobStatus, true); + } expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1)); assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE)); @@ -2118,23 +2470,35 @@ public class QuotaControllerTest { // shouldn't be included in either job count. setDischarging(); start = JobSchedulerService.sElapsedRealtimeClock.millis(); - mQuotaController.maybeStartTrackingJobLocked(jobStatus, null); - mQuotaController.prepareForExecutionLocked(jobStatus); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStartTrackingJobLocked(jobStatus, null); + mQuotaController.prepareForExecutionLocked(jobStatus); + } advanceElapsedClock(10 * SECOND_IN_MILLIS); - mQuotaController.prepareForExecutionLocked(jobStatus2); + synchronized (mQuotaController.mLock) { + mQuotaController.prepareForExecutionLocked(jobStatus2); + } advanceElapsedClock(10 * SECOND_IN_MILLIS); setCharging(); expected.add(createTimingSession(start, 20 * SECOND_IN_MILLIS, 2)); - mQuotaController.prepareForExecutionLocked(jobStatus3); + synchronized (mQuotaController.mLock) { + mQuotaController.prepareForExecutionLocked(jobStatus3); + } advanceElapsedClock(10 * SECOND_IN_MILLIS); - mQuotaController.maybeStopTrackingJobLocked(jobStatus3, null, false); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStopTrackingJobLocked(jobStatus3, null, false); + } advanceElapsedClock(10 * SECOND_IN_MILLIS); - mQuotaController.maybeStopTrackingJobLocked(jobStatus2, null, false); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStopTrackingJobLocked(jobStatus2, null, false); + } advanceElapsedClock(10 * SECOND_IN_MILLIS); setDischarging(); start = JobSchedulerService.sElapsedRealtimeClock.millis(); advanceElapsedClock(20 * SECOND_IN_MILLIS); - mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false); + } expected.add(createTimingSession(start, 20 * SECOND_IN_MILLIS, 1)); assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE)); @@ -2142,13 +2506,17 @@ public class QuotaControllerTest { // during the discharging period should be counted. setDischarging(); start = JobSchedulerService.sElapsedRealtimeClock.millis(); - mQuotaController.maybeStartTrackingJobLocked(jobStatus2, null); - mQuotaController.prepareForExecutionLocked(jobStatus2); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStartTrackingJobLocked(jobStatus2, null); + mQuotaController.prepareForExecutionLocked(jobStatus2); + } advanceElapsedClock(10 * SECOND_IN_MILLIS); expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1)); setCharging(); advanceElapsedClock(10 * SECOND_IN_MILLIS); - mQuotaController.maybeStopTrackingJobLocked(jobStatus2, null, false); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStopTrackingJobLocked(jobStatus2, null, false); + } assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE)); } @@ -2159,42 +2527,63 @@ public class QuotaControllerTest { setProcessState(ActivityManager.PROCESS_STATE_RECEIVER); JobStatus jobStatus = createJobStatus("testTimerTracking_AllBackground", 1); - mQuotaController.maybeStartTrackingJobLocked(jobStatus, null); - + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStartTrackingJobLocked(jobStatus, null); + } assertNull(mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE)); List<TimingSession> expected = new ArrayList<>(); // Test single job. long start = JobSchedulerService.sElapsedRealtimeClock.millis(); - mQuotaController.prepareForExecutionLocked(jobStatus); + synchronized (mQuotaController.mLock) { + mQuotaController.prepareForExecutionLocked(jobStatus); + } advanceElapsedClock(5 * SECOND_IN_MILLIS); - mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false); + } expected.add(createTimingSession(start, 5 * SECOND_IN_MILLIS, 1)); assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE)); // Test overlapping jobs. JobStatus jobStatus2 = createJobStatus("testTimerTracking_AllBackground", 2); - mQuotaController.maybeStartTrackingJobLocked(jobStatus2, null); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStartTrackingJobLocked(jobStatus2, null); + } JobStatus jobStatus3 = createJobStatus("testTimerTracking_AllBackground", 3); - mQuotaController.maybeStartTrackingJobLocked(jobStatus3, null); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStartTrackingJobLocked(jobStatus3, null); + } advanceElapsedClock(SECOND_IN_MILLIS); start = JobSchedulerService.sElapsedRealtimeClock.millis(); - mQuotaController.maybeStartTrackingJobLocked(jobStatus, null); - mQuotaController.prepareForExecutionLocked(jobStatus); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStartTrackingJobLocked(jobStatus, null); + mQuotaController.prepareForExecutionLocked(jobStatus); + } advanceElapsedClock(10 * SECOND_IN_MILLIS); - mQuotaController.prepareForExecutionLocked(jobStatus2); + synchronized (mQuotaController.mLock) { + mQuotaController.prepareForExecutionLocked(jobStatus2); + } advanceElapsedClock(10 * SECOND_IN_MILLIS); - mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false); + } advanceElapsedClock(10 * SECOND_IN_MILLIS); - mQuotaController.prepareForExecutionLocked(jobStatus3); + synchronized (mQuotaController.mLock) { + mQuotaController.prepareForExecutionLocked(jobStatus3); + } advanceElapsedClock(20 * SECOND_IN_MILLIS); - mQuotaController.maybeStopTrackingJobLocked(jobStatus3, null, false); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStopTrackingJobLocked(jobStatus3, null, false); + } advanceElapsedClock(10 * SECOND_IN_MILLIS); - mQuotaController.maybeStopTrackingJobLocked(jobStatus2, null, false); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStopTrackingJobLocked(jobStatus2, null, false); + } expected.add(createTimingSession(start, MINUTE_IN_MILLIS, 3)); assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE)); } @@ -2206,16 +2595,22 @@ public class QuotaControllerTest { JobStatus jobStatus = createJobStatus("testTimerTracking_AllForeground", 1); setProcessState(ActivityManager.PROCESS_STATE_TOP); - mQuotaController.maybeStartTrackingJobLocked(jobStatus, null); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStartTrackingJobLocked(jobStatus, null); + } assertNull(mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE)); - mQuotaController.prepareForExecutionLocked(jobStatus); + synchronized (mQuotaController.mLock) { + mQuotaController.prepareForExecutionLocked(jobStatus); + } advanceElapsedClock(5 * SECOND_IN_MILLIS); // Change to a state that should still be considered foreground. setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE); advanceElapsedClock(5 * SECOND_IN_MILLIS); - mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false); + } assertNull(mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE)); } @@ -2230,18 +2625,24 @@ public class QuotaControllerTest { JobStatus jobBg1 = createJobStatus("testTimerTracking_ForegroundAndBackground", 1); JobStatus jobBg2 = createJobStatus("testTimerTracking_ForegroundAndBackground", 2); JobStatus jobFg3 = createJobStatus("testTimerTracking_ForegroundAndBackground", 3); - mQuotaController.maybeStartTrackingJobLocked(jobBg1, null); - mQuotaController.maybeStartTrackingJobLocked(jobBg2, null); - mQuotaController.maybeStartTrackingJobLocked(jobFg3, null); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStartTrackingJobLocked(jobBg1, null); + mQuotaController.maybeStartTrackingJobLocked(jobBg2, null); + mQuotaController.maybeStartTrackingJobLocked(jobFg3, null); + } assertNull(mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE)); List<TimingSession> expected = new ArrayList<>(); // UID starts out inactive. setProcessState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND); long start = JobSchedulerService.sElapsedRealtimeClock.millis(); - mQuotaController.prepareForExecutionLocked(jobBg1); + synchronized (mQuotaController.mLock) { + mQuotaController.prepareForExecutionLocked(jobBg1); + } advanceElapsedClock(10 * SECOND_IN_MILLIS); - mQuotaController.maybeStopTrackingJobLocked(jobBg1, jobBg1, true); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStopTrackingJobLocked(jobBg1, jobBg1, true); + } expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1)); assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE)); @@ -2253,16 +2654,24 @@ public class QuotaControllerTest { // App remains in foreground state after coming to foreground, so there should only be one // session. start = JobSchedulerService.sElapsedRealtimeClock.millis(); - mQuotaController.maybeStartTrackingJobLocked(jobBg2, null); - mQuotaController.prepareForExecutionLocked(jobBg2); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStartTrackingJobLocked(jobBg2, null); + mQuotaController.prepareForExecutionLocked(jobBg2); + } advanceElapsedClock(10 * SECOND_IN_MILLIS); expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1)); setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE); - mQuotaController.prepareForExecutionLocked(jobFg3); + synchronized (mQuotaController.mLock) { + mQuotaController.prepareForExecutionLocked(jobFg3); + } advanceElapsedClock(10 * SECOND_IN_MILLIS); - mQuotaController.maybeStopTrackingJobLocked(jobFg3, null, false); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStopTrackingJobLocked(jobFg3, null, false); + } advanceElapsedClock(10 * SECOND_IN_MILLIS); - mQuotaController.maybeStopTrackingJobLocked(jobBg2, null, false); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStopTrackingJobLocked(jobBg2, null, false); + } assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE)); advanceElapsedClock(SECOND_IN_MILLIS); @@ -2273,25 +2682,39 @@ public class QuotaControllerTest { // * The first should have a count of 1 // * The second should have a count of 2 since it will include both jobs start = JobSchedulerService.sElapsedRealtimeClock.millis(); - mQuotaController.maybeStartTrackingJobLocked(jobBg1, null); - mQuotaController.maybeStartTrackingJobLocked(jobBg2, null); - mQuotaController.maybeStartTrackingJobLocked(jobFg3, null); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStartTrackingJobLocked(jobBg1, null); + mQuotaController.maybeStartTrackingJobLocked(jobBg2, null); + mQuotaController.maybeStartTrackingJobLocked(jobFg3, null); + } setProcessState(ActivityManager.PROCESS_STATE_LAST_ACTIVITY); - mQuotaController.prepareForExecutionLocked(jobBg1); + synchronized (mQuotaController.mLock) { + mQuotaController.prepareForExecutionLocked(jobBg1); + } advanceElapsedClock(10 * SECOND_IN_MILLIS); expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1)); setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE); - mQuotaController.prepareForExecutionLocked(jobFg3); + synchronized (mQuotaController.mLock) { + mQuotaController.prepareForExecutionLocked(jobFg3); + } advanceElapsedClock(10 * SECOND_IN_MILLIS); - mQuotaController.maybeStopTrackingJobLocked(jobBg1, jobBg1, true); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStopTrackingJobLocked(jobBg1, jobBg1, true); + } advanceElapsedClock(10 * SECOND_IN_MILLIS); // UID "inactive" now start = JobSchedulerService.sElapsedRealtimeClock.millis(); setProcessState(ActivityManager.PROCESS_STATE_TOP_SLEEPING); - mQuotaController.prepareForExecutionLocked(jobBg2); + synchronized (mQuotaController.mLock) { + mQuotaController.prepareForExecutionLocked(jobBg2); + } advanceElapsedClock(10 * SECOND_IN_MILLIS); - mQuotaController.maybeStopTrackingJobLocked(jobFg3, null, false); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStopTrackingJobLocked(jobFg3, null, false); + } advanceElapsedClock(10 * SECOND_IN_MILLIS); - mQuotaController.maybeStopTrackingJobLocked(jobBg2, null, false); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStopTrackingJobLocked(jobBg2, null, false); + } expected.add(createTimingSession(start, 20 * SECOND_IN_MILLIS, 2)); assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE)); } @@ -2307,21 +2730,34 @@ public class QuotaControllerTest { JobStatus jobFg1 = createJobStatus("testTimerTracking_JobCount_Foreground", 1); JobStatus jobFg2 = createJobStatus("testTimerTracking_JobCount_Foreground", 2); - mQuotaController.maybeStartTrackingJobLocked(jobFg1, null); - mQuotaController.maybeStartTrackingJobLocked(jobFg2, null); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStartTrackingJobLocked(jobFg1, null); + mQuotaController.maybeStartTrackingJobLocked(jobFg2, null); + } assertNull(mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE)); - ExecutionStats stats = mQuotaController.getExecutionStatsLocked(SOURCE_USER_ID, - SOURCE_PACKAGE, standbyBucket); + ExecutionStats stats; + synchronized (mQuotaController.mLock) { + stats = mQuotaController.getExecutionStatsLocked( + SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket); + } assertEquals(0, stats.jobCountInRateLimitingWindow); setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE); - mQuotaController.prepareForExecutionLocked(jobFg1); + synchronized (mQuotaController.mLock) { + mQuotaController.prepareForExecutionLocked(jobFg1); + } advanceElapsedClock(10 * SECOND_IN_MILLIS); - mQuotaController.prepareForExecutionLocked(jobFg2); + synchronized (mQuotaController.mLock) { + mQuotaController.prepareForExecutionLocked(jobFg2); + } advanceElapsedClock(10 * SECOND_IN_MILLIS); - mQuotaController.maybeStopTrackingJobLocked(jobFg1, null, false); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStopTrackingJobLocked(jobFg1, null, false); + } advanceElapsedClock(10 * SECOND_IN_MILLIS); - mQuotaController.maybeStopTrackingJobLocked(jobFg2, null, false); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStopTrackingJobLocked(jobFg2, null, false); + } assertNull(mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE)); assertEquals(0, stats.jobCountInRateLimitingWindow); @@ -2335,21 +2771,32 @@ public class QuotaControllerTest { final int standbyBucket = WORKING_INDEX; JobStatus jobBg1 = createJobStatus("testTimerTracking_JobCount_Background", 1); JobStatus jobBg2 = createJobStatus("testTimerTracking_JobCount_Background", 2); - mQuotaController.maybeStartTrackingJobLocked(jobBg1, null); - mQuotaController.maybeStartTrackingJobLocked(jobBg2, null); + ExecutionStats stats; + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStartTrackingJobLocked(jobBg1, null); + mQuotaController.maybeStartTrackingJobLocked(jobBg2, null); - ExecutionStats stats = mQuotaController.getExecutionStatsLocked(SOURCE_USER_ID, - SOURCE_PACKAGE, standbyBucket); + stats = mQuotaController.getExecutionStatsLocked(SOURCE_USER_ID, + SOURCE_PACKAGE, standbyBucket); + } assertEquals(0, stats.jobCountInRateLimitingWindow); setProcessState(ActivityManager.PROCESS_STATE_TOP_SLEEPING); - mQuotaController.prepareForExecutionLocked(jobBg1); + synchronized (mQuotaController.mLock) { + mQuotaController.prepareForExecutionLocked(jobBg1); + } advanceElapsedClock(10 * SECOND_IN_MILLIS); - mQuotaController.prepareForExecutionLocked(jobBg2); + synchronized (mQuotaController.mLock) { + mQuotaController.prepareForExecutionLocked(jobBg2); + } advanceElapsedClock(10 * SECOND_IN_MILLIS); - mQuotaController.maybeStopTrackingJobLocked(jobBg1, null, false); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStopTrackingJobLocked(jobBg1, null, false); + } advanceElapsedClock(10 * SECOND_IN_MILLIS); - mQuotaController.maybeStopTrackingJobLocked(jobBg2, null, false); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStopTrackingJobLocked(jobBg2, null, false); + } assertEquals(2, stats.jobCountInRateLimitingWindow); } @@ -2365,19 +2812,25 @@ public class QuotaControllerTest { JobStatus jobBg2 = createJobStatus("testTimerTracking_TopAndNonTop", 2); JobStatus jobFg1 = createJobStatus("testTimerTracking_TopAndNonTop", 3); JobStatus jobTop = createJobStatus("testTimerTracking_TopAndNonTop", 4); - mQuotaController.maybeStartTrackingJobLocked(jobBg1, null); - mQuotaController.maybeStartTrackingJobLocked(jobBg2, null); - mQuotaController.maybeStartTrackingJobLocked(jobFg1, null); - mQuotaController.maybeStartTrackingJobLocked(jobTop, null); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStartTrackingJobLocked(jobBg1, null); + mQuotaController.maybeStartTrackingJobLocked(jobBg2, null); + mQuotaController.maybeStartTrackingJobLocked(jobFg1, null); + mQuotaController.maybeStartTrackingJobLocked(jobTop, null); + } assertNull(mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE)); List<TimingSession> expected = new ArrayList<>(); // UID starts out inactive. setProcessState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND); long start = JobSchedulerService.sElapsedRealtimeClock.millis(); - mQuotaController.prepareForExecutionLocked(jobBg1); + synchronized (mQuotaController.mLock) { + mQuotaController.prepareForExecutionLocked(jobBg1); + } advanceElapsedClock(10 * SECOND_IN_MILLIS); - mQuotaController.maybeStopTrackingJobLocked(jobBg1, jobBg1, true); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStopTrackingJobLocked(jobBg1, jobBg1, true); + } expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1)); assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE)); @@ -2389,16 +2842,24 @@ public class QuotaControllerTest { // App remains in top state after coming to top, so there should only be one // session. start = JobSchedulerService.sElapsedRealtimeClock.millis(); - mQuotaController.maybeStartTrackingJobLocked(jobBg2, null); - mQuotaController.prepareForExecutionLocked(jobBg2); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStartTrackingJobLocked(jobBg2, null); + mQuotaController.prepareForExecutionLocked(jobBg2); + } advanceElapsedClock(10 * SECOND_IN_MILLIS); expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1)); setProcessState(ActivityManager.PROCESS_STATE_TOP); - mQuotaController.prepareForExecutionLocked(jobTop); + synchronized (mQuotaController.mLock) { + mQuotaController.prepareForExecutionLocked(jobTop); + } advanceElapsedClock(10 * SECOND_IN_MILLIS); - mQuotaController.maybeStopTrackingJobLocked(jobTop, null, false); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStopTrackingJobLocked(jobTop, null, false); + } advanceElapsedClock(10 * SECOND_IN_MILLIS); - mQuotaController.maybeStopTrackingJobLocked(jobBg2, null, false); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStopTrackingJobLocked(jobBg2, null, false); + } assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE)); advanceElapsedClock(SECOND_IN_MILLIS); @@ -2411,31 +2872,47 @@ public class QuotaControllerTest { // * The second should have a count of 2, which accounts for the bg2 and fg, but not top // jobs. start = JobSchedulerService.sElapsedRealtimeClock.millis(); - mQuotaController.maybeStartTrackingJobLocked(jobBg1, null); - mQuotaController.maybeStartTrackingJobLocked(jobBg2, null); - mQuotaController.maybeStartTrackingJobLocked(jobTop, null); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStartTrackingJobLocked(jobBg1, null); + mQuotaController.maybeStartTrackingJobLocked(jobBg2, null); + mQuotaController.maybeStartTrackingJobLocked(jobTop, null); + } setProcessState(ActivityManager.PROCESS_STATE_LAST_ACTIVITY); - mQuotaController.prepareForExecutionLocked(jobBg1); + synchronized (mQuotaController.mLock) { + mQuotaController.prepareForExecutionLocked(jobBg1); + } advanceElapsedClock(10 * SECOND_IN_MILLIS); expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1)); setProcessState(ActivityManager.PROCESS_STATE_TOP); - mQuotaController.prepareForExecutionLocked(jobTop); + synchronized (mQuotaController.mLock) { + mQuotaController.prepareForExecutionLocked(jobTop); + } advanceElapsedClock(10 * SECOND_IN_MILLIS); - mQuotaController.maybeStopTrackingJobLocked(jobBg1, jobBg1, true); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStopTrackingJobLocked(jobBg1, jobBg1, true); + } advanceElapsedClock(5 * SECOND_IN_MILLIS); setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE); - mQuotaController.prepareForExecutionLocked(jobFg1); + synchronized (mQuotaController.mLock) { + mQuotaController.prepareForExecutionLocked(jobFg1); + } advanceElapsedClock(5 * SECOND_IN_MILLIS); setProcessState(ActivityManager.PROCESS_STATE_TOP); advanceElapsedClock(10 * SECOND_IN_MILLIS); // UID "inactive" now start = JobSchedulerService.sElapsedRealtimeClock.millis(); setProcessState(ActivityManager.PROCESS_STATE_TOP_SLEEPING); - mQuotaController.prepareForExecutionLocked(jobBg2); + synchronized (mQuotaController.mLock) { + mQuotaController.prepareForExecutionLocked(jobBg2); + } advanceElapsedClock(10 * SECOND_IN_MILLIS); - mQuotaController.maybeStopTrackingJobLocked(jobTop, null, false); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStopTrackingJobLocked(jobTop, null, false); + } advanceElapsedClock(10 * SECOND_IN_MILLIS); - mQuotaController.maybeStopTrackingJobLocked(jobBg2, null, false); - mQuotaController.maybeStopTrackingJobLocked(jobFg1, null, false); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStopTrackingJobLocked(jobBg2, null, false); + mQuotaController.maybeStopTrackingJobLocked(jobFg1, null, false); + } expected.add(createTimingSession(start, 20 * SECOND_IN_MILLIS, 2)); assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE)); } @@ -2463,20 +2940,28 @@ public class QuotaControllerTest { // UID starts out inactive. setProcessState(ActivityManager.PROCESS_STATE_SERVICE); // Start the job. - mQuotaController.prepareForExecutionLocked(jobBg); + synchronized (mQuotaController.mLock) { + mQuotaController.prepareForExecutionLocked(jobBg); + } advanceElapsedClock(remainingTimeMs / 2); // New job starts after UID is in the foreground. Since the app is now in the foreground, it // should continue to have remainingTimeMs / 2 time remaining. setProcessState(ActivityManager.PROCESS_STATE_TOP); - mQuotaController.prepareForExecutionLocked(jobTop); + synchronized (mQuotaController.mLock) { + mQuotaController.prepareForExecutionLocked(jobTop); + } advanceElapsedClock(remainingTimeMs); // Wait for some extra time to allow for job processing. inOrder.verify(mJobSchedulerService, timeout(remainingTimeMs + 2 * SECOND_IN_MILLIS).times(0)) .onControllerStateChanged(); - assertEquals(remainingTimeMs / 2, mQuotaController.getRemainingExecutionTimeLocked(jobBg)); - assertEquals(remainingTimeMs / 2, mQuotaController.getRemainingExecutionTimeLocked(jobTop)); + synchronized (mQuotaController.mLock) { + assertEquals(remainingTimeMs / 2, + mQuotaController.getRemainingExecutionTimeLocked(jobBg)); + assertEquals(remainingTimeMs / 2, + mQuotaController.getRemainingExecutionTimeLocked(jobTop)); + } // Go to a background state. setProcessState(ActivityManager.PROCESS_STATE_TOP_SLEEPING); advanceElapsedClock(remainingTimeMs / 2 + 1); @@ -2498,7 +2983,9 @@ public class QuotaControllerTest { inOrder.verify(mJobSchedulerService, timeout(SECOND_IN_MILLIS).times(1)) .onControllerStateChanged(); trackJobs(jobFg, jobTop); - mQuotaController.prepareForExecutionLocked(jobTop); + synchronized (mQuotaController.mLock) { + mQuotaController.prepareForExecutionLocked(jobTop); + } assertTrue(jobTop.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA)); assertTrue(jobFg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA)); assertTrue(jobBg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA)); @@ -2530,7 +3017,9 @@ public class QuotaControllerTest { @Test public void testTracking_OutOfQuota() { JobStatus jobStatus = createJobStatus("testTracking_OutOfQuota", 1); - mQuotaController.maybeStartTrackingJobLocked(jobStatus, null); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStartTrackingJobLocked(jobStatus, null); + } setStandbyBucket(WORKING_INDEX, jobStatus); // 2 hour window setProcessState(ActivityManager.PROCESS_STATE_HOME); // Now the package only has two seconds to run. @@ -2541,7 +3030,9 @@ public class QuotaControllerTest { 10 * MINUTE_IN_MILLIS - remainingTimeMs, 1)); // Start the job. - mQuotaController.prepareForExecutionLocked(jobStatus); + synchronized (mQuotaController.mLock) { + mQuotaController.prepareForExecutionLocked(jobStatus); + } advanceElapsedClock(remainingTimeMs); // Wait for some extra time to allow for job processing. @@ -2560,7 +3051,9 @@ public class QuotaControllerTest { @Test public void testTracking_RollingQuota() { JobStatus jobStatus = createJobStatus("testTracking_OutOfQuota", 1); - mQuotaController.maybeStartTrackingJobLocked(jobStatus, null); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStartTrackingJobLocked(jobStatus, null); + } setStandbyBucket(WORKING_INDEX, jobStatus); // 2 hour window setProcessState(ActivityManager.PROCESS_STATE_SERVICE); Handler handler = mQuotaController.getHandler(); @@ -2577,9 +3070,13 @@ public class QuotaControllerTest { createTimingSession(now - HOUR_IN_MILLIS, 9 * MINUTE_IN_MILLIS + 50 * SECOND_IN_MILLIS, 1)); - assertEquals(remainingTimeMs, mQuotaController.getRemainingExecutionTimeLocked(jobStatus)); - // Start the job. - mQuotaController.prepareForExecutionLocked(jobStatus); + synchronized (mQuotaController.mLock) { + assertEquals(remainingTimeMs, + mQuotaController.getRemainingExecutionTimeLocked(jobStatus)); + + // Start the job. + mQuotaController.prepareForExecutionLocked(jobStatus); + } advanceElapsedClock(remainingTimeMs); // Wait for some extra time to allow for job processing. @@ -2590,8 +3087,11 @@ public class QuotaControllerTest { // The job used up the remaining quota, but in that time, the same amount of time in the // old TimingSession also fell out of the quota window, so it should still have the same // amount of remaining time left its quota. - assertEquals(remainingTimeMs, - mQuotaController.getRemainingExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE)); + synchronized (mQuotaController.mLock) { + assertEquals(remainingTimeMs, + mQuotaController.getRemainingExecutionTimeLocked( + SOURCE_USER_ID, SOURCE_PACKAGE)); + } // Handler is told to check when the quota will be consumed, not when the initial // remaining time is over. verify(handler, atLeast(1)).sendMessageDelayed(any(), eq(10 * SECOND_IN_MILLIS)); @@ -2619,27 +3119,33 @@ public class QuotaControllerTest { doNothing().when(mQuotaController).maybeScheduleCleanupAlarmLocked(); // Essentially disable session throttling. - mQcConstants.MAX_SESSION_COUNT_WORKING = - mQcConstants.MAX_SESSION_COUNT_PER_RATE_LIMITING_WINDOW = Integer.MAX_VALUE; - mQcConstants.updateConstants(); + setDeviceConfigInt(QcConstants.KEY_MAX_SESSION_COUNT_WORKING, Integer.MAX_VALUE); + setDeviceConfigInt(QcConstants.KEY_MAX_SESSION_COUNT_PER_RATE_LIMITING_WINDOW, + Integer.MAX_VALUE); final int standbyBucket = WORKING_INDEX; setProcessState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND); // No sessions saved yet. - mQuotaController.maybeScheduleStartAlarmLocked(SOURCE_USER_ID, SOURCE_PACKAGE, - standbyBucket); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeScheduleStartAlarmLocked( + SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket); + } verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any()); // Ran jobs up to the job limit. All of them should be allowed to run. for (int i = 0; i < mQcConstants.MAX_JOB_COUNT_PER_RATE_LIMITING_WINDOW; ++i) { JobStatus job = createJobStatus("testStartAlarmScheduled_JobCount_AllowedTime", i); setStandbyBucket(WORKING_INDEX, job); - mQuotaController.maybeStartTrackingJobLocked(job, null); - assertTrue(job.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA)); - mQuotaController.prepareForExecutionLocked(job); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStartTrackingJobLocked(job, null); + assertTrue(job.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA)); + mQuotaController.prepareForExecutionLocked(job); + } advanceElapsedClock(SECOND_IN_MILLIS); - mQuotaController.maybeStopTrackingJobLocked(job, null, false); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStopTrackingJobLocked(job, null, false); + } advanceElapsedClock(SECOND_IN_MILLIS); } // Start alarm shouldn't have been scheduled since the app was in quota up until this point. @@ -2649,11 +3155,16 @@ public class QuotaControllerTest { JobStatus throttledJob = createJobStatus( "testStartAlarmScheduled_JobCount_AllowedTime", 42); setStandbyBucket(WORKING_INDEX, throttledJob); - mQuotaController.maybeStartTrackingJobLocked(throttledJob, null); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStartTrackingJobLocked(throttledJob, null); + } assertFalse(throttledJob.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA)); - ExecutionStats stats = mQuotaController.getExecutionStatsLocked(SOURCE_USER_ID, - SOURCE_PACKAGE, standbyBucket); + ExecutionStats stats; + synchronized (mQuotaController.mLock) { + stats = mQuotaController.getExecutionStatsLocked( + SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket); + } final long expectedWorkingAlarmTime = stats.jobRateLimitExpirationTimeElapsed; verify(mAlarmManager, times(1)) .set(anyInt(), eq(expectedWorkingAlarmTime), eq(TAG_QUOTA_CHECK), any(), any()); @@ -2671,19 +3182,21 @@ public class QuotaControllerTest { doNothing().when(mQuotaController).maybeScheduleCleanupAlarmLocked(); // Essentially disable job count throttling. - mQcConstants.MAX_JOB_COUNT_FREQUENT = - mQcConstants.MAX_JOB_COUNT_PER_RATE_LIMITING_WINDOW = Integer.MAX_VALUE; + setDeviceConfigInt(QcConstants.KEY_MAX_JOB_COUNT_FREQUENT, Integer.MAX_VALUE); + setDeviceConfigInt(QcConstants.KEY_MAX_JOB_COUNT_PER_RATE_LIMITING_WINDOW, + Integer.MAX_VALUE); // Make sure throttling is because of COUNT_PER_RATE_LIMITING_WINDOW. - mQcConstants.MAX_SESSION_COUNT_FREQUENT = - mQcConstants.MAX_SESSION_COUNT_PER_RATE_LIMITING_WINDOW + 1; - mQcConstants.updateConstants(); + setDeviceConfigInt(QcConstants.KEY_MAX_SESSION_COUNT_FREQUENT, + mQcConstants.MAX_SESSION_COUNT_PER_RATE_LIMITING_WINDOW + 1); final int standbyBucket = FREQUENT_INDEX; setProcessState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND); // No sessions saved yet. - mQuotaController.maybeScheduleStartAlarmLocked(SOURCE_USER_ID, SOURCE_PACKAGE, - standbyBucket); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeScheduleStartAlarmLocked( + SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket); + } verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any()); // Ran jobs up to the job limit. All of them should be allowed to run. @@ -2691,12 +3204,16 @@ public class QuotaControllerTest { JobStatus job = createJobStatus( "testStartAlarmScheduled_TimingSessionCount_AllowedTime", i); setStandbyBucket(FREQUENT_INDEX, job); - mQuotaController.maybeStartTrackingJobLocked(job, null); - assertTrue("Constraint not satisfied for job #" + (i + 1), - job.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA)); - mQuotaController.prepareForExecutionLocked(job); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStartTrackingJobLocked(job, null); + assertTrue("Constraint not satisfied for job #" + (i + 1), + job.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA)); + mQuotaController.prepareForExecutionLocked(job); + } advanceElapsedClock(SECOND_IN_MILLIS); - mQuotaController.maybeStopTrackingJobLocked(job, null, false); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStopTrackingJobLocked(job, null, false); + } advanceElapsedClock(SECOND_IN_MILLIS); } // Start alarm shouldn't have been scheduled since the app was in quota up until this point. @@ -2705,13 +3222,18 @@ public class QuotaControllerTest { // The app is now out of session count quota JobStatus throttledJob = createJobStatus( "testStartAlarmScheduled_TimingSessionCount_AllowedTime", 42); - mQuotaController.maybeStartTrackingJobLocked(throttledJob, null); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStartTrackingJobLocked(throttledJob, null); + } assertFalse(throttledJob.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA)); assertEquals(JobSchedulerService.sElapsedRealtimeClock.millis(), throttledJob.getWhenStandbyDeferred()); - ExecutionStats stats = mQuotaController.getExecutionStatsLocked(SOURCE_USER_ID, - SOURCE_PACKAGE, standbyBucket); + ExecutionStats stats; + synchronized (mQuotaController.mLock) { + stats = mQuotaController.getExecutionStatsLocked( + SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket); + } final long expectedWorkingAlarmTime = stats.sessionRateLimitExpirationTimeElapsed; verify(mAlarmManager, times(1)) .set(anyInt(), eq(expectedWorkingAlarmTime), eq(TAG_QUOTA_CHECK), any(), any()); diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml index 79936ce6d623..26fd0a21f10f 100644 --- a/services/tests/servicestests/AndroidManifest.xml +++ b/services/tests/servicestests/AndroidManifest.xml @@ -45,7 +45,7 @@ <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/> <uses-permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD"/> <uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT"/> - <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS"/> + <uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS"/> <uses-permission android:name="android.permission.INSTALL_PACKAGES"/> <uses-permission android:name="android.permission.CHANGE_CONFIGURATION"/> <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/> diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java index 241b5a9523b1..b360ae88b1ba 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java @@ -81,6 +81,7 @@ import com.android.server.appop.AppOpsService; import com.android.server.wm.ActivityTaskManagerService; import org.junit.After; +import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; @@ -128,11 +129,14 @@ public class ActivityManagerServiceTest { sPackageManagerInternal = mock(PackageManagerInternal.class); doReturn(new ComponentName("", "")).when(sPackageManagerInternal) .getSystemUiServiceComponent(); - // Remove stale instance of PackageManagerInternal if there is any - LocalServices.removeServiceForTest(PackageManagerInternal.class); LocalServices.addService(PackageManagerInternal.class, sPackageManagerInternal); } + @AfterClass + public static void tearDownOnce() { + LocalServices.removeServiceForTest(PackageManagerInternal.class); + } + @Rule public ServiceThreadRule mServiceThreadRule = new ServiceThreadRule(); private Context mContext = getInstrumentation().getTargetContext(); diff --git a/services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java b/services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java index b2d7177e04eb..4f58c87e61ea 100644 --- a/services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java +++ b/services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java @@ -35,6 +35,7 @@ import android.content.pm.PackageManagerInternal; import com.android.server.LocalServices; import com.android.server.wm.ActivityTaskManagerService; +import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; @@ -63,8 +64,6 @@ public class OomAdjusterTests { sPackageManagerInternal = mock(PackageManagerInternal.class); doReturn(new ComponentName("", "")).when(sPackageManagerInternal) .getSystemUiServiceComponent(); - // Remove stale instance of PackageManagerInternal if there is any - LocalServices.removeServiceForTest(PackageManagerInternal.class); LocalServices.addService(PackageManagerInternal.class, sPackageManagerInternal); // We need to run with dexmaker share class loader to make use of @@ -78,13 +77,18 @@ public class OomAdjusterTests { sService.mConstants = new ActivityManagerConstants(sContext, sService, sContext.getMainThreadHandler()); sService.mOomAdjuster = new OomAdjuster(sService, sService.mProcessList, null); - LocalServices.removeServiceForTest(UsageStatsManagerInternal.class); LocalServices.addService(UsageStatsManagerInternal.class, mock(UsageStatsManagerInternal.class)); sService.mUsageStatsService = LocalServices.getService(UsageStatsManagerInternal.class); }); } + @AfterClass + public static void tearDownOnce() { + LocalServices.removeServiceForTest(PackageManagerInternal.class); + LocalServices.removeServiceForTest(UsageStatsManagerInternal.class); + } + @Before public void setUpProcess() { // Need to run with dexmaker share class loader to mock package private class. 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 f0be9f1d3213..3b6059406785 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java @@ -262,7 +262,8 @@ public class BiometricServiceTest { verify(mBiometricService.mStatusBarService).showAuthenticationDialog( eq(mBiometricService.mCurrentAuthSession.mPromptInfo), any(IBiometricSysuiReceiver.class), - eq(0), + AdditionalMatchers.aryEq(new int[0]) /* sensorIds */, + eq(true) /* credentialAllowed */, anyBoolean() /* requireConfirmation */, anyInt() /* userId */, eq(TEST_PACKAGE_NAME), @@ -345,7 +346,8 @@ public class BiometricServiceTest { verify(mBiometricService.mStatusBarService).showAuthenticationDialog( eq(mBiometricService.mCurrentAuthSession.mPromptInfo), any(IBiometricSysuiReceiver.class), - eq(BiometricAuthenticator.TYPE_FACE), + AdditionalMatchers.aryEq(new int[] {SENSOR_ID_FACE}), + eq(false) /* credentialAllowed */, eq(false) /* requireConfirmation */, anyInt() /* userId */, eq(TEST_PACKAGE_NAME), @@ -477,7 +479,8 @@ public class BiometricServiceTest { verify(mBiometricService.mStatusBarService).showAuthenticationDialog( eq(mBiometricService.mCurrentAuthSession.mPromptInfo), any(IBiometricSysuiReceiver.class), - eq(BiometricAuthenticator.TYPE_FINGERPRINT), + any(), + eq(false) /* credentialAllowed */, anyBoolean() /* requireConfirmation */, anyInt() /* userId */, eq(TEST_PACKAGE_NAME), @@ -530,7 +533,8 @@ public class BiometricServiceTest { verify(mBiometricService.mStatusBarService).showAuthenticationDialog( eq(mBiometricService.mCurrentAuthSession.mPromptInfo), any(IBiometricSysuiReceiver.class), - eq(0 /* biometricModality */), + AdditionalMatchers.aryEq(new int[0]) /* sensorIds */, + eq(true) /* credentialAllowed */, anyBoolean() /* requireConfirmation */, anyInt() /* userId */, eq(TEST_PACKAGE_NAME), @@ -696,7 +700,8 @@ public class BiometricServiceTest { verify(mBiometricService.mStatusBarService, never()).showAuthenticationDialog( any(PromptInfo.class), any(IBiometricSysuiReceiver.class), - anyInt(), + any() /* sensorIds */, + anyBoolean() /* credentialAllowed */, anyBoolean() /* requireConfirmation */, anyInt() /* userId */, anyString(), @@ -796,7 +801,8 @@ public class BiometricServiceTest { verify(mBiometricService.mStatusBarService).showAuthenticationDialog( eq(mBiometricService.mCurrentAuthSession.mPromptInfo), any(IBiometricSysuiReceiver.class), - eq(0 /* biometricModality */), + AdditionalMatchers.aryEq(new int[0]) /* sensorIds */, + eq(true) /* credentialAllowed */, anyBoolean() /* requireConfirmation */, anyInt() /* userId */, eq(TEST_PACKAGE_NAME), @@ -874,7 +880,8 @@ public class BiometricServiceTest { verify(mBiometricService.mStatusBarService).showAuthenticationDialog( eq(mBiometricService.mCurrentAuthSession.mPromptInfo), any(IBiometricSysuiReceiver.class), - eq(0 /* biometricModality */), + AdditionalMatchers.aryEq(new int[0]) /* sensorIds */, + eq(true) /* credentialAllowed */, anyBoolean() /* requireConfirmation */, anyInt() /* userId */, eq(TEST_PACKAGE_NAME), @@ -1383,7 +1390,8 @@ public class BiometricServiceTest { verify(mBiometricService.mStatusBarService).showAuthenticationDialog( eq(mBiometricService.mCurrentAuthSession.mPromptInfo), any(IBiometricSysuiReceiver.class), - eq(BiometricAuthenticator.TYPE_FINGERPRINT /* biometricModality */), + AdditionalMatchers.aryEq(new int[] {testId}), + eq(false) /* credentialAllowed */, anyBoolean() /* requireConfirmation */, anyInt() /* userId */, eq(TEST_PACKAGE_NAME), @@ -1403,7 +1411,8 @@ public class BiometricServiceTest { verify(mBiometricService.mStatusBarService).showAuthenticationDialog( eq(mBiometricService.mCurrentAuthSession.mPromptInfo), any(IBiometricSysuiReceiver.class), - eq(BiometricAuthenticator.TYPE_NONE /* biometricModality */), + AdditionalMatchers.aryEq(new int[0]) /* sensorIds */, + eq(true) /* credentialAllowed */, anyBoolean() /* requireConfirmation */, anyInt() /* userId */, eq(TEST_PACKAGE_NAME), @@ -1426,7 +1435,8 @@ public class BiometricServiceTest { verify(mBiometricService.mStatusBarService).showAuthenticationDialog( eq(mBiometricService.mCurrentAuthSession.mPromptInfo), any(IBiometricSysuiReceiver.class), - eq(BiometricAuthenticator.TYPE_FINGERPRINT /* biometricModality */), + AdditionalMatchers.aryEq(new int[] {testId}) /* sensorIds */, + eq(false) /* credentialAllowed */, anyBoolean() /* requireConfirmation */, anyInt() /* userId */, eq(TEST_PACKAGE_NAME), diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index 30b1b3e78ad3..c4f7b9547277 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -2814,7 +2814,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { exerciseUserProvisioningTransitions(CALLER_USER_HANDLE, DevicePolicyManager.STATE_USER_PROFILE_COMPLETE, - DevicePolicyManager.STATE_USER_UNMANAGED); + DevicePolicyManager.STATE_USER_PROFILE_FINALIZED); } public void testSetUserProvisioningState_managedProfileFromSetupWizard_managedProfile() diff --git a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java index 058794a3b9e9..9b182a71f419 100644 --- a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java @@ -105,6 +105,30 @@ public final class DeviceStateManagerServiceTest { } @Test + public void requestOverrideState() { + mService.setOverrideState(OTHER_DEVICE_STATE); + // Committed state changes as there is a requested override. + assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE); + assertEquals(mService.getRequestedState(), DEFAULT_DEVICE_STATE); + assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), OTHER_DEVICE_STATE); + + // Committed state is set back to the requested state once the override is cleared. + mService.clearOverrideState(); + assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE); + assertEquals(mService.getRequestedState(), DEFAULT_DEVICE_STATE); + assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), DEFAULT_DEVICE_STATE); + } + + @Test + public void requestOverrideState_unsupportedState() { + mService.setOverrideState(UNSUPPORTED_DEVICE_STATE); + // Committed state remains the same as the override state is unsupported. + assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE); + assertEquals(mService.getRequestedState(), DEFAULT_DEVICE_STATE); + assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), DEFAULT_DEVICE_STATE); + } + + @Test public void supportedStatesChanged() { assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE); assertEquals(mService.getPendingState(), INVALID_DEVICE_STATE); @@ -146,6 +170,23 @@ public final class DeviceStateManagerServiceTest { assertEquals(mService.getRequestedState(), OTHER_DEVICE_STATE); } + @Test + public void supportedStatesChanged_unsupportedOverrideState() { + mService.setOverrideState(OTHER_DEVICE_STATE); + // Committed state changes as there is a requested override. + assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE); + assertEquals(mService.getRequestedState(), DEFAULT_DEVICE_STATE); + assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), OTHER_DEVICE_STATE); + + mProvider.notifySupportedDeviceStates(new int []{ DEFAULT_DEVICE_STATE }); + + // Committed state is set back to the requested state as the override state is no longer + // supported. + assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE); + assertEquals(mService.getRequestedState(), DEFAULT_DEVICE_STATE); + assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), DEFAULT_DEVICE_STATE); + } + private static final class TestDeviceStatePolicy implements DeviceStatePolicy { private final DeviceStateProvider mProvider; private int mLastDeviceStateRequestedToConfigure = INVALID_DEVICE_STATE; diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java index 5a05fc6eda4c..debf20bffe28 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java @@ -17,6 +17,7 @@ package com.android.server.hdmi; import static com.android.server.hdmi.HdmiCecMessageValidator.ERROR_DESTINATION; +import static com.android.server.hdmi.HdmiCecMessageValidator.ERROR_PARAMETER; import static com.android.server.hdmi.HdmiCecMessageValidator.ERROR_PARAMETER_SHORT; import static com.android.server.hdmi.HdmiCecMessageValidator.ERROR_SOURCE; import static com.android.server.hdmi.HdmiCecMessageValidator.OK; @@ -71,6 +72,44 @@ public class HdmiCecMessageValidatorTest { assertMessageValidity("04:90").isEqualTo(ERROR_PARAMETER_SHORT); } + @Test + public void isValid_setMenuLanguage() { + assertMessageValidity("4F:32:53:50:41").isEqualTo(OK); + assertMessageValidity("0F:32:45:4E:47:8C:49:D3:48").isEqualTo(OK); + + assertMessageValidity("40:32:53:50:41").isEqualTo(ERROR_DESTINATION); + assertMessageValidity("F0:32").isEqualTo(ERROR_SOURCE); + assertMessageValidity("4F:32:45:55").isEqualTo(ERROR_PARAMETER_SHORT); + assertMessageValidity("4F:32:19:7F:83").isEqualTo(ERROR_PARAMETER); + } + + @Test + public void isValid_setOsdString() { + assertMessageValidity("40:64:80:41").isEqualTo(OK); + // Even though the parameter string in this message is longer than 14 bytes, it is accepted + // as this parameter might be extended in future versions. + assertMessageValidity("04:64:00:4C:69:76:69:6E:67:52:6F:6F:6D:20:54:56:C4").isEqualTo(OK); + + assertMessageValidity("4F:64:40:41").isEqualTo(ERROR_DESTINATION); + assertMessageValidity("F0:64:C0:41").isEqualTo(ERROR_SOURCE); + assertMessageValidity("40:64:00").isEqualTo(ERROR_PARAMETER_SHORT); + // Invalid Display Control + assertMessageValidity("40:64:20:4C:69:76").isEqualTo(ERROR_PARAMETER); + // Invalid ASCII characters + assertMessageValidity("40:64:40:4C:69:7F").isEqualTo(ERROR_PARAMETER); + } + + @Test + public void isValid_setOsdName() { + assertMessageValidity("40:47:4C:69:76:69:6E:67:52:6F:6F:6D:54:56").isEqualTo(OK); + assertMessageValidity("40:47:54:56").isEqualTo(OK); + + assertMessageValidity("4F:47:54:56").isEqualTo(ERROR_DESTINATION); + assertMessageValidity("F0:47:54:56").isEqualTo(ERROR_SOURCE); + assertMessageValidity("40:47").isEqualTo(ERROR_PARAMETER_SHORT); + assertMessageValidity("40:47:4C:69:7F").isEqualTo(ERROR_PARAMETER); + } + private IntegerSubject assertMessageValidity(String message) { return assertThat(mHdmiCecMessageValidator.isValid(buildMessage(message))); } diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java index 8f631a307f15..382ae8218729 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java @@ -383,6 +383,41 @@ public class HdmiControlServiceTest { } + @Test + public void getCecVersion_default() { + assertThat(mHdmiControlService.getCecVersion()).isEqualTo(Constants.VERSION_1_4); + } + + @Test + public void getCecVersion_1_4() { + Settings.Global.putInt(mContextSpy.getContentResolver(), Settings.Global.HDMI_CEC_VERSION, + Constants.VERSION_1_4); + mHdmiControlService.setControlEnabled(true); + assertThat(mHdmiControlService.getCecVersion()).isEqualTo(Constants.VERSION_1_4); + } + + @Test + public void getCecVersion_2_0() { + Settings.Global.putInt(mContextSpy.getContentResolver(), Settings.Global.HDMI_CEC_VERSION, + Constants.VERSION_2_0); + mHdmiControlService.setControlEnabled(true); + assertThat(mHdmiControlService.getCecVersion()).isEqualTo(Constants.VERSION_2_0); + } + + @Test + public void getCecVersion_change() { + Settings.Global.putInt(mContextSpy.getContentResolver(), Settings.Global.HDMI_CEC_VERSION, + Constants.VERSION_1_4); + mHdmiControlService.setControlEnabled(true); + assertThat(mHdmiControlService.getCecVersion()).isEqualTo(Constants.VERSION_1_4); + + Settings.Global.putInt(mContextSpy.getContentResolver(), Settings.Global.HDMI_CEC_VERSION, + Constants.VERSION_2_0); + mHdmiControlService.setControlEnabled(true); + assertThat(mHdmiControlService.getCecVersion()).isEqualTo(Constants.VERSION_2_0); + } + + private static class VolumeControlFeatureCallback extends IHdmiCecVolumeControlFeatureListener.Stub { boolean mCallbackReceived = false; diff --git a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java index 72afca0300cd..9b25d0dc9c77 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java @@ -45,6 +45,7 @@ import androidx.test.runner.AndroidJUnit4; import com.android.server.pm.parsing.PackageParser2; import com.android.server.pm.parsing.TestPackageParser2; +import com.android.server.pm.parsing.pkg.AndroidPackage; import org.junit.Before; import org.junit.Test; @@ -288,6 +289,31 @@ public class ApexManagerTest { assertThat(mApexManager.isApkInApexInstallSuccess(activeApex.apexModuleName)).isFalse(); } + /** + * registerApkInApex method checks if the prefix of base apk path contains the apex package + * name. When an apex package name is a prefix of another apex package name, e.g, + * com.android.media and com.android.mediaprovider, then we need to ensure apk inside apex + * mediaprovider does not get registered under apex media. + */ + @Test + public void testRegisterApkInApexDoesNotRegisterSimilarPrefix() throws RemoteException { + when(mApexService.getActivePackages()).thenReturn(createApexInfo(true, true)); + final ApexManager.ActiveApexInfo activeApex = mApexManager.getActiveApexInfos().get(0); + assertThat(activeApex.apexModuleName).isEqualTo(TEST_APEX_PKG); + + AndroidPackage fakeApkInApex = mock(AndroidPackage.class); + when(fakeApkInApex.getBaseApkPath()).thenReturn("/apex/" + TEST_APEX_PKG + "randomSuffix"); + when(fakeApkInApex.getPackageName()).thenReturn("randomPackageName"); + + when(mApexService.getAllPackages()).thenReturn(createApexInfo(true, true)); + mApexManager.scanApexPackagesTraced(mPackageParser2, + ParallelPackageParser.makeExecutorService()); + + assertThat(mApexManager.getApksInApex(activeApex.apexModuleName)).isEmpty(); + mApexManager.registerApkInApex(fakeApkInApex); + assertThat(mApexManager.getApksInApex(activeApex.apexModuleName)).isEmpty(); + } + private ApexInfo[] createApexInfo(boolean isActive, boolean isFactory) { File apexFile = extractResource(TEST_APEX_PKG, TEST_APEX_FILE_NAME); ApexInfo apexInfo = new ApexInfo(); diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml index 9099272a0fd6..7f4f3dd58812 100644 --- a/services/tests/wmtests/AndroidManifest.xml +++ b/services/tests/wmtests/AndroidManifest.xml @@ -24,7 +24,7 @@ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" /> <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" /> - <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" /> + <uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS" /> <uses-permission android:name="android.permission.GET_TOP_ACTIVITY_INFO" /> <uses-permission android:name="android.permission.MANAGE_USERS" /> <uses-permission android:name="android.permission.STORAGE_INTERNAL" /> diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java index 64a05bb361e9..823aef095831 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java @@ -19,13 +19,14 @@ package com.android.server.wm; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.content.ClipDescription.MIMETYPE_APPLICATION_ACTIVITY; +import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT; +import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK; import static android.view.DragEvent.ACTION_DRAG_STARTED; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; @@ -33,7 +34,6 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.verify; import android.app.PendingIntent; @@ -82,6 +82,8 @@ import java.util.concurrent.TimeUnit; @RunWith(WindowTestRunner.class) public class DragDropControllerTests extends WindowTestsBase { private static final int TIMEOUT_MS = 3000; + private static final int TEST_UID = 12345; + private TestDragDropController mTarget; private WindowState mWindow; private IBinder mToken; @@ -195,8 +197,7 @@ public class DragDropControllerTests extends WindowTestsBase { attrs.privateFlags |= PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP; policy.validateAddingWindowLw(attrs, Binder.getCallingPid(), Binder.getCallingUid()); - verify(mWm.mContext).enforcePermission( - eq(android.Manifest.permission.MANAGE_ACTIVITY_STACKS), anyInt(), anyInt(), any()); + verify(mWm.mAtmService).enforceTaskPermission(any()); } @Test @@ -278,6 +279,42 @@ public class DragDropControllerTests extends WindowTestsBase { return clipData; } + @Test + public void testValidateAppShortcutArguments() { + final Session session = new Session(mWm, new IWindowSessionCallback.Stub() { + @Override + public void onAnimatorScaleChanged(float scale) {} + }); + try { + final ClipData clipData = new ClipData( + new ClipDescription("drag", new String[] { MIMETYPE_APPLICATION_SHORTCUT }), + new ClipData.Item(new Intent())); + + session.validateAndResolveDragMimeTypeExtras(clipData, TEST_UID); + fail("Expected failure without shortcut id"); + } catch (IllegalArgumentException e) { + // Expected failure + } + } + + @Test + public void testValidateAppTaskArguments() { + final Session session = new Session(mWm, new IWindowSessionCallback.Stub() { + @Override + public void onAnimatorScaleChanged(float scale) {} + }); + try { + final ClipData clipData = new ClipData( + new ClipDescription("drag", new String[] { MIMETYPE_APPLICATION_TASK }), + new ClipData.Item(new Intent())); + + session.validateAndResolveDragMimeTypeExtras(clipData, TEST_UID); + fail("Expected failure without task id"); + } catch (IllegalArgumentException e) { + // Expected failure + } + } + private void doDragAndDrop(int flags, ClipData data, float dropX, float dropY) { startDrag(flags, data, () -> { mTarget.handleMotionEvent(false, dropX, dropY); diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java index 2985796d005f..8094c9767b39 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java @@ -394,6 +394,21 @@ public class RecentsAnimationControllerTest extends WindowTestsBase { // The rotation transform should be cleared after updating orientation with display. assertFalse(activity.hasFixedRotationTransform()); assertFalse(mDefaultDisplay.hasTopFixedRotationLaunchingApp()); + + // Simulate swiping up recents (home) in different rotation. + final ActivityRecord home = mDefaultDisplay.getDefaultTaskDisplayArea().getHomeActivity(); + mDefaultDisplay.setFixedRotationLaunchingApp(home, (mDefaultDisplay.getRotation() + 1) % 4); + mController = new RecentsAnimationController(mWm, mMockRunner, mAnimationCallbacks, + mDefaultDisplay.getDisplayId()); + initializeRecentsAnimationController(mController, home); + assertTrue(home.hasFixedRotationTransform()); + + // Assume recents activity becomes invisible for some reason (e.g. screen off). + home.setVisible(false); + mController.cleanupAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION); + // Although there won't be a transition finish callback, the fixed rotation must be cleared. + assertFalse(home.hasFixedRotationTransform()); + assertFalse(mDefaultDisplay.hasTopFixedRotationLaunchingApp()); } @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java index ace0400bc293..91e55ed7ab6a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java @@ -23,6 +23,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; @@ -194,4 +195,29 @@ public class TaskTests extends WindowTestsBase { assertEquals(1, rootTask.getChildCount()); assertEquals(leafTask1, childTask.getTopChild()); } + + @Test + public void testEnsureActivitiesVisible() { + final Task rootTask = createTaskStackOnDisplay(mDisplayContent); + final Task leafTask1 = createTaskInStack(rootTask, 0 /* userId */); + final Task leafTask2 = createTaskInStack(rootTask, 0 /* userId */); + final ActivityRecord activity1 = createActivityRecordInTask(mDisplayContent, leafTask1); + final ActivityRecord activity2 = createActivityRecordInTask(mDisplayContent, leafTask2); + + // Check visibility of occluded tasks + doReturn(false).when(leafTask1).shouldBeVisible(any()); + doReturn(true).when(leafTask2).shouldBeVisible(any()); + rootTask.ensureActivitiesVisible( + null /* starting */ , 0 /* configChanges */, false /* preserveWindows */); + assertFalse(activity1.isVisible()); + assertTrue(activity2.isVisible()); + + // Check visibility of not occluded tasks + doReturn(true).when(leafTask1).shouldBeVisible(any()); + doReturn(true).when(leafTask2).shouldBeVisible(any()); + rootTask.ensureActivitiesVisible( + null /* starting */ , 0 /* configChanges */, false /* preserveWindows */); + assertTrue(activity1.isVisible()); + assertTrue(activity2.isVisible()); + } } diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java index 82da4475c1b9..ae485d502a1e 100644 --- a/telecomm/java/android/telecom/TelecomManager.java +++ b/telecomm/java/android/telecom/TelecomManager.java @@ -32,6 +32,7 @@ import android.content.Intent; import android.net.Uri; import android.os.Build; import android.os.Bundle; +import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; @@ -1605,6 +1606,30 @@ public class TelecomManager { } /** + * Returns whether the caller has {@link InCallService} access for companion apps. + * + * A companion app is an app associated with a physical wearable device via the + * {@link android.companion.CompanionDeviceManager} API. + * + * @return {@code true} if the caller has {@link InCallService} access for + * companion app; {@code false} otherwise. + */ + public boolean hasCompanionInCallServiceAccess() { + try { + if (isServiceConnected()) { + return getTelecomService().hasCompanionInCallServiceAccess( + mContext.getOpPackageName()); + } + } catch (RemoteException e) { + Log.e(TAG, "RemoteException calling hasCompanionInCallServiceAccess().", e); + if (!isSystemProcess()) { + e.rethrowAsRuntimeException(); + } + } + return false; + } + + /** * Returns whether there is an ongoing call originating from a managed * {@link ConnectionService}. An ongoing call can be in dialing, ringing, active or holding * states. @@ -2416,6 +2441,10 @@ public class TelecomManager { } } + private boolean isSystemProcess() { + return Process.myUid() == Process.SYSTEM_UID; + } + private ITelecomService getTelecomService() { if (mTelecomServiceOverride != null) { return mTelecomServiceOverride; diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl index 7c6f1df972f3..e636b93deace 100644 --- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl +++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl @@ -179,6 +179,11 @@ interface ITelecomService { boolean isInCall(String callingPackage, String callingFeatureId); /** + * @see TelecomServiceImpl#hasCompanionInCallServiceAccess + */ + boolean hasCompanionInCallServiceAccess(String callingPackage); + + /** * @see TelecomServiceImpl#isInManagedCall */ boolean isInManagedCall(String callingPackage, String callingFeatureId); diff --git a/telephony/api/system-current.txt b/telephony/api/system-current.txt deleted file mode 100644 index a58b6d84cbd1..000000000000 --- a/telephony/api/system-current.txt +++ /dev/null @@ -1,2107 +0,0 @@ -// Signature format: 2.0 -package android.telephony { - - public final class AccessNetworkConstants { - field public static final int TRANSPORT_TYPE_INVALID = -1; // 0xffffffff - } - - public static final class AccessNetworkConstants.NgranBands { - method public static int getFrequencyRangeGroup(int); - field public static final int FREQUENCY_RANGE_GROUP_1 = 1; // 0x1 - field public static final int FREQUENCY_RANGE_GROUP_2 = 2; // 0x2 - field public static final int FREQUENCY_RANGE_GROUP_UNKNOWN = 0; // 0x0 - } - - public final class BarringInfo implements android.os.Parcelable { - ctor public BarringInfo(); - method @NonNull public android.telephony.BarringInfo createLocationInfoSanitizedCopy(); - } - - public final class CallAttributes implements android.os.Parcelable { - ctor public CallAttributes(@NonNull android.telephony.PreciseCallState, int, @NonNull android.telephony.CallQuality); - method public int describeContents(); - method @NonNull public android.telephony.CallQuality getCallQuality(); - method public int getNetworkType(); - method @NonNull public android.telephony.PreciseCallState getPreciseCallState(); - method public void writeToParcel(android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CallAttributes> CREATOR; - } - - public final class CallForwardingInfo implements android.os.Parcelable { - ctor public CallForwardingInfo(boolean, int, @Nullable String, int); - method public int describeContents(); - method @Nullable public String getNumber(); - method public int getReason(); - method public int getTimeoutSeconds(); - method public boolean isEnabled(); - field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CallForwardingInfo> CREATOR; - field public static final int REASON_ALL = 4; // 0x4 - field public static final int REASON_ALL_CONDITIONAL = 5; // 0x5 - field public static final int REASON_BUSY = 1; // 0x1 - field public static final int REASON_NOT_REACHABLE = 3; // 0x3 - field public static final int REASON_NO_REPLY = 2; // 0x2 - field public static final int REASON_UNCONDITIONAL = 0; // 0x0 - } - - public final class CallQuality implements android.os.Parcelable { - ctor public CallQuality(int, int, int, int, int, int, int, int, int, int, int); - ctor public CallQuality(int, int, int, int, int, int, int, int, int, int, int, boolean, boolean, boolean); - method public int describeContents(); - method public int getAverageRelativeJitter(); - method public int getAverageRoundTripTime(); - method public int getCallDuration(); - method public int getCodecType(); - method public int getDownlinkCallQualityLevel(); - method public int getMaxRelativeJitter(); - method public int getNumRtpPacketsNotReceived(); - method public int getNumRtpPacketsReceived(); - method public int getNumRtpPacketsTransmitted(); - method public int getNumRtpPacketsTransmittedLost(); - method public int getUplinkCallQualityLevel(); - method public boolean isIncomingSilenceDetectedAtCallSetup(); - method public boolean isOutgoingSilenceDetectedAtCallSetup(); - method public boolean isRtpInactivityDetected(); - method public void writeToParcel(android.os.Parcel, int); - field public static final int CALL_QUALITY_BAD = 4; // 0x4 - field public static final int CALL_QUALITY_EXCELLENT = 0; // 0x0 - field public static final int CALL_QUALITY_FAIR = 2; // 0x2 - field public static final int CALL_QUALITY_GOOD = 1; // 0x1 - field public static final int CALL_QUALITY_NOT_AVAILABLE = 5; // 0x5 - field public static final int CALL_QUALITY_POOR = 3; // 0x3 - field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CallQuality> CREATOR; - } - - public class CarrierConfigManager { - method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getDefaultCarrierServicePackageName(); - method @NonNull public static android.os.PersistableBundle getDefaultConfig(); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void overrideConfig(int, @Nullable android.os.PersistableBundle); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void updateConfigForPhoneId(int, String); - field public static final String KEY_CARRIER_SETUP_APP_STRING = "carrier_setup_app_string"; - field public static final String KEY_SUPPORT_CDMA_1X_VOICE_CALLS_BOOL = "support_cdma_1x_voice_calls_bool"; - } - - public static final class CarrierConfigManager.Wifi { - field public static final String KEY_HOTSPOT_MAX_CLIENT_COUNT = "wifi.hotspot_maximum_client_count"; - field public static final String KEY_PREFIX = "wifi."; - } - - public final class CarrierRestrictionRules implements android.os.Parcelable { - method @NonNull public java.util.List<java.lang.Boolean> areCarrierIdentifiersAllowed(@NonNull java.util.List<android.service.carrier.CarrierIdentifier>); - method public int describeContents(); - method @NonNull public java.util.List<android.service.carrier.CarrierIdentifier> getAllowedCarriers(); - method public int getDefaultCarrierRestriction(); - method @NonNull public java.util.List<android.service.carrier.CarrierIdentifier> getExcludedCarriers(); - method public int getMultiSimPolicy(); - method public boolean isAllCarriersAllowed(); - method public void writeToParcel(android.os.Parcel, int); - field public static final int CARRIER_RESTRICTION_DEFAULT_ALLOWED = 1; // 0x1 - field public static final int CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED = 0; // 0x0 - field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CarrierRestrictionRules> CREATOR; - field public static final int MULTISIM_POLICY_NONE = 0; // 0x0 - field public static final int MULTISIM_POLICY_ONE_VALID_SIM_MUST_BE_PRESENT = 1; // 0x1 - } - - public static final class CarrierRestrictionRules.Builder { - ctor public CarrierRestrictionRules.Builder(); - method @NonNull public android.telephony.CarrierRestrictionRules build(); - method @NonNull public android.telephony.CarrierRestrictionRules.Builder setAllCarriersAllowed(); - method @NonNull public android.telephony.CarrierRestrictionRules.Builder setAllowedCarriers(@NonNull java.util.List<android.service.carrier.CarrierIdentifier>); - method @NonNull public android.telephony.CarrierRestrictionRules.Builder setDefaultCarrierRestriction(int); - method @NonNull public android.telephony.CarrierRestrictionRules.Builder setExcludedCarriers(@NonNull java.util.List<android.service.carrier.CarrierIdentifier>); - method @NonNull public android.telephony.CarrierRestrictionRules.Builder setMultiSimPolicy(int); - } - - public class CbGeoUtils { - } - - public static class CbGeoUtils.Circle implements android.telephony.CbGeoUtils.Geometry { - ctor public CbGeoUtils.Circle(@NonNull android.telephony.CbGeoUtils.LatLng, double); - method public boolean contains(@NonNull android.telephony.CbGeoUtils.LatLng); - method @NonNull public android.telephony.CbGeoUtils.LatLng getCenter(); - method public double getRadius(); - } - - public static interface CbGeoUtils.Geometry { - method public boolean contains(@NonNull android.telephony.CbGeoUtils.LatLng); - } - - public static class CbGeoUtils.LatLng { - ctor public CbGeoUtils.LatLng(double, double); - method public double distance(@NonNull android.telephony.CbGeoUtils.LatLng); - method @NonNull public android.telephony.CbGeoUtils.LatLng subtract(@NonNull android.telephony.CbGeoUtils.LatLng); - field public final double lat; - field public final double lng; - } - - public static class CbGeoUtils.Polygon implements android.telephony.CbGeoUtils.Geometry { - ctor public CbGeoUtils.Polygon(@NonNull java.util.List<android.telephony.CbGeoUtils.LatLng>); - method public boolean contains(@NonNull android.telephony.CbGeoUtils.LatLng); - method @NonNull public java.util.List<android.telephony.CbGeoUtils.LatLng> getVertices(); - } - - public abstract class CellBroadcastService extends android.app.Service { - ctor public CellBroadcastService(); - method @NonNull @WorkerThread public abstract CharSequence getCellBroadcastAreaInfo(int); - method public android.os.IBinder onBind(@Nullable android.content.Intent); - method public abstract void onCdmaCellBroadcastSms(int, @NonNull byte[], int); - method public abstract void onCdmaScpMessage(int, @NonNull java.util.List<android.telephony.cdma.CdmaSmsCbProgramData>, @NonNull String, @NonNull java.util.function.Consumer<android.os.Bundle>); - method public abstract void onGsmCellBroadcastSms(int, @NonNull byte[]); - field public static final String CELL_BROADCAST_SERVICE_INTERFACE = "android.telephony.CellBroadcastService"; - } - - public abstract class CellIdentity implements android.os.Parcelable { - method @NonNull public abstract android.telephony.CellLocation asCellLocation(); - method @NonNull public abstract android.telephony.CellIdentity sanitizeLocationInfo(); - } - - public final class CellIdentityCdma extends android.telephony.CellIdentity { - method @NonNull public android.telephony.cdma.CdmaCellLocation asCellLocation(); - method @NonNull public android.telephony.CellIdentityCdma sanitizeLocationInfo(); - } - - public final class CellIdentityGsm extends android.telephony.CellIdentity { - method @NonNull public android.telephony.gsm.GsmCellLocation asCellLocation(); - method @NonNull public android.telephony.CellIdentityGsm sanitizeLocationInfo(); - } - - public final class CellIdentityLte extends android.telephony.CellIdentity { - method @NonNull public android.telephony.gsm.GsmCellLocation asCellLocation(); - method @NonNull public android.telephony.CellIdentityLte sanitizeLocationInfo(); - } - - public final class CellIdentityNr extends android.telephony.CellIdentity { - method @NonNull public android.telephony.CellLocation asCellLocation(); - method @NonNull public android.telephony.CellIdentityNr sanitizeLocationInfo(); - } - - public final class CellIdentityTdscdma extends android.telephony.CellIdentity { - method @NonNull public android.telephony.gsm.GsmCellLocation asCellLocation(); - method @NonNull public android.telephony.CellIdentityTdscdma sanitizeLocationInfo(); - } - - public final class CellIdentityWcdma extends android.telephony.CellIdentity { - method @NonNull public android.telephony.gsm.GsmCellLocation asCellLocation(); - method @NonNull public android.telephony.CellIdentityWcdma sanitizeLocationInfo(); - } - - public final class DataFailCause { - field @Deprecated public static final int VSNCP_APN_UNATHORIZED = 2238; // 0x8be - } - - public final class DataSpecificRegistrationInfo implements android.os.Parcelable { - method public int describeContents(); - method @NonNull public android.telephony.LteVopsSupportInfo getLteVopsSupportInfo(); - method public void writeToParcel(android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.telephony.DataSpecificRegistrationInfo> CREATOR; - } - - public final class ImsiEncryptionInfo implements android.os.Parcelable { - method public int describeContents(); - method @Nullable public String getKeyIdentifier(); - method @Nullable public java.security.PublicKey getPublicKey(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ImsiEncryptionInfo> CREATOR; - } - - public final class LteVopsSupportInfo implements android.os.Parcelable { - ctor public LteVopsSupportInfo(int, int); - method public int describeContents(); - method public int getEmcBearerSupport(); - method public int getVopsSupport(); - method public void writeToParcel(android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.telephony.LteVopsSupportInfo> CREATOR; - field public static final int LTE_STATUS_NOT_AVAILABLE = 1; // 0x1 - field public static final int LTE_STATUS_NOT_SUPPORTED = 3; // 0x3 - field public static final int LTE_STATUS_SUPPORTED = 2; // 0x2 - } - - public class MbmsDownloadSession implements java.lang.AutoCloseable { - field public static final String MBMS_DOWNLOAD_SERVICE_ACTION = "android.telephony.action.EmbmsDownload"; - } - - public class MbmsGroupCallSession implements java.lang.AutoCloseable { - field public static final String MBMS_GROUP_CALL_SERVICE_ACTION = "android.telephony.action.EmbmsGroupCall"; - } - - public class MbmsStreamingSession implements java.lang.AutoCloseable { - field public static final String MBMS_STREAMING_SERVICE_ACTION = "android.telephony.action.EmbmsStreaming"; - } - - public final class ModemActivityInfo implements android.os.Parcelable { - method public int describeContents(); - method @NonNull public android.telephony.ModemActivityInfo getDelta(@NonNull android.telephony.ModemActivityInfo); - method public long getIdleTimeMillis(); - method public static int getNumTxPowerLevels(); - method public long getReceiveTimeMillis(); - method public long getSleepTimeMillis(); - method public long getTimestampMillis(); - method public long getTransmitDurationMillisAtPowerLevel(int); - method @NonNull public android.util.Range<java.lang.Integer> getTransmitPowerRange(int); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ModemActivityInfo> CREATOR; - field public static final int TX_POWER_LEVEL_0 = 0; // 0x0 - field public static final int TX_POWER_LEVEL_1 = 1; // 0x1 - field public static final int TX_POWER_LEVEL_2 = 2; // 0x2 - field public static final int TX_POWER_LEVEL_3 = 3; // 0x3 - field public static final int TX_POWER_LEVEL_4 = 4; // 0x4 - } - - public final class NetworkRegistrationInfo implements android.os.Parcelable { - method @Nullable public android.telephony.DataSpecificRegistrationInfo getDataSpecificInfo(); - method public int getRegistrationState(); - method public int getRejectCause(); - method public int getRoamingType(); - method public boolean isEmergencyEnabled(); - method public void writeToParcel(android.os.Parcel, int); - field public static final int REGISTRATION_STATE_DENIED = 3; // 0x3 - field public static final int REGISTRATION_STATE_HOME = 1; // 0x1 - field public static final int REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING = 0; // 0x0 - field public static final int REGISTRATION_STATE_NOT_REGISTERED_SEARCHING = 2; // 0x2 - field public static final int REGISTRATION_STATE_ROAMING = 5; // 0x5 - field public static final int REGISTRATION_STATE_UNKNOWN = 4; // 0x4 - } - - public static final class NetworkRegistrationInfo.Builder { - ctor public NetworkRegistrationInfo.Builder(); - method @NonNull public android.telephony.NetworkRegistrationInfo build(); - method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setAccessNetworkTechnology(int); - method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setAvailableServices(@NonNull java.util.List<java.lang.Integer>); - method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setCellIdentity(@Nullable android.telephony.CellIdentity); - method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setDomain(int); - method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setEmergencyOnly(boolean); - method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setRegisteredPlmn(@Nullable String); - method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setRegistrationState(int); - method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setRejectCause(int); - method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setTransportType(int); - } - - public abstract class NetworkService extends android.app.Service { - ctor public NetworkService(); - method public android.os.IBinder onBind(android.content.Intent); - method @Nullable public abstract android.telephony.NetworkService.NetworkServiceProvider onCreateNetworkServiceProvider(int); - field public static final String SERVICE_INTERFACE = "android.telephony.NetworkService"; - } - - public abstract class NetworkService.NetworkServiceProvider implements java.lang.AutoCloseable { - ctor public NetworkService.NetworkServiceProvider(int); - method public abstract void close(); - method public final int getSlotIndex(); - method public final void notifyNetworkRegistrationInfoChanged(); - method public void requestNetworkRegistrationInfo(int, @NonNull android.telephony.NetworkServiceCallback); - } - - public class NetworkServiceCallback { - method public void onRequestNetworkRegistrationInfoComplete(int, @Nullable android.telephony.NetworkRegistrationInfo); - field public static final int RESULT_ERROR_BUSY = 3; // 0x3 - field public static final int RESULT_ERROR_FAILED = 5; // 0x5 - field public static final int RESULT_ERROR_ILLEGAL_STATE = 4; // 0x4 - field public static final int RESULT_ERROR_INVALID_ARG = 2; // 0x2 - field public static final int RESULT_ERROR_UNSUPPORTED = 1; // 0x1 - field public static final int RESULT_SUCCESS = 0; // 0x0 - } - - public interface NumberVerificationCallback { - method public default void onCallReceived(@NonNull String); - method public default void onVerificationFailed(int); - field public static final int REASON_CONCURRENT_REQUESTS = 4; // 0x4 - field public static final int REASON_IN_ECBM = 5; // 0x5 - field public static final int REASON_IN_EMERGENCY_CALL = 6; // 0x6 - field public static final int REASON_NETWORK_NOT_AVAILABLE = 2; // 0x2 - field public static final int REASON_TIMED_OUT = 1; // 0x1 - field public static final int REASON_TOO_MANY_CALLS = 3; // 0x3 - field public static final int REASON_UNSPECIFIED = 0; // 0x0 - } - - public final class PhoneNumberRange implements android.os.Parcelable { - ctor public PhoneNumberRange(@NonNull String, @NonNull String, @NonNull String, @NonNull String); - method public int describeContents(); - method public boolean matches(@NonNull String); - method public void writeToParcel(android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.telephony.PhoneNumberRange> CREATOR; - } - - public class PhoneNumberUtils { - method @NonNull public static String getUsernameFromUriNumber(@NonNull String); - method public static boolean isUriNumber(@Nullable String); - method public static boolean isVoiceMailNumber(@NonNull android.content.Context, int, @Nullable String); - } - - public final class PhysicalChannelConfig implements android.os.Parcelable { - method public int describeContents(); - method public int getCellBandwidthDownlink(); - method public int getChannelNumber(); - method public int getConnectionStatus(); - method public int getNetworkType(); - method @IntRange(from=0, to=1007) public int getPhysicalCellId(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field public static final int CHANNEL_NUMBER_UNKNOWN = -1; // 0xffffffff - field public static final int CONNECTION_PRIMARY_SERVING = 1; // 0x1 - field public static final int CONNECTION_SECONDARY_SERVING = 2; // 0x2 - field public static final int CONNECTION_UNKNOWN = -1; // 0xffffffff - field @NonNull public static final android.os.Parcelable.Creator<android.telephony.PhysicalChannelConfig> CREATOR; - field public static final int PHYSICAL_CELL_ID_UNKNOWN = -1; // 0xffffffff - } - - public final class PreciseCallState implements android.os.Parcelable { - ctor public PreciseCallState(int, int, int, int, int); - method public int describeContents(); - method public int getBackgroundCallState(); - method public int getForegroundCallState(); - method public int getRingingCallState(); - method public void writeToParcel(android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.telephony.PreciseCallState> CREATOR; - field public static final int PRECISE_CALL_STATE_ACTIVE = 1; // 0x1 - field public static final int PRECISE_CALL_STATE_ALERTING = 4; // 0x4 - field public static final int PRECISE_CALL_STATE_DIALING = 3; // 0x3 - field public static final int PRECISE_CALL_STATE_DISCONNECTED = 7; // 0x7 - field public static final int PRECISE_CALL_STATE_DISCONNECTING = 8; // 0x8 - field public static final int PRECISE_CALL_STATE_HOLDING = 2; // 0x2 - field public static final int PRECISE_CALL_STATE_IDLE = 0; // 0x0 - field public static final int PRECISE_CALL_STATE_INCOMING = 5; // 0x5 - field public static final int PRECISE_CALL_STATE_NOT_VALID = -1; // 0xffffffff - field public static final int PRECISE_CALL_STATE_WAITING = 6; // 0x6 - } - - public final class PreciseDataConnectionState implements android.os.Parcelable { - method @Deprecated @NonNull public String getDataConnectionApn(); - method @Deprecated public int getDataConnectionApnTypeBitMask(); - method @Deprecated public int getDataConnectionFailCause(); - method @Deprecated public int getDataConnectionState(); - method public int getId(); - } - - public final class PreciseDisconnectCause { - field public static final int ACCESS_CLASS_BLOCKED = 260; // 0x104 - field public static final int ACCESS_INFORMATION_DISCARDED = 43; // 0x2b - field public static final int ACM_LIMIT_EXCEEDED = 68; // 0x44 - field public static final int BEARER_CAPABILITY_NOT_AUTHORIZED = 57; // 0x39 - field public static final int BEARER_NOT_AVAIL = 58; // 0x3a - field public static final int BEARER_SERVICE_NOT_IMPLEMENTED = 65; // 0x41 - field public static final int BUSY = 17; // 0x11 - field public static final int CALL_BARRED = 240; // 0xf0 - field public static final int CALL_REJECTED = 21; // 0x15 - field public static final int CDMA_ACCESS_BLOCKED = 1009; // 0x3f1 - field public static final int CDMA_ACCESS_FAILURE = 1006; // 0x3ee - field public static final int CDMA_DROP = 1001; // 0x3e9 - field public static final int CDMA_INTERCEPT = 1002; // 0x3ea - field public static final int CDMA_LOCKED_UNTIL_POWER_CYCLE = 1000; // 0x3e8 - field public static final int CDMA_NOT_EMERGENCY = 1008; // 0x3f0 - field public static final int CDMA_PREEMPTED = 1007; // 0x3ef - field public static final int CDMA_REORDER = 1003; // 0x3eb - field public static final int CDMA_RETRY_ORDER = 1005; // 0x3ed - field public static final int CDMA_SO_REJECT = 1004; // 0x3ec - field public static final int CHANNEL_NOT_AVAIL = 44; // 0x2c - field public static final int CHANNEL_UNACCEPTABLE = 6; // 0x6 - field public static final int CONDITIONAL_IE_ERROR = 100; // 0x64 - field public static final int DESTINATION_OUT_OF_ORDER = 27; // 0x1b - field public static final int ERROR_UNSPECIFIED = 65535; // 0xffff - field public static final int FACILITY_REJECTED = 29; // 0x1d - field public static final int FDN_BLOCKED = 241; // 0xf1 - field public static final int IMEI_NOT_ACCEPTED = 243; // 0xf3 - field public static final int IMSI_UNKNOWN_IN_VLR = 242; // 0xf2 - field public static final int INCOMING_CALLS_BARRED_WITHIN_CUG = 55; // 0x37 - field public static final int INCOMPATIBLE_DESTINATION = 88; // 0x58 - field public static final int INFORMATION_ELEMENT_NON_EXISTENT = 99; // 0x63 - field public static final int INTERWORKING_UNSPECIFIED = 127; // 0x7f - field public static final int INVALID_MANDATORY_INFORMATION = 96; // 0x60 - field public static final int INVALID_NUMBER_FORMAT = 28; // 0x1c - field public static final int INVALID_TRANSACTION_IDENTIFIER = 81; // 0x51 - field public static final int MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 101; // 0x65 - field public static final int MESSAGE_TYPE_NON_IMPLEMENTED = 97; // 0x61 - field public static final int MESSAGE_TYPE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 98; // 0x62 - field public static final int NETWORK_DETACH = 261; // 0x105 - field public static final int NETWORK_OUT_OF_ORDER = 38; // 0x26 - field public static final int NETWORK_REJECT = 252; // 0xfc - field public static final int NETWORK_RESP_TIMEOUT = 251; // 0xfb - field public static final int NORMAL = 16; // 0x10 - field public static final int NORMAL_UNSPECIFIED = 31; // 0x1f - field public static final int NOT_VALID = -1; // 0xffffffff - field public static final int NO_ANSWER_FROM_USER = 19; // 0x13 - field public static final int NO_CIRCUIT_AVAIL = 34; // 0x22 - field public static final int NO_DISCONNECT_CAUSE_AVAILABLE = 0; // 0x0 - field public static final int NO_ROUTE_TO_DESTINATION = 3; // 0x3 - field public static final int NO_USER_RESPONDING = 18; // 0x12 - field public static final int NO_VALID_SIM = 249; // 0xf9 - field public static final int NUMBER_CHANGED = 22; // 0x16 - field public static final int OEM_CAUSE_1 = 61441; // 0xf001 - field public static final int OEM_CAUSE_10 = 61450; // 0xf00a - field public static final int OEM_CAUSE_11 = 61451; // 0xf00b - field public static final int OEM_CAUSE_12 = 61452; // 0xf00c - field public static final int OEM_CAUSE_13 = 61453; // 0xf00d - field public static final int OEM_CAUSE_14 = 61454; // 0xf00e - field public static final int OEM_CAUSE_15 = 61455; // 0xf00f - field public static final int OEM_CAUSE_2 = 61442; // 0xf002 - field public static final int OEM_CAUSE_3 = 61443; // 0xf003 - field public static final int OEM_CAUSE_4 = 61444; // 0xf004 - field public static final int OEM_CAUSE_5 = 61445; // 0xf005 - field public static final int OEM_CAUSE_6 = 61446; // 0xf006 - field public static final int OEM_CAUSE_7 = 61447; // 0xf007 - field public static final int OEM_CAUSE_8 = 61448; // 0xf008 - field public static final int OEM_CAUSE_9 = 61449; // 0xf009 - field public static final int ONLY_DIGITAL_INFORMATION_BEARER_AVAILABLE = 70; // 0x46 - field public static final int OPERATOR_DETERMINED_BARRING = 8; // 0x8 - field public static final int OUT_OF_SRV = 248; // 0xf8 - field public static final int PREEMPTION = 25; // 0x19 - field public static final int PROTOCOL_ERROR_UNSPECIFIED = 111; // 0x6f - field public static final int QOS_NOT_AVAIL = 49; // 0x31 - field public static final int RADIO_ACCESS_FAILURE = 253; // 0xfd - field public static final int RADIO_INTERNAL_ERROR = 250; // 0xfa - field public static final int RADIO_LINK_FAILURE = 254; // 0xfe - field public static final int RADIO_LINK_LOST = 255; // 0xff - field public static final int RADIO_OFF = 247; // 0xf7 - field public static final int RADIO_RELEASE_ABNORMAL = 259; // 0x103 - field public static final int RADIO_RELEASE_NORMAL = 258; // 0x102 - field public static final int RADIO_SETUP_FAILURE = 257; // 0x101 - field public static final int RADIO_UPLINK_FAILURE = 256; // 0x100 - field public static final int RECOVERY_ON_TIMER_EXPIRED = 102; // 0x66 - field public static final int REQUESTED_FACILITY_NOT_IMPLEMENTED = 69; // 0x45 - field public static final int REQUESTED_FACILITY_NOT_SUBSCRIBED = 50; // 0x32 - field public static final int RESOURCES_UNAVAILABLE_OR_UNSPECIFIED = 47; // 0x2f - field public static final int SEMANTICALLY_INCORRECT_MESSAGE = 95; // 0x5f - field public static final int SERVICE_OPTION_NOT_AVAILABLE = 63; // 0x3f - field public static final int SERVICE_OR_OPTION_NOT_IMPLEMENTED = 79; // 0x4f - field public static final int STATUS_ENQUIRY = 30; // 0x1e - field public static final int SWITCHING_CONGESTION = 42; // 0x2a - field public static final int TEMPORARY_FAILURE = 41; // 0x29 - field public static final int UNOBTAINABLE_NUMBER = 1; // 0x1 - field public static final int USER_NOT_MEMBER_OF_CUG = 87; // 0x57 - } - - public class ServiceState implements android.os.Parcelable { - method @Nullable public android.telephony.NetworkRegistrationInfo getNetworkRegistrationInfo(int, int); - method @NonNull public java.util.List<android.telephony.NetworkRegistrationInfo> getNetworkRegistrationInfoListForDomain(int); - method @NonNull public java.util.List<android.telephony.NetworkRegistrationInfo> getNetworkRegistrationInfoListForTransportType(int); - field public static final int ROAMING_TYPE_DOMESTIC = 2; // 0x2 - field public static final int ROAMING_TYPE_INTERNATIONAL = 3; // 0x3 - field public static final int ROAMING_TYPE_NOT_ROAMING = 0; // 0x0 - field public static final int ROAMING_TYPE_UNKNOWN = 1; // 0x1 - } - - public final class SmsCbCmasInfo implements android.os.Parcelable { - ctor public SmsCbCmasInfo(int, int, int, int, int, int); - method public int describeContents(); - method public int getCategory(); - method public int getCertainty(); - method public int getMessageClass(); - method public int getResponseType(); - method public int getSeverity(); - method public int getUrgency(); - method public void writeToParcel(android.os.Parcel, int); - field public static final int CMAS_CATEGORY_CBRNE = 10; // 0xa - field public static final int CMAS_CATEGORY_ENV = 7; // 0x7 - field public static final int CMAS_CATEGORY_FIRE = 5; // 0x5 - field public static final int CMAS_CATEGORY_GEO = 0; // 0x0 - field public static final int CMAS_CATEGORY_HEALTH = 6; // 0x6 - field public static final int CMAS_CATEGORY_INFRA = 9; // 0x9 - field public static final int CMAS_CATEGORY_MET = 1; // 0x1 - field public static final int CMAS_CATEGORY_OTHER = 11; // 0xb - field public static final int CMAS_CATEGORY_RESCUE = 4; // 0x4 - field public static final int CMAS_CATEGORY_SAFETY = 2; // 0x2 - field public static final int CMAS_CATEGORY_SECURITY = 3; // 0x3 - field public static final int CMAS_CATEGORY_TRANSPORT = 8; // 0x8 - field public static final int CMAS_CATEGORY_UNKNOWN = -1; // 0xffffffff - field public static final int CMAS_CERTAINTY_LIKELY = 1; // 0x1 - field public static final int CMAS_CERTAINTY_OBSERVED = 0; // 0x0 - field public static final int CMAS_CERTAINTY_UNKNOWN = -1; // 0xffffffff - field public static final int CMAS_CLASS_CHILD_ABDUCTION_EMERGENCY = 3; // 0x3 - field public static final int CMAS_CLASS_CMAS_EXERCISE = 5; // 0x5 - field public static final int CMAS_CLASS_EXTREME_THREAT = 1; // 0x1 - field public static final int CMAS_CLASS_OPERATOR_DEFINED_USE = 6; // 0x6 - field public static final int CMAS_CLASS_PRESIDENTIAL_LEVEL_ALERT = 0; // 0x0 - field public static final int CMAS_CLASS_REQUIRED_MONTHLY_TEST = 4; // 0x4 - field public static final int CMAS_CLASS_SEVERE_THREAT = 2; // 0x2 - field public static final int CMAS_CLASS_UNKNOWN = -1; // 0xffffffff - field public static final int CMAS_RESPONSE_TYPE_ASSESS = 6; // 0x6 - field public static final int CMAS_RESPONSE_TYPE_AVOID = 5; // 0x5 - field public static final int CMAS_RESPONSE_TYPE_EVACUATE = 1; // 0x1 - field public static final int CMAS_RESPONSE_TYPE_EXECUTE = 3; // 0x3 - field public static final int CMAS_RESPONSE_TYPE_MONITOR = 4; // 0x4 - field public static final int CMAS_RESPONSE_TYPE_NONE = 7; // 0x7 - field public static final int CMAS_RESPONSE_TYPE_PREPARE = 2; // 0x2 - field public static final int CMAS_RESPONSE_TYPE_SHELTER = 0; // 0x0 - field public static final int CMAS_RESPONSE_TYPE_UNKNOWN = -1; // 0xffffffff - field public static final int CMAS_SEVERITY_EXTREME = 0; // 0x0 - field public static final int CMAS_SEVERITY_SEVERE = 1; // 0x1 - field public static final int CMAS_SEVERITY_UNKNOWN = -1; // 0xffffffff - field public static final int CMAS_URGENCY_EXPECTED = 1; // 0x1 - field public static final int CMAS_URGENCY_IMMEDIATE = 0; // 0x0 - field public static final int CMAS_URGENCY_UNKNOWN = -1; // 0xffffffff - field @NonNull public static final android.os.Parcelable.Creator<android.telephony.SmsCbCmasInfo> CREATOR; - } - - public final class SmsCbEtwsInfo implements android.os.Parcelable { - ctor public SmsCbEtwsInfo(int, boolean, boolean, boolean, @Nullable byte[]); - method public int describeContents(); - method @Nullable public byte[] getPrimaryNotificationSignature(); - method public long getPrimaryNotificationTimestamp(); - method public int getWarningType(); - method public boolean isEmergencyUserAlert(); - method public boolean isPopupAlert(); - method public boolean isPrimary(); - method public void writeToParcel(android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.telephony.SmsCbEtwsInfo> CREATOR; - field public static final int ETWS_WARNING_TYPE_EARTHQUAKE = 0; // 0x0 - field public static final int ETWS_WARNING_TYPE_EARTHQUAKE_AND_TSUNAMI = 2; // 0x2 - field public static final int ETWS_WARNING_TYPE_OTHER_EMERGENCY = 4; // 0x4 - field public static final int ETWS_WARNING_TYPE_TEST_MESSAGE = 3; // 0x3 - field public static final int ETWS_WARNING_TYPE_TSUNAMI = 1; // 0x1 - field public static final int ETWS_WARNING_TYPE_UNKNOWN = -1; // 0xffffffff - } - - public final class SmsCbLocation implements android.os.Parcelable { - ctor public SmsCbLocation(@NonNull String, int, int); - method public int describeContents(); - method public int getCid(); - method public int getLac(); - method @NonNull public String getPlmn(); - method public boolean isInLocationArea(@NonNull android.telephony.SmsCbLocation); - method public boolean isInLocationArea(@Nullable String, int, int); - method public void writeToParcel(android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.telephony.SmsCbLocation> CREATOR; - } - - public final class SmsCbMessage implements android.os.Parcelable { - ctor public SmsCbMessage(int, int, int, @NonNull android.telephony.SmsCbLocation, int, @Nullable String, int, @Nullable String, int, @Nullable android.telephony.SmsCbEtwsInfo, @Nullable android.telephony.SmsCbCmasInfo, int, @Nullable java.util.List<android.telephony.CbGeoUtils.Geometry>, long, int, int); - method @NonNull public static android.telephony.SmsCbMessage createFromCursor(@NonNull android.database.Cursor); - method public int describeContents(); - method @Nullable public android.telephony.SmsCbCmasInfo getCmasWarningInfo(); - method @NonNull public android.content.ContentValues getContentValues(); - method public int getDataCodingScheme(); - method @Nullable public android.telephony.SmsCbEtwsInfo getEtwsWarningInfo(); - method public int getGeographicalScope(); - method @NonNull public java.util.List<android.telephony.CbGeoUtils.Geometry> getGeometries(); - method @Nullable public String getLanguageCode(); - method @NonNull public android.telephony.SmsCbLocation getLocation(); - method public int getMaximumWaitingDuration(); - method @Nullable public String getMessageBody(); - method public int getMessageFormat(); - method public int getMessagePriority(); - method public long getReceivedTime(); - method public int getSerialNumber(); - method public int getServiceCategory(); - method public int getSlotIndex(); - method public int getSubscriptionId(); - method public boolean isCmasMessage(); - method public boolean isEmergencyMessage(); - method public boolean isEtwsMessage(); - method public boolean needGeoFencingCheck(); - method public void writeToParcel(android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.telephony.SmsCbMessage> CREATOR; - field public static final int GEOGRAPHICAL_SCOPE_CELL_WIDE = 3; // 0x3 - field public static final int GEOGRAPHICAL_SCOPE_CELL_WIDE_IMMEDIATE = 0; // 0x0 - field public static final int GEOGRAPHICAL_SCOPE_LOCATION_AREA_WIDE = 2; // 0x2 - field public static final int GEOGRAPHICAL_SCOPE_PLMN_WIDE = 1; // 0x1 - field public static final int MAXIMUM_WAIT_TIME_NOT_SET = 255; // 0xff - field public static final int MESSAGE_FORMAT_3GPP = 1; // 0x1 - field public static final int MESSAGE_FORMAT_3GPP2 = 2; // 0x2 - field public static final int MESSAGE_PRIORITY_EMERGENCY = 3; // 0x3 - field public static final int MESSAGE_PRIORITY_INTERACTIVE = 1; // 0x1 - field public static final int MESSAGE_PRIORITY_NORMAL = 0; // 0x0 - field public static final int MESSAGE_PRIORITY_URGENT = 2; // 0x2 - } - - public final class SmsManager { - method public boolean disableCellBroadcastRange(int, int, int); - method public boolean enableCellBroadcastRange(int, int, int); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getPremiumSmsConsent(@NonNull String); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void sendMultipartTextMessageWithoutPersisting(String, String, java.util.List<java.lang.String>, java.util.List<android.app.PendingIntent>, java.util.List<android.app.PendingIntent>); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setPremiumSmsConsent(@NonNull String, int); - field public static final int PREMIUM_SMS_CONSENT_ALWAYS_ALLOW = 3; // 0x3 - field public static final int PREMIUM_SMS_CONSENT_ASK_USER = 1; // 0x1 - field public static final int PREMIUM_SMS_CONSENT_NEVER_ALLOW = 2; // 0x2 - field public static final int PREMIUM_SMS_CONSENT_UNKNOWN = 0; // 0x0 - } - - public class SmsMessage { - method @Nullable public static android.telephony.SmsMessage createFromNativeSmsSubmitPdu(@NonNull byte[], boolean); - method @Nullable public static android.telephony.SmsMessage.SubmitPdu getSmsPdu(int, int, @Nullable String, @NonNull String, @NonNull String, long); - method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public static byte[] getSubmitPduEncodedMessage(boolean, @NonNull String, @NonNull String, int, @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0, to=255) int, @IntRange(from=1, to=255) int, @IntRange(from=1, to=255) int); - } - - public class SubscriptionInfo implements android.os.Parcelable { - method public boolean areUiccApplicationsEnabled(); - method @Nullable public java.util.List<android.telephony.UiccAccessRule> getAccessRules(); - method public int getProfileClass(); - method public boolean isGroupDisabled(); - } - - public class SubscriptionManager { - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean canDisablePhysicalSubscription(); - method public boolean canManageSubscription(@NonNull android.telephony.SubscriptionInfo, @NonNull String); - method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int[] getActiveSubscriptionIdList(); - method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.SubscriptionInfo getActiveSubscriptionInfoForIcc(@NonNull String); - method public java.util.List<android.telephony.SubscriptionInfo> getAvailableSubscriptionInfoList(); - method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int[] getCompleteActiveSubscriptionIdList(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getEnabledSubscriptionId(int); - method @NonNull public static android.content.res.Resources getResourcesForSubId(@NonNull android.content.Context, int); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isSubscriptionEnabled(int); - method public void requestEmbeddedSubscriptionInfoListRefresh(); - method public void requestEmbeddedSubscriptionInfoListRefresh(int); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDefaultDataSubId(int); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDefaultSmsSubId(int); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDefaultVoiceSubscriptionId(int); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setPreferredDataSubscriptionId(int, boolean, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setSubscriptionEnabled(int, boolean); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUiccApplicationsEnabled(int, boolean); - field @RequiresPermission(android.Manifest.permission.MANAGE_SUBSCRIPTION_PLANS) public static final String ACTION_SUBSCRIPTION_PLANS_CHANGED = "android.telephony.action.SUBSCRIPTION_PLANS_CHANGED"; - field @NonNull public static final android.net.Uri ADVANCED_CALLING_ENABLED_CONTENT_URI; - field @Deprecated public static final int PROFILE_CLASS_DEFAULT; - field public static final int PROFILE_CLASS_OPERATIONAL; - field public static final int PROFILE_CLASS_PROVISIONING; - field public static final int PROFILE_CLASS_TESTING; - field public static final int PROFILE_CLASS_UNSET; - field @NonNull public static final android.net.Uri VT_ENABLED_CONTENT_URI; - field @NonNull public static final android.net.Uri WFC_ENABLED_CONTENT_URI; - field @NonNull public static final android.net.Uri WFC_MODE_CONTENT_URI; - field @NonNull public static final android.net.Uri WFC_ROAMING_ENABLED_CONTENT_URI; - field @NonNull public static final android.net.Uri WFC_ROAMING_MODE_CONTENT_URI; - } - - public final class TelephonyHistogram implements android.os.Parcelable { - ctor public TelephonyHistogram(int, int, int); - ctor public TelephonyHistogram(android.telephony.TelephonyHistogram); - ctor public TelephonyHistogram(android.os.Parcel); - method public void addTimeTaken(int); - method public int describeContents(); - method public int getAverageTime(); - method public int getBucketCount(); - method public int[] getBucketCounters(); - method public int[] getBucketEndPoints(); - method public int getCategory(); - method public int getId(); - method public int getMaxTime(); - method public int getMinTime(); - method public int getSampleCount(); - method public void writeToParcel(android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.telephony.TelephonyHistogram> CREATOR; - field public static final int TELEPHONY_CATEGORY_RIL = 1; // 0x1 - } - - public class TelephonyManager { - method @Deprecated @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void call(String, String); - method public int checkCarrierPrivilegesForPackage(String); - method public int checkCarrierPrivilegesForPackageAnyPhone(String); - method public void dial(String); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean disableDataConnectivity(); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean enableDataConnectivity(); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean enableModemForSlot(int, boolean); - method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void enableVideoCalling(boolean); - method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getAidForAppType(int); - method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<android.service.carrier.CarrierIdentifier> getAllowedCarriers(int); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getAllowedNetworkTypes(); - method @Nullable @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public android.content.ComponentName getAndUpdateDefaultRespondViaMessageApplication(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getCallForwarding(int, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CallForwardingInfoCallback); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getCallWaitingStatus(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); - method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int); - method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent); - method public java.util.List<java.lang.String> getCarrierPackageNamesForIntentAndPhone(android.content.Intent, int); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCarrierPrivilegeStatus(int); - method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<java.lang.String> getCarrierPrivilegedPackagesForAllActiveSubscriptions(); - method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.CarrierRestrictionRules getCarrierRestrictionRules(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCdmaEnhancedRoamingIndicatorIconIndex(); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMdn(); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMdn(int); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMin(); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMin(int); - method public String getCdmaPrlVersion(); - method public int getCurrentPhoneType(); - method public int getCurrentPhoneType(int); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getDataActivationState(); - method @Deprecated public boolean getDataEnabled(); - method @Deprecated public boolean getDataEnabled(int); - method @Nullable @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public android.content.ComponentName getDefaultRespondViaMessageApplication(); - method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getDeviceSoftwareVersion(int); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean getEmergencyCallbackMode(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getEmergencyNumberDbVersion(); - method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimDomain(); - method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimIst(); - method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.Map<java.lang.Integer,java.lang.Integer> getLogicalToPhysicalSlotMapping(); - method public int getMaxNumberOfSimultaneouslyActiveSims(); - method public static long getMaxNumberVerificationTimeoutMillis(); - method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String[] getMergedImsisFromGroup(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getPreferredNetworkTypeBitmask(); - method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public int getRadioPowerState(); - method public int getSimApplicationState(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getSimApplicationState(int); - method public int getSimCardState(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getSimCardState(int); - method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.Locale getSimLocale(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getSupportedRadioAccessFamily(); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public java.util.List<android.telephony.TelephonyHistogram> getTelephonyHistograms(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.UiccSlotInfo[] getUiccSlotsInfo(); - method @Nullable public android.os.Bundle getVisualVoicemailSettings(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoiceActivationState(); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handlePinMmi(String); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handlePinMmiForSubscriber(int, String); - method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean iccCloseLogicalChannelBySlot(int, int); - method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannelBySlot(int, @Nullable String, int); - method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String iccTransmitApduBasicChannelBySlot(int, int, int, int, int, int, @Nullable String); - method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String iccTransmitApduLogicalChannelBySlot(int, int, int, int, int, int, int, @Nullable String); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAnyRadioPoweredOn(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApnMetered(int); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApplicationOnUicc(int); - method public boolean isDataConnectivityPossible(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isDataEnabledForApn(int); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isEmergencyAssistanceEnabled(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public boolean isIccLockEnabled(); - method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isIdle(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isLteCdmaEvdoGsmWcdmaEnabled(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isMobileDataPolicyEnabled(int); - method public boolean isNrDualConnectivityEnabled(); - method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isOffhook(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isOpportunisticNetworkEnabled(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isPotentialEmergencyNumber(@NonNull String); - method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRadioOn(); - method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRinging(); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean isTetheringApnRequired(); - method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isVideoCallingEnabled(); - method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isVisualVoicemailEnabled(android.telecom.PhoneAccountHandle); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean matchesCurrentSimOperator(@NonNull String, int, @Nullable String); - method public boolean needsOtaServiceProvisioning(); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyOtaEmergencyNumberDbInstalled(); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean rebootRadio(); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void reportDefaultNetworkStatus(boolean); - method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.MODIFY_PHONE_STATE}) public void requestCellInfoUpdate(@NonNull android.os.WorkSource, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CellInfoCallback); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestModemActivityInfo(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.telephony.ModemActivityInfo,android.telephony.TelephonyManager.ModemActivityInfoException>); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestNumberVerification(@NonNull android.telephony.PhoneNumberRange, long, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.NumberVerificationCallback); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void resetAllCarrierActions(); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void resetCarrierKeysForImsiEncryption(); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void resetIms(int); - method @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public void resetOtaEmergencyNumberDbFilePath(); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean resetRadioConfig(); - method @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL) public void resetSettings(); - method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setAllowedCarriers(int, java.util.List<android.service.carrier.CarrierIdentifier>); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setAllowedNetworkTypes(long); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCallForwarding(@NonNull android.telephony.CallForwardingInfo, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCallWaitingEnabled(boolean, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>); - method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCarrierDataEnabled(boolean); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setCarrierRestrictionRules(@NonNull android.telephony.CarrierRestrictionRules); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataActivationState(int); - method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(int, boolean); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataRoamingEnabled(boolean); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setMobileDataPolicyEnabledStatus(int, boolean); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setMultiSimCarrierRestriction(boolean); - method public int setNrDualConnectivityState(int); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setOpportunisticNetworkState(boolean); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setPreferredNetworkTypeBitmask(long); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setRadio(boolean); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setRadioEnabled(boolean); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setRadioPower(boolean); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setSimPowerState(int); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setSimPowerStateForSlot(int, int); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setSystemSelectionChannels(@NonNull java.util.List<android.telephony.RadioAccessSpecifier>, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setSystemSelectionChannels(@NonNull java.util.List<android.telephony.RadioAccessSpecifier>); - method @Deprecated public void setVisualVoicemailEnabled(android.telecom.PhoneAccountHandle, boolean); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoiceActivationState(int); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void shutdownAllRadios(); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean supplyPin(String); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int[] supplyPinReportResult(String); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean supplyPuk(String, String); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int[] supplyPukReportResult(String, String); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean switchSlots(int[]); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void toggleRadioOnOff(); - method @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public void updateOtaEmergencyNumberDbFilePath(@NonNull android.os.ParcelFileDescriptor); - method public void updateServiceLocation(); - field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final String ACTION_ANOMALY_REPORTED = "android.telephony.action.ANOMALY_REPORTED"; - field public static final String ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED = "android.intent.action.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED"; - field public static final String ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED = "android.intent.action.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED"; - field public static final String ACTION_EMERGENCY_ASSISTANCE = "android.telephony.action.EMERGENCY_ASSISTANCE"; - field public static final String ACTION_EMERGENCY_CALLBACK_MODE_CHANGED = "android.intent.action.EMERGENCY_CALLBACK_MODE_CHANGED"; - field public static final String ACTION_EMERGENCY_CALL_STATE_CHANGED = "android.intent.action.EMERGENCY_CALL_STATE_CHANGED"; - field public static final String ACTION_REQUEST_OMADM_CONFIGURATION_UPDATE = "com.android.omadm.service.CONFIGURATION_UPDATE"; - field public static final String ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS = "android.telephony.action.SHOW_NOTICE_ECM_BLOCK_OTHERS"; - field public static final String ACTION_SIM_APPLICATION_STATE_CHANGED = "android.telephony.action.SIM_APPLICATION_STATE_CHANGED"; - field public static final String ACTION_SIM_CARD_STATE_CHANGED = "android.telephony.action.SIM_CARD_STATE_CHANGED"; - field public static final String ACTION_SIM_SLOT_STATUS_CHANGED = "android.telephony.action.SIM_SLOT_STATUS_CHANGED"; - field public static final int CALL_WAITING_STATUS_DISABLED = 2; // 0x2 - field public static final int CALL_WAITING_STATUS_ENABLED = 1; // 0x1 - field public static final int CALL_WAITING_STATUS_NOT_SUPPORTED = 4; // 0x4 - field public static final int CALL_WAITING_STATUS_UNKNOWN_ERROR = 3; // 0x3 - field public static final int CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES = -2; // 0xfffffffe - field public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; // 0x1 - field public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0; // 0x0 - field public static final int CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED = -1; // 0xffffffff - field public static final int ENABLE_NR_DUAL_CONNECTIVITY_INVALID_STATE = 4; // 0x4 - field public static final int ENABLE_NR_DUAL_CONNECTIVITY_NOT_SUPPORTED = 1; // 0x1 - field public static final int ENABLE_NR_DUAL_CONNECTIVITY_RADIO_ERROR = 3; // 0x3 - field public static final int ENABLE_NR_DUAL_CONNECTIVITY_RADIO_NOT_AVAILABLE = 2; // 0x2 - field public static final int ENABLE_NR_DUAL_CONNECTIVITY_SUCCESS = 0; // 0x0 - field public static final String EXTRA_ANOMALY_DESCRIPTION = "android.telephony.extra.ANOMALY_DESCRIPTION"; - field public static final String EXTRA_ANOMALY_ID = "android.telephony.extra.ANOMALY_ID"; - field public static final String EXTRA_PHONE_IN_ECM_STATE = "android.telephony.extra.PHONE_IN_ECM_STATE"; - field public static final String EXTRA_PHONE_IN_EMERGENCY_CALL = "android.telephony.extra.PHONE_IN_EMERGENCY_CALL"; - field public static final String EXTRA_SIM_STATE = "android.telephony.extra.SIM_STATE"; - field public static final String EXTRA_VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL = "android.telephony.extra.VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL"; - field public static final String EXTRA_VOICEMAIL_SCRAMBLED_PIN_STRING = "android.telephony.extra.VOICEMAIL_SCRAMBLED_PIN_STRING"; - field public static final int INVALID_EMERGENCY_NUMBER_DB_VERSION = -1; // 0xffffffff - field public static final int KEY_TYPE_EPDG = 1; // 0x1 - field public static final int KEY_TYPE_WLAN = 2; // 0x2 - field public static final int MOBILE_DATA_POLICY_DATA_ON_NON_DEFAULT_DURING_VOICE_CALL = 1; // 0x1 - field public static final int MOBILE_DATA_POLICY_MMS_ALWAYS_ALLOWED = 2; // 0x2 - field public static final long NETWORK_TYPE_BITMASK_1xRTT = 64L; // 0x40L - field public static final long NETWORK_TYPE_BITMASK_CDMA = 8L; // 0x8L - field public static final long NETWORK_TYPE_BITMASK_EDGE = 2L; // 0x2L - field public static final long NETWORK_TYPE_BITMASK_EHRPD = 8192L; // 0x2000L - field public static final long NETWORK_TYPE_BITMASK_EVDO_0 = 16L; // 0x10L - field public static final long NETWORK_TYPE_BITMASK_EVDO_A = 32L; // 0x20L - field public static final long NETWORK_TYPE_BITMASK_EVDO_B = 2048L; // 0x800L - field public static final long NETWORK_TYPE_BITMASK_GPRS = 1L; // 0x1L - field public static final long NETWORK_TYPE_BITMASK_GSM = 32768L; // 0x8000L - field public static final long NETWORK_TYPE_BITMASK_HSDPA = 128L; // 0x80L - field public static final long NETWORK_TYPE_BITMASK_HSPA = 512L; // 0x200L - field public static final long NETWORK_TYPE_BITMASK_HSPAP = 16384L; // 0x4000L - field public static final long NETWORK_TYPE_BITMASK_HSUPA = 256L; // 0x100L - field public static final long NETWORK_TYPE_BITMASK_IWLAN = 131072L; // 0x20000L - field public static final long NETWORK_TYPE_BITMASK_LTE = 4096L; // 0x1000L - field public static final long NETWORK_TYPE_BITMASK_LTE_CA = 262144L; // 0x40000L - field public static final long NETWORK_TYPE_BITMASK_NR = 524288L; // 0x80000L - field public static final long NETWORK_TYPE_BITMASK_TD_SCDMA = 65536L; // 0x10000L - field public static final long NETWORK_TYPE_BITMASK_UMTS = 4L; // 0x4L - field public static final long NETWORK_TYPE_BITMASK_UNKNOWN = 0L; // 0x0L - field public static final int NR_DUAL_CONNECTIVITY_DISABLE = 2; // 0x2 - field public static final int NR_DUAL_CONNECTIVITY_DISABLE_IMMEDIATE = 3; // 0x3 - field public static final int NR_DUAL_CONNECTIVITY_ENABLE = 1; // 0x1 - field public static final int RADIO_POWER_OFF = 0; // 0x0 - field public static final int RADIO_POWER_ON = 1; // 0x1 - field public static final int RADIO_POWER_UNAVAILABLE = 2; // 0x2 - field public static final int SET_CARRIER_RESTRICTION_ERROR = 2; // 0x2 - field public static final int SET_CARRIER_RESTRICTION_NOT_SUPPORTED = 1; // 0x1 - field public static final int SET_CARRIER_RESTRICTION_SUCCESS = 0; // 0x0 - field public static final int SIM_ACTIVATION_STATE_ACTIVATED = 2; // 0x2 - field public static final int SIM_ACTIVATION_STATE_ACTIVATING = 1; // 0x1 - field public static final int SIM_ACTIVATION_STATE_DEACTIVATED = 3; // 0x3 - field public static final int SIM_ACTIVATION_STATE_RESTRICTED = 4; // 0x4 - field public static final int SIM_ACTIVATION_STATE_UNKNOWN = 0; // 0x0 - field public static final int SIM_STATE_LOADED = 10; // 0xa - field public static final int SIM_STATE_PRESENT = 11; // 0xb - field public static final int SRVCC_STATE_HANDOVER_CANCELED = 3; // 0x3 - field public static final int SRVCC_STATE_HANDOVER_COMPLETED = 1; // 0x1 - field public static final int SRVCC_STATE_HANDOVER_FAILED = 2; // 0x2 - field public static final int SRVCC_STATE_HANDOVER_NONE = -1; // 0xffffffff - field public static final int SRVCC_STATE_HANDOVER_STARTED = 0; // 0x0 - } - - public static interface TelephonyManager.CallForwardingInfoCallback { - method public void onCallForwardingInfoAvailable(@NonNull android.telephony.CallForwardingInfo); - method public void onError(int); - field public static final int RESULT_ERROR_FDN_CHECK_FAILURE = 2; // 0x2 - field public static final int RESULT_ERROR_NOT_SUPPORTED = 3; // 0x3 - field public static final int RESULT_ERROR_UNKNOWN = 1; // 0x1 - field public static final int RESULT_SUCCESS = 0; // 0x0 - } - - public static class TelephonyManager.ModemActivityInfoException extends java.lang.Exception { - method public int getErrorCode(); - field public static final int ERROR_INVALID_INFO_RECEIVED = 2; // 0x2 - field public static final int ERROR_MODEM_RESPONSE_ERROR = 3; // 0x3 - field public static final int ERROR_PHONE_NOT_AVAILABLE = 1; // 0x1 - field public static final int ERROR_UNKNOWN = 0; // 0x0 - } - - public final class UiccAccessRule implements android.os.Parcelable { - ctor public UiccAccessRule(byte[], @Nullable String, long); - method public int describeContents(); - method public int getCarrierPrivilegeStatus(android.content.pm.PackageInfo); - method public int getCarrierPrivilegeStatus(android.content.pm.Signature, String); - method public String getCertificateHexString(); - method @Nullable public String getPackageName(); - method public void writeToParcel(android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.telephony.UiccAccessRule> CREATOR; - } - - public class UiccSlotInfo implements android.os.Parcelable { - ctor @Deprecated public UiccSlotInfo(boolean, boolean, String, int, int, boolean); - method public int describeContents(); - method public String getCardId(); - method public int getCardStateInfo(); - method public boolean getIsActive(); - method public boolean getIsEuicc(); - method public boolean getIsExtendedApduSupported(); - method public int getLogicalSlotIdx(); - method public boolean isRemovable(); - method public void writeToParcel(android.os.Parcel, int); - field public static final int CARD_STATE_INFO_ABSENT = 1; // 0x1 - field public static final int CARD_STATE_INFO_ERROR = 3; // 0x3 - field public static final int CARD_STATE_INFO_PRESENT = 2; // 0x2 - field public static final int CARD_STATE_INFO_RESTRICTED = 4; // 0x4 - field @NonNull public static final android.os.Parcelable.Creator<android.telephony.UiccSlotInfo> CREATOR; - } - - public abstract class VisualVoicemailService extends android.app.Service { - method public static final void sendVisualVoicemailSms(android.content.Context, android.telecom.PhoneAccountHandle, String, short, String, android.app.PendingIntent); - method public static final void setSmsFilterSettings(android.content.Context, android.telecom.PhoneAccountHandle, android.telephony.VisualVoicemailSmsFilterSettings); - } - -} - -package android.telephony.cdma { - - public final class CdmaSmsCbProgramData implements android.os.Parcelable { - method public int describeContents(); - method public int getCategory(); - method public int getOperation(); - method public void writeToParcel(android.os.Parcel, int); - field public static final int CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY = 4099; // 0x1003 - field public static final int CATEGORY_CMAS_EXTREME_THREAT = 4097; // 0x1001 - field public static final int CATEGORY_CMAS_LAST_RESERVED_VALUE = 4351; // 0x10ff - field public static final int CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT = 4096; // 0x1000 - field public static final int CATEGORY_CMAS_SEVERE_THREAT = 4098; // 0x1002 - field public static final int CATEGORY_CMAS_TEST_MESSAGE = 4100; // 0x1004 - field @NonNull public static final android.os.Parcelable.Creator<android.telephony.cdma.CdmaSmsCbProgramData> CREATOR; - field public static final int OPERATION_ADD_CATEGORY = 1; // 0x1 - field public static final int OPERATION_CLEAR_CATEGORIES = 2; // 0x2 - field public static final int OPERATION_DELETE_CATEGORY = 0; // 0x0 - } - -} - -package android.telephony.data { - - public final class DataCallResponse implements android.os.Parcelable { - method public int describeContents(); - method @NonNull public java.util.List<android.net.LinkAddress> getAddresses(); - method public int getCause(); - method @NonNull public java.util.List<java.net.InetAddress> getDnsAddresses(); - method @NonNull public java.util.List<java.net.InetAddress> getGatewayAddresses(); - method public int getHandoverFailureMode(); - method public int getId(); - method @NonNull public String getInterfaceName(); - method public int getLinkStatus(); - method @Deprecated public int getMtu(); - method public int getMtuV4(); - method public int getMtuV6(); - method @NonNull public java.util.List<java.net.InetAddress> getPcscfAddresses(); - method public int getProtocolType(); - method public int getSuggestedRetryTime(); - method public void writeToParcel(android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.DataCallResponse> CREATOR; - field public static final int HANDOVER_FAILURE_MODE_DO_FALLBACK = 1; // 0x1 - field public static final int HANDOVER_FAILURE_MODE_LEGACY = 0; // 0x0 - field public static final int HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_HANDOVER = 2; // 0x2 - field public static final int HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_SETUP_NORMAL = 3; // 0x3 - field public static final int HANDOVER_FAILURE_MODE_UNKNOWN = -1; // 0xffffffff - field public static final int LINK_STATUS_ACTIVE = 2; // 0x2 - field public static final int LINK_STATUS_DORMANT = 1; // 0x1 - field public static final int LINK_STATUS_INACTIVE = 0; // 0x0 - field public static final int LINK_STATUS_UNKNOWN = -1; // 0xffffffff - } - - public static final class DataCallResponse.Builder { - ctor public DataCallResponse.Builder(); - method @NonNull public android.telephony.data.DataCallResponse build(); - method @NonNull public android.telephony.data.DataCallResponse.Builder setAddresses(@NonNull java.util.List<android.net.LinkAddress>); - method @NonNull public android.telephony.data.DataCallResponse.Builder setCause(int); - method @NonNull public android.telephony.data.DataCallResponse.Builder setDnsAddresses(@NonNull java.util.List<java.net.InetAddress>); - method @NonNull public android.telephony.data.DataCallResponse.Builder setGatewayAddresses(@NonNull java.util.List<java.net.InetAddress>); - method @NonNull public android.telephony.data.DataCallResponse.Builder setHandoverFailureMode(int); - method @NonNull public android.telephony.data.DataCallResponse.Builder setId(int); - method @NonNull public android.telephony.data.DataCallResponse.Builder setInterfaceName(@NonNull String); - method @NonNull public android.telephony.data.DataCallResponse.Builder setLinkStatus(int); - method @Deprecated @NonNull public android.telephony.data.DataCallResponse.Builder setMtu(int); - method @NonNull public android.telephony.data.DataCallResponse.Builder setMtuV4(int); - method @NonNull public android.telephony.data.DataCallResponse.Builder setMtuV6(int); - method @NonNull public android.telephony.data.DataCallResponse.Builder setPcscfAddresses(@NonNull java.util.List<java.net.InetAddress>); - method @NonNull public android.telephony.data.DataCallResponse.Builder setProtocolType(int); - method @NonNull public android.telephony.data.DataCallResponse.Builder setSuggestedRetryTime(int); - } - - public final class DataProfile implements android.os.Parcelable { - method public int describeContents(); - method @NonNull public String getApn(); - method public int getAuthType(); - method public int getBearerBitmask(); - method @Deprecated public int getMtu(); - method public int getMtuV4(); - method public int getMtuV6(); - method @Nullable public String getPassword(); - method public int getProfileId(); - method public int getProtocolType(); - method public int getRoamingProtocolType(); - method public int getSupportedApnTypesBitmask(); - method public int getType(); - method @Nullable public String getUserName(); - method public boolean isEnabled(); - method public boolean isPersistent(); - method public boolean isPreferred(); - method public void writeToParcel(android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.DataProfile> CREATOR; - field public static final int TYPE_3GPP = 1; // 0x1 - field public static final int TYPE_3GPP2 = 2; // 0x2 - field public static final int TYPE_COMMON = 0; // 0x0 - } - - public static final class DataProfile.Builder { - ctor public DataProfile.Builder(); - method @NonNull public android.telephony.data.DataProfile build(); - method @NonNull public android.telephony.data.DataProfile.Builder enable(boolean); - method @NonNull public android.telephony.data.DataProfile.Builder setApn(@NonNull String); - method @NonNull public android.telephony.data.DataProfile.Builder setAuthType(int); - method @NonNull public android.telephony.data.DataProfile.Builder setBearerBitmask(int); - method @Deprecated @NonNull public android.telephony.data.DataProfile.Builder setMtu(int); - method @NonNull public android.telephony.data.DataProfile.Builder setMtuV4(int); - method @NonNull public android.telephony.data.DataProfile.Builder setMtuV6(int); - method @NonNull public android.telephony.data.DataProfile.Builder setPassword(@NonNull String); - method @NonNull public android.telephony.data.DataProfile.Builder setPersistent(boolean); - method @NonNull public android.telephony.data.DataProfile.Builder setPreferred(boolean); - method @NonNull public android.telephony.data.DataProfile.Builder setProfileId(int); - method @NonNull public android.telephony.data.DataProfile.Builder setProtocolType(int); - method @NonNull public android.telephony.data.DataProfile.Builder setRoamingProtocolType(int); - method @NonNull public android.telephony.data.DataProfile.Builder setSupportedApnTypesBitmask(int); - method @NonNull public android.telephony.data.DataProfile.Builder setType(int); - method @NonNull public android.telephony.data.DataProfile.Builder setUserName(@NonNull String); - } - - public abstract class DataService extends android.app.Service { - ctor public DataService(); - method public android.os.IBinder onBind(android.content.Intent); - method @Nullable public abstract android.telephony.data.DataService.DataServiceProvider onCreateDataServiceProvider(int); - field public static final int REQUEST_REASON_HANDOVER = 3; // 0x3 - field public static final int REQUEST_REASON_NORMAL = 1; // 0x1 - field public static final int REQUEST_REASON_SHUTDOWN = 2; // 0x2 - field public static final int REQUEST_REASON_UNKNOWN = 0; // 0x0 - field public static final String SERVICE_INTERFACE = "android.telephony.data.DataService"; - } - - public abstract class DataService.DataServiceProvider implements java.lang.AutoCloseable { - ctor public DataService.DataServiceProvider(int); - method public abstract void close(); - method public void deactivateDataCall(int, int, @Nullable android.telephony.data.DataServiceCallback); - method public final int getSlotIndex(); - method public final void notifyDataCallListChanged(java.util.List<android.telephony.data.DataCallResponse>); - method public void requestDataCallList(@NonNull android.telephony.data.DataServiceCallback); - method public void setDataProfile(@NonNull java.util.List<android.telephony.data.DataProfile>, boolean, @NonNull android.telephony.data.DataServiceCallback); - method public void setInitialAttachApn(@NonNull android.telephony.data.DataProfile, boolean, @NonNull android.telephony.data.DataServiceCallback); - method public void setupDataCall(int, @NonNull android.telephony.data.DataProfile, boolean, boolean, int, @Nullable android.net.LinkProperties, @NonNull android.telephony.data.DataServiceCallback); - } - - public class DataServiceCallback { - method public void onDataCallListChanged(@NonNull java.util.List<android.telephony.data.DataCallResponse>); - method public void onDeactivateDataCallComplete(int); - method public void onRequestDataCallListComplete(int, @NonNull java.util.List<android.telephony.data.DataCallResponse>); - method public void onSetDataProfileComplete(int); - method public void onSetInitialAttachApnComplete(int); - method public void onSetupDataCallComplete(int, @Nullable android.telephony.data.DataCallResponse); - field public static final int RESULT_ERROR_BUSY = 3; // 0x3 - field public static final int RESULT_ERROR_ILLEGAL_STATE = 4; // 0x4 - field public static final int RESULT_ERROR_INVALID_ARG = 2; // 0x2 - field public static final int RESULT_ERROR_UNSUPPORTED = 1; // 0x1 - field public static final int RESULT_SUCCESS = 0; // 0x0 - } - - public abstract class QualifiedNetworksService extends android.app.Service { - ctor public QualifiedNetworksService(); - method @NonNull public abstract android.telephony.data.QualifiedNetworksService.NetworkAvailabilityProvider onCreateNetworkAvailabilityProvider(int); - field public static final String QUALIFIED_NETWORKS_SERVICE_INTERFACE = "android.telephony.data.QualifiedNetworksService"; - } - - public abstract class QualifiedNetworksService.NetworkAvailabilityProvider implements java.lang.AutoCloseable { - ctor public QualifiedNetworksService.NetworkAvailabilityProvider(int); - method public abstract void close(); - method public final int getSlotIndex(); - method public final void updateQualifiedNetworkTypes(int, @NonNull java.util.List<java.lang.Integer>); - } - -} - -package android.telephony.euicc { - - public final class DownloadableSubscription implements android.os.Parcelable { - method public java.util.List<android.telephony.UiccAccessRule> getAccessRules(); - method @Nullable public String getCarrierName(); - } - - public static final class DownloadableSubscription.Builder { - ctor public DownloadableSubscription.Builder(); - ctor public DownloadableSubscription.Builder(android.telephony.euicc.DownloadableSubscription); - method public android.telephony.euicc.DownloadableSubscription build(); - method public android.telephony.euicc.DownloadableSubscription.Builder setAccessRules(java.util.List<android.telephony.UiccAccessRule>); - method public android.telephony.euicc.DownloadableSubscription.Builder setCarrierName(String); - method public android.telephony.euicc.DownloadableSubscription.Builder setConfirmationCode(String); - method public android.telephony.euicc.DownloadableSubscription.Builder setEncodedActivationCode(String); - } - - public class EuiccCardManager { - method public void authenticateServer(String, String, byte[], byte[], byte[], byte[], java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>); - method public void cancelSession(String, byte[], @android.telephony.euicc.EuiccCardManager.CancelReason int, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>); - method public void deleteProfile(String, String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>); - method public void disableProfile(String, String, boolean, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>); - method public void listNotifications(String, @android.telephony.euicc.EuiccNotification.Event int, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.telephony.euicc.EuiccNotification[]>); - method public void loadBoundProfilePackage(String, byte[], java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>); - method public void prepareDownload(String, @Nullable byte[], byte[], byte[], byte[], java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>); - method public void removeNotificationFromList(String, int, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>); - method public void requestAllProfiles(String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.service.euicc.EuiccProfileInfo[]>); - method public void requestDefaultSmdpAddress(String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.String>); - method public void requestEuiccChallenge(String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>); - method public void requestEuiccInfo1(String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>); - method public void requestEuiccInfo2(String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>); - method public void requestProfile(String, String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.service.euicc.EuiccProfileInfo>); - method public void requestRulesAuthTable(String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.telephony.euicc.EuiccRulesAuthTable>); - method public void requestSmdsAddress(String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.String>); - method public void resetMemory(String, @android.telephony.euicc.EuiccCardManager.ResetOption int, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>); - method public void retrieveNotification(String, int, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.telephony.euicc.EuiccNotification>); - method public void retrieveNotificationList(String, @android.telephony.euicc.EuiccNotification.Event int, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.telephony.euicc.EuiccNotification[]>); - method public void setDefaultSmdpAddress(String, String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>); - method public void setNickname(String, String, String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>); - method public void switchToProfile(String, String, boolean, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.service.euicc.EuiccProfileInfo>); - field public static final int CANCEL_REASON_END_USER_REJECTED = 0; // 0x0 - field public static final int CANCEL_REASON_POSTPONED = 1; // 0x1 - field public static final int CANCEL_REASON_PPR_NOT_ALLOWED = 3; // 0x3 - field public static final int CANCEL_REASON_TIMEOUT = 2; // 0x2 - field public static final int RESET_OPTION_DELETE_FIELD_LOADED_TEST_PROFILES = 2; // 0x2 - field public static final int RESET_OPTION_DELETE_OPERATIONAL_PROFILES = 1; // 0x1 - field public static final int RESET_OPTION_RESET_DEFAULT_SMDP_ADDRESS = 4; // 0x4 - field public static final int RESULT_CALLER_NOT_ALLOWED = -3; // 0xfffffffd - field public static final int RESULT_EUICC_NOT_FOUND = -2; // 0xfffffffe - field public static final int RESULT_OK = 0; // 0x0 - field public static final int RESULT_UNKNOWN_ERROR = -1; // 0xffffffff - } - - @IntDef(prefix={"CANCEL_REASON_"}, value={android.telephony.euicc.EuiccCardManager.CANCEL_REASON_END_USER_REJECTED, android.telephony.euicc.EuiccCardManager.CANCEL_REASON_POSTPONED, android.telephony.euicc.EuiccCardManager.CANCEL_REASON_TIMEOUT, android.telephony.euicc.EuiccCardManager.CANCEL_REASON_PPR_NOT_ALLOWED}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface EuiccCardManager.CancelReason { - } - - @IntDef(flag=true, prefix={"RESET_OPTION_"}, value={android.telephony.euicc.EuiccCardManager.RESET_OPTION_DELETE_OPERATIONAL_PROFILES, android.telephony.euicc.EuiccCardManager.RESET_OPTION_DELETE_FIELD_LOADED_TEST_PROFILES, android.telephony.euicc.EuiccCardManager.RESET_OPTION_RESET_DEFAULT_SMDP_ADDRESS}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface EuiccCardManager.ResetOption { - } - - public static interface EuiccCardManager.ResultCallback<T> { - method public void onComplete(int, T); - } - - public class EuiccManager { - method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void continueOperation(android.content.Intent, android.os.Bundle); - method @Deprecated @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void eraseSubscriptions(@NonNull android.app.PendingIntent); - method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void eraseSubscriptions(@android.telephony.euicc.EuiccCardManager.ResetOption int, @NonNull android.app.PendingIntent); - method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void getDefaultDownloadableSubscriptionList(android.app.PendingIntent); - method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void getDownloadableSubscriptionMetadata(android.telephony.euicc.DownloadableSubscription, android.app.PendingIntent); - method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public int getOtaStatus(); - method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public java.util.List<java.lang.String> getSupportedCountries(); - method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public java.util.List<java.lang.String> getUnsupportedCountries(); - method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public boolean isSupportedCountry(@NonNull String); - method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void setSupportedCountries(@NonNull java.util.List<java.lang.String>); - method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void setUnsupportedCountries(@NonNull java.util.List<java.lang.String>); - field public static final String ACTION_DELETE_SUBSCRIPTION_PRIVILEGED = "android.telephony.euicc.action.DELETE_SUBSCRIPTION_PRIVILEGED"; - field @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public static final String ACTION_OTA_STATUS_CHANGED = "android.telephony.euicc.action.OTA_STATUS_CHANGED"; - field public static final String ACTION_PROVISION_EMBEDDED_SUBSCRIPTION = "android.telephony.euicc.action.PROVISION_EMBEDDED_SUBSCRIPTION"; - field public static final String ACTION_RENAME_SUBSCRIPTION_PRIVILEGED = "android.telephony.euicc.action.RENAME_SUBSCRIPTION_PRIVILEGED"; - field public static final String ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED = "android.telephony.euicc.action.TOGGLE_SUBSCRIPTION_PRIVILEGED"; - field public static final int EUICC_ACTIVATION_TYPE_ACCOUNT_REQUIRED = 4; // 0x4 - field public static final int EUICC_ACTIVATION_TYPE_BACKUP = 2; // 0x2 - field public static final int EUICC_ACTIVATION_TYPE_DEFAULT = 1; // 0x1 - field public static final int EUICC_ACTIVATION_TYPE_TRANSFER = 3; // 0x3 - field public static final int EUICC_OTA_FAILED = 2; // 0x2 - field public static final int EUICC_OTA_IN_PROGRESS = 1; // 0x1 - field public static final int EUICC_OTA_NOT_NEEDED = 4; // 0x4 - field public static final int EUICC_OTA_STATUS_UNAVAILABLE = 5; // 0x5 - field public static final int EUICC_OTA_SUCCEEDED = 3; // 0x3 - field public static final String EXTRA_ACTIVATION_TYPE = "android.telephony.euicc.extra.ACTIVATION_TYPE"; - field public static final String EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTIONS = "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTIONS"; - field public static final String EXTRA_ENABLE_SUBSCRIPTION = "android.telephony.euicc.extra.ENABLE_SUBSCRIPTION"; - field public static final String EXTRA_FORCE_PROVISION = "android.telephony.euicc.extra.FORCE_PROVISION"; - field public static final String EXTRA_FROM_SUBSCRIPTION_ID = "android.telephony.euicc.extra.FROM_SUBSCRIPTION_ID"; - field public static final String EXTRA_PHYSICAL_SLOT_ID = "android.telephony.euicc.extra.PHYSICAL_SLOT_ID"; - field public static final String EXTRA_SUBSCRIPTION_ID = "android.telephony.euicc.extra.SUBSCRIPTION_ID"; - field public static final String EXTRA_SUBSCRIPTION_NICKNAME = "android.telephony.euicc.extra.SUBSCRIPTION_NICKNAME"; - } - - @IntDef(prefix={"EUICC_OTA_"}, value={android.telephony.euicc.EuiccManager.EUICC_OTA_IN_PROGRESS, android.telephony.euicc.EuiccManager.EUICC_OTA_FAILED, android.telephony.euicc.EuiccManager.EUICC_OTA_SUCCEEDED, android.telephony.euicc.EuiccManager.EUICC_OTA_NOT_NEEDED, android.telephony.euicc.EuiccManager.EUICC_OTA_STATUS_UNAVAILABLE}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface EuiccManager.OtaStatus { - } - - public final class EuiccNotification implements android.os.Parcelable { - ctor public EuiccNotification(int, String, @android.telephony.euicc.EuiccNotification.Event int, @Nullable byte[]); - method public int describeContents(); - method @Nullable public byte[] getData(); - method @android.telephony.euicc.EuiccNotification.Event public int getEvent(); - method public int getSeq(); - method public String getTargetAddr(); - method public void writeToParcel(android.os.Parcel, int); - field @android.telephony.euicc.EuiccNotification.Event public static final int ALL_EVENTS = 15; // 0xf - field @NonNull public static final android.os.Parcelable.Creator<android.telephony.euicc.EuiccNotification> CREATOR; - field public static final int EVENT_DELETE = 8; // 0x8 - field public static final int EVENT_DISABLE = 4; // 0x4 - field public static final int EVENT_ENABLE = 2; // 0x2 - field public static final int EVENT_INSTALL = 1; // 0x1 - } - - @IntDef(flag=true, prefix={"EVENT_"}, value={android.telephony.euicc.EuiccNotification.EVENT_INSTALL, android.telephony.euicc.EuiccNotification.EVENT_ENABLE, android.telephony.euicc.EuiccNotification.EVENT_DISABLE, android.telephony.euicc.EuiccNotification.EVENT_DELETE}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface EuiccNotification.Event { - } - - public final class EuiccRulesAuthTable implements android.os.Parcelable { - method public int describeContents(); - method public int findIndex(@android.service.euicc.EuiccProfileInfo.PolicyRule int, android.service.carrier.CarrierIdentifier); - method public boolean hasPolicyRuleFlag(int, @android.telephony.euicc.EuiccRulesAuthTable.PolicyRuleFlag int); - method public void writeToParcel(android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.telephony.euicc.EuiccRulesAuthTable> CREATOR; - field public static final int POLICY_RULE_FLAG_CONSENT_REQUIRED = 1; // 0x1 - } - - public static final class EuiccRulesAuthTable.Builder { - ctor public EuiccRulesAuthTable.Builder(int); - method public android.telephony.euicc.EuiccRulesAuthTable.Builder add(int, java.util.List<android.service.carrier.CarrierIdentifier>, int); - method public android.telephony.euicc.EuiccRulesAuthTable build(); - } - - @IntDef(flag=true, prefix={"POLICY_RULE_FLAG_"}, value={android.telephony.euicc.EuiccRulesAuthTable.POLICY_RULE_FLAG_CONSENT_REQUIRED}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface EuiccRulesAuthTable.PolicyRuleFlag { - } - -} - -package android.telephony.ims { - - public final class ImsCallForwardInfo implements android.os.Parcelable { - ctor public ImsCallForwardInfo(int, int, int, int, @NonNull String, int); - method public int describeContents(); - method public int getCondition(); - method public String getNumber(); - method public int getServiceClass(); - method public int getStatus(); - method public int getTimeSeconds(); - method public int getToA(); - method public void writeToParcel(android.os.Parcel, int); - field public static final int CDIV_CF_REASON_ALL = 4; // 0x4 - field public static final int CDIV_CF_REASON_ALL_CONDITIONAL = 5; // 0x5 - field public static final int CDIV_CF_REASON_BUSY = 1; // 0x1 - field public static final int CDIV_CF_REASON_NOT_LOGGED_IN = 6; // 0x6 - field public static final int CDIV_CF_REASON_NOT_REACHABLE = 3; // 0x3 - field public static final int CDIV_CF_REASON_NO_REPLY = 2; // 0x2 - field public static final int CDIV_CF_REASON_UNCONDITIONAL = 0; // 0x0 - field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.ImsCallForwardInfo> CREATOR; - field public static final int STATUS_ACTIVE = 1; // 0x1 - field public static final int STATUS_NOT_ACTIVE = 0; // 0x0 - field public static final int TYPE_OF_ADDRESS_INTERNATIONAL = 145; // 0x91 - field public static final int TYPE_OF_ADDRESS_UNKNOWN = 129; // 0x81 - } - - public final class ImsCallProfile implements android.os.Parcelable { - ctor public ImsCallProfile(); - ctor public ImsCallProfile(int, int); - ctor public ImsCallProfile(int, int, android.os.Bundle, android.telephony.ims.ImsStreamMediaProfile); - method public int describeContents(); - method public String getCallExtra(String); - method public String getCallExtra(String, String); - method public boolean getCallExtraBoolean(String); - method public boolean getCallExtraBoolean(String, boolean); - method public int getCallExtraInt(String); - method public int getCallExtraInt(String, int); - method public android.os.Bundle getCallExtras(); - method public int getCallType(); - method public static int getCallTypeFromVideoState(int); - method public int getCallerNumberVerificationStatus(); - method public int getEmergencyCallRouting(); - method public int getEmergencyServiceCategories(); - method @NonNull public java.util.List<java.lang.String> getEmergencyUrns(); - method public android.telephony.ims.ImsStreamMediaProfile getMediaProfile(); - method @NonNull public android.os.Bundle getProprietaryCallExtras(); - method public int getRestrictCause(); - method public int getServiceType(); - method public static int getVideoStateFromCallType(int); - method public static int getVideoStateFromImsCallProfile(android.telephony.ims.ImsCallProfile); - method public boolean hasKnownUserIntentEmergency(); - method public boolean isEmergencyCallTesting(); - method public boolean isVideoCall(); - method public boolean isVideoPaused(); - method public static int presentationToOir(int); - method public void setCallExtra(String, String); - method public void setCallExtraBoolean(String, boolean); - method public void setCallExtraInt(String, int); - method public void setCallRestrictCause(int); - method public void setCallerNumberVerificationStatus(int); - method public void setEmergencyCallRouting(int); - method public void setEmergencyCallTesting(boolean); - method public void setEmergencyServiceCategories(int); - method public void setEmergencyUrns(@NonNull java.util.List<java.lang.String>); - method public void setHasKnownUserIntentEmergency(boolean); - method public void updateCallExtras(android.telephony.ims.ImsCallProfile); - method public void updateCallType(android.telephony.ims.ImsCallProfile); - method public void updateMediaProfile(android.telephony.ims.ImsCallProfile); - method public void writeToParcel(android.os.Parcel, int); - field public static final int CALL_RESTRICT_CAUSE_DISABLED = 2; // 0x2 - field public static final int CALL_RESTRICT_CAUSE_HD = 3; // 0x3 - field public static final int CALL_RESTRICT_CAUSE_NONE = 0; // 0x0 - field public static final int CALL_RESTRICT_CAUSE_RAT = 1; // 0x1 - field public static final int CALL_TYPE_VIDEO_N_VOICE = 3; // 0x3 - field public static final int CALL_TYPE_VOICE = 2; // 0x2 - field public static final int CALL_TYPE_VOICE_N_VIDEO = 1; // 0x1 - field public static final int CALL_TYPE_VS = 8; // 0x8 - field public static final int CALL_TYPE_VS_RX = 10; // 0xa - field public static final int CALL_TYPE_VS_TX = 9; // 0x9 - field public static final int CALL_TYPE_VT = 4; // 0x4 - field public static final int CALL_TYPE_VT_NODIR = 7; // 0x7 - field public static final int CALL_TYPE_VT_RX = 6; // 0x6 - field public static final int CALL_TYPE_VT_TX = 5; // 0x5 - field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.ImsCallProfile> CREATOR; - field public static final int DIALSTRING_NORMAL = 0; // 0x0 - field public static final int DIALSTRING_SS_CONF = 1; // 0x1 - field public static final int DIALSTRING_USSD = 2; // 0x2 - field public static final String EXTRA_ADDITIONAL_CALL_INFO = "AdditionalCallInfo"; - field public static final String EXTRA_ADDITIONAL_SIP_INVITE_FIELDS = "android.telephony.ims.extra.ADDITIONAL_SIP_INVITE_FIELDS"; - field public static final String EXTRA_CALL_DISCONNECT_CAUSE = "android.telephony.ims.extra.CALL_DISCONNECT_CAUSE"; - field public static final String EXTRA_CALL_NETWORK_TYPE = "android.telephony.ims.extra.CALL_NETWORK_TYPE"; - field @Deprecated public static final String EXTRA_CALL_RAT_TYPE = "CallRadioTech"; - field public static final String EXTRA_CHILD_NUMBER = "ChildNum"; - field public static final String EXTRA_CNA = "cna"; - field public static final String EXTRA_CNAP = "cnap"; - field public static final String EXTRA_CODEC = "Codec"; - field public static final String EXTRA_DIALSTRING = "dialstring"; - field public static final String EXTRA_DISPLAY_TEXT = "DisplayText"; - field public static final String EXTRA_EMERGENCY_CALL = "e_call"; - field public static final String EXTRA_FORWARDED_NUMBER = "android.telephony.ims.extra.FORWARDED_NUMBER"; - field public static final String EXTRA_IS_CALL_PULL = "CallPull"; - field public static final String EXTRA_OI = "oi"; - field public static final String EXTRA_OIR = "oir"; - field public static final String EXTRA_REMOTE_URI = "remote_uri"; - field public static final String EXTRA_USSD = "ussd"; - field public static final int OIR_DEFAULT = 0; // 0x0 - field public static final int OIR_PRESENTATION_NOT_RESTRICTED = 2; // 0x2 - field public static final int OIR_PRESENTATION_PAYPHONE = 4; // 0x4 - field public static final int OIR_PRESENTATION_RESTRICTED = 1; // 0x1 - field public static final int OIR_PRESENTATION_UNKNOWN = 3; // 0x3 - field public static final int SERVICE_TYPE_EMERGENCY = 2; // 0x2 - field public static final int SERVICE_TYPE_NONE = 0; // 0x0 - field public static final int SERVICE_TYPE_NORMAL = 1; // 0x1 - field public static final int VERIFICATION_STATUS_FAILED = 2; // 0x2 - field public static final int VERIFICATION_STATUS_NOT_VERIFIED = 0; // 0x0 - field public static final int VERIFICATION_STATUS_PASSED = 1; // 0x1 - } - - public class ImsCallSessionListener { - method public void callQualityChanged(@NonNull android.telephony.CallQuality); - method public void callSessionConferenceExtendFailed(android.telephony.ims.ImsReasonInfo); - method public void callSessionConferenceExtendReceived(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile); - method public void callSessionConferenceExtended(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile); - method public void callSessionConferenceStateUpdated(android.telephony.ims.ImsConferenceState); - method @Deprecated public void callSessionHandover(int, int, android.telephony.ims.ImsReasonInfo); - method @Deprecated public void callSessionHandoverFailed(int, int, android.telephony.ims.ImsReasonInfo); - method public void callSessionHeld(android.telephony.ims.ImsCallProfile); - method public void callSessionHoldFailed(android.telephony.ims.ImsReasonInfo); - method public void callSessionHoldReceived(android.telephony.ims.ImsCallProfile); - method public void callSessionInitiated(android.telephony.ims.ImsCallProfile); - method public void callSessionInitiatedFailed(android.telephony.ims.ImsReasonInfo); - method public void callSessionInviteParticipantsRequestDelivered(); - method public void callSessionInviteParticipantsRequestFailed(android.telephony.ims.ImsReasonInfo); - method @Deprecated public void callSessionMayHandover(int, int); - method public void callSessionMergeComplete(android.telephony.ims.stub.ImsCallSessionImplBase); - method public void callSessionMergeFailed(android.telephony.ims.ImsReasonInfo); - method public void callSessionMergeStarted(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile); - method public void callSessionMultipartyStateChanged(boolean); - method public void callSessionProgressing(android.telephony.ims.ImsStreamMediaProfile); - method public void callSessionRemoveParticipantsRequestDelivered(); - method public void callSessionRemoveParticipantsRequestFailed(android.telephony.ims.ImsReasonInfo); - method public void callSessionResumeFailed(android.telephony.ims.ImsReasonInfo); - method public void callSessionResumeReceived(android.telephony.ims.ImsCallProfile); - method public void callSessionResumed(android.telephony.ims.ImsCallProfile); - method public void callSessionRttAudioIndicatorChanged(@NonNull android.telephony.ims.ImsStreamMediaProfile); - method public void callSessionRttMessageReceived(String); - method public void callSessionRttModifyRequestReceived(android.telephony.ims.ImsCallProfile); - method public void callSessionRttModifyResponseReceived(int); - method public void callSessionSuppServiceReceived(android.telephony.ims.ImsSuppServiceNotification); - method public void callSessionTerminated(android.telephony.ims.ImsReasonInfo); - method public void callSessionTtyModeReceived(int); - method public void callSessionUpdateFailed(android.telephony.ims.ImsReasonInfo); - method public void callSessionUpdateReceived(android.telephony.ims.ImsCallProfile); - method public void callSessionUpdated(android.telephony.ims.ImsCallProfile); - method public void callSessionUssdMessageReceived(int, String); - method public void onHandover(int, int, @Nullable android.telephony.ims.ImsReasonInfo); - method public void onHandoverFailed(int, int, @NonNull android.telephony.ims.ImsReasonInfo); - method public void onMayHandover(int, int); - } - - public final class ImsConferenceState implements android.os.Parcelable { - method public int describeContents(); - method public static int getConnectionStateForStatus(String); - method public void writeToParcel(android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.ImsConferenceState> CREATOR; - field public static final String DISPLAY_TEXT = "display-text"; - field public static final String ENDPOINT = "endpoint"; - field public static final String SIP_STATUS_CODE = "sipstatuscode"; - field public static final String STATUS = "status"; - field public static final String STATUS_ALERTING = "alerting"; - field public static final String STATUS_CONNECTED = "connected"; - field public static final String STATUS_CONNECT_FAIL = "connect-fail"; - field public static final String STATUS_DIALING_IN = "dialing-in"; - field public static final String STATUS_DIALING_OUT = "dialing-out"; - field public static final String STATUS_DISCONNECTED = "disconnected"; - field public static final String STATUS_DISCONNECTING = "disconnecting"; - field public static final String STATUS_MUTED_VIA_FOCUS = "muted-via-focus"; - field public static final String STATUS_ON_HOLD = "on-hold"; - field public static final String STATUS_PENDING = "pending"; - field public static final String STATUS_SEND_ONLY = "sendonly"; - field public static final String STATUS_SEND_RECV = "sendrecv"; - field public static final String USER = "user"; - field public final java.util.HashMap<java.lang.String,android.os.Bundle> mParticipants; - } - - public final class ImsException extends java.lang.Exception { - ctor public ImsException(@Nullable String); - ctor public ImsException(@Nullable String, int); - ctor public ImsException(@Nullable String, int, @Nullable Throwable); - } - - public final class ImsExternalCallState implements android.os.Parcelable { - ctor public ImsExternalCallState(@NonNull String, @NonNull android.net.Uri, @Nullable android.net.Uri, boolean, int, int, boolean); - method public int describeContents(); - method @NonNull public android.net.Uri getAddress(); - method public int getCallId(); - method public int getCallState(); - method public int getCallType(); - method @Nullable public android.net.Uri getLocalAddress(); - method public boolean isCallHeld(); - method public boolean isCallPullable(); - method public void writeToParcel(android.os.Parcel, int); - field public static final int CALL_STATE_CONFIRMED = 1; // 0x1 - field public static final int CALL_STATE_TERMINATED = 2; // 0x2 - field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.ImsExternalCallState> CREATOR; - } - - public class ImsManager { - method @NonNull public android.telephony.ims.SipDelegateManager getSipDelegateManager(int); - } - - public class ImsMmTelManager implements android.telephony.ims.RegistrationManager { - method @Deprecated @NonNull @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getFeatureState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>) throws android.telephony.ims.ImsException; - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoWiFiRoamingModeSetting(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAvailable(int, int); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isCapable(int, int); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void isSupported(int, int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>) throws android.telephony.ims.ImsException; - method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsMmTelManager.RegistrationCallback) throws android.telephony.ims.ImsException; - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setAdvancedCallingSettingEnabled(boolean); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setRttCapabilitySetting(boolean); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiModeSetting(int); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiNonPersistent(boolean, int); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiRoamingModeSetting(int); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiRoamingSettingEnabled(boolean); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiSettingEnabled(boolean); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVtSettingEnabled(boolean); - method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.ImsMmTelManager.RegistrationCallback); - } - - @Deprecated public static class ImsMmTelManager.RegistrationCallback extends android.telephony.ims.RegistrationManager.RegistrationCallback { - ctor @Deprecated public ImsMmTelManager.RegistrationCallback(); - } - - public final class ImsReasonInfo implements android.os.Parcelable { - field public static final String EXTRA_MSG_SERVICE_NOT_AUTHORIZED = "Forbidden. Not Authorized for Service"; - } - - public class ImsService extends android.app.Service { - ctor public ImsService(); - method public android.telephony.ims.feature.MmTelFeature createMmTelFeature(int); - method public android.telephony.ims.feature.RcsFeature createRcsFeature(int); - method public void disableIms(int); - method public void enableIms(int); - method public android.telephony.ims.stub.ImsConfigImplBase getConfig(int); - method public long getImsServiceCapabilities(); - method public android.telephony.ims.stub.ImsRegistrationImplBase getRegistration(int); - method @Nullable public android.telephony.ims.stub.SipTransportImplBase getSipTransport(int); - method public final void onUpdateSupportedImsFeatures(android.telephony.ims.stub.ImsFeatureConfiguration) throws android.os.RemoteException; - method public android.telephony.ims.stub.ImsFeatureConfiguration querySupportedImsFeatures(); - method public void readyForFeatureCreation(); - field public static final long CAPABILITY_SIP_DELEGATE_CREATION = 2L; // 0x2L - } - - public final class ImsSsData implements android.os.Parcelable { - ctor public ImsSsData(int, int, int, int, int); - method public int describeContents(); - method @Nullable public java.util.List<android.telephony.ims.ImsCallForwardInfo> getCallForwardInfo(); - method public int getRequestType(); - method public int getResult(); - method public int getServiceClass(); - method public int getServiceType(); - method @NonNull public java.util.List<android.telephony.ims.ImsSsInfo> getSuppServiceInfo(); - method public int getTeleserviceType(); - method public boolean isTypeBarring(); - method public boolean isTypeCf(); - method public boolean isTypeClip(); - method public boolean isTypeClir(); - method public boolean isTypeColp(); - method public boolean isTypeColr(); - method public boolean isTypeCw(); - method public boolean isTypeIcb(); - method public boolean isTypeInterrogation(); - method public boolean isTypeUnConditional(); - method public void writeToParcel(android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.ImsSsData> CREATOR; - field public static final int RESULT_SUCCESS = 0; // 0x0 - field public static final int SERVICE_CLASS_DATA = 2; // 0x2 - field public static final int SERVICE_CLASS_DATA_CIRCUIT_ASYNC = 32; // 0x20 - field public static final int SERVICE_CLASS_DATA_CIRCUIT_SYNC = 16; // 0x10 - field public static final int SERVICE_CLASS_DATA_PACKET_ACCESS = 64; // 0x40 - field public static final int SERVICE_CLASS_DATA_PAD = 128; // 0x80 - field public static final int SERVICE_CLASS_FAX = 4; // 0x4 - field public static final int SERVICE_CLASS_NONE = 0; // 0x0 - field public static final int SERVICE_CLASS_SMS = 8; // 0x8 - field public static final int SERVICE_CLASS_VOICE = 1; // 0x1 - field public static final int SS_ACTIVATION = 0; // 0x0 - field public static final int SS_ALL_BARRING = 18; // 0x12 - field public static final int SS_ALL_DATA_TELESERVICES = 3; // 0x3 - field public static final int SS_ALL_TELESERVICES_EXCEPT_SMS = 5; // 0x5 - field public static final int SS_ALL_TELESEVICES = 1; // 0x1 - field public static final int SS_ALL_TELE_AND_BEARER_SERVICES = 0; // 0x0 - field public static final int SS_BAIC = 16; // 0x10 - field public static final int SS_BAIC_ROAMING = 17; // 0x11 - field public static final int SS_BAOC = 13; // 0xd - field public static final int SS_BAOIC = 14; // 0xe - field public static final int SS_BAOIC_EXC_HOME = 15; // 0xf - field public static final int SS_CFU = 0; // 0x0 - field public static final int SS_CFUT = 6; // 0x6 - field public static final int SS_CF_ALL = 4; // 0x4 - field public static final int SS_CF_ALL_CONDITIONAL = 5; // 0x5 - field public static final int SS_CF_BUSY = 1; // 0x1 - field public static final int SS_CF_NOT_REACHABLE = 3; // 0x3 - field public static final int SS_CF_NO_REPLY = 2; // 0x2 - field public static final int SS_CLIP = 7; // 0x7 - field public static final int SS_CLIR = 8; // 0x8 - field public static final int SS_CNAP = 11; // 0xb - field public static final int SS_COLP = 9; // 0x9 - field public static final int SS_COLR = 10; // 0xa - field public static final int SS_DEACTIVATION = 1; // 0x1 - field public static final int SS_ERASURE = 4; // 0x4 - field public static final int SS_INCOMING_BARRING = 20; // 0x14 - field public static final int SS_INCOMING_BARRING_ANONYMOUS = 22; // 0x16 - field public static final int SS_INCOMING_BARRING_DN = 21; // 0x15 - field public static final int SS_INTERROGATION = 2; // 0x2 - field public static final int SS_OUTGOING_BARRING = 19; // 0x13 - field public static final int SS_REGISTRATION = 3; // 0x3 - field public static final int SS_SMS_SERVICES = 4; // 0x4 - field public static final int SS_TELEPHONY = 2; // 0x2 - field public static final int SS_WAIT = 12; // 0xc - } - - public static final class ImsSsData.Builder { - ctor public ImsSsData.Builder(int, int, int, int, int); - method @NonNull public android.telephony.ims.ImsSsData build(); - method @NonNull public android.telephony.ims.ImsSsData.Builder setCallForwardingInfo(@NonNull java.util.List<android.telephony.ims.ImsCallForwardInfo>); - method @NonNull public android.telephony.ims.ImsSsData.Builder setSuppServiceInfo(@NonNull java.util.List<android.telephony.ims.ImsSsInfo>); - } - - public final class ImsSsInfo implements android.os.Parcelable { - ctor @Deprecated public ImsSsInfo(int, @Nullable String); - method public int describeContents(); - method public int getClirInterrogationStatus(); - method public int getClirOutgoingState(); - method @Deprecated public String getIcbNum(); - method @Nullable public String getIncomingCommunicationBarringNumber(); - method public int getProvisionStatus(); - method public int getStatus(); - method public void writeToParcel(android.os.Parcel, int); - field public static final int CLIR_OUTGOING_DEFAULT = 0; // 0x0 - field public static final int CLIR_OUTGOING_INVOCATION = 1; // 0x1 - field public static final int CLIR_OUTGOING_SUPPRESSION = 2; // 0x2 - field public static final int CLIR_STATUS_NOT_PROVISIONED = 0; // 0x0 - field public static final int CLIR_STATUS_PROVISIONED_PERMANENT = 1; // 0x1 - field public static final int CLIR_STATUS_TEMPORARILY_ALLOWED = 4; // 0x4 - field public static final int CLIR_STATUS_TEMPORARILY_RESTRICTED = 3; // 0x3 - field public static final int CLIR_STATUS_UNKNOWN = 2; // 0x2 - field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.ImsSsInfo> CREATOR; - field public static final int DISABLED = 0; // 0x0 - field public static final int ENABLED = 1; // 0x1 - field public static final int NOT_REGISTERED = -1; // 0xffffffff - field public static final int SERVICE_NOT_PROVISIONED = 0; // 0x0 - field public static final int SERVICE_PROVISIONED = 1; // 0x1 - field public static final int SERVICE_PROVISIONING_UNKNOWN = -1; // 0xffffffff - } - - public static final class ImsSsInfo.Builder { - ctor public ImsSsInfo.Builder(int); - method @NonNull public android.telephony.ims.ImsSsInfo build(); - method @NonNull public android.telephony.ims.ImsSsInfo.Builder setClirInterrogationStatus(int); - method @NonNull public android.telephony.ims.ImsSsInfo.Builder setClirOutgoingState(int); - method @NonNull public android.telephony.ims.ImsSsInfo.Builder setIncomingCommunicationBarringNumber(@NonNull String); - method @NonNull public android.telephony.ims.ImsSsInfo.Builder setProvisionStatus(int); - } - - public final class ImsStreamMediaProfile implements android.os.Parcelable { - ctor public ImsStreamMediaProfile(int, int, int, int, int); - method public void copyFrom(android.telephony.ims.ImsStreamMediaProfile); - method public int describeContents(); - method public int getAudioDirection(); - method public int getAudioQuality(); - method public int getRttMode(); - method public int getVideoDirection(); - method public int getVideoQuality(); - method public boolean isReceivingRttAudio(); - method public boolean isRttCall(); - method public void setReceivingRttAudio(boolean); - method public void setRttMode(int); - method public void writeToParcel(android.os.Parcel, int); - field public static final int AUDIO_QUALITY_AMR = 1; // 0x1 - field public static final int AUDIO_QUALITY_AMR_WB = 2; // 0x2 - field public static final int AUDIO_QUALITY_EVRC = 4; // 0x4 - field public static final int AUDIO_QUALITY_EVRC_B = 5; // 0x5 - field public static final int AUDIO_QUALITY_EVRC_NW = 7; // 0x7 - field public static final int AUDIO_QUALITY_EVRC_WB = 6; // 0x6 - field public static final int AUDIO_QUALITY_EVS_FB = 20; // 0x14 - field public static final int AUDIO_QUALITY_EVS_NB = 17; // 0x11 - field public static final int AUDIO_QUALITY_EVS_SWB = 19; // 0x13 - field public static final int AUDIO_QUALITY_EVS_WB = 18; // 0x12 - field public static final int AUDIO_QUALITY_G711A = 13; // 0xd - field public static final int AUDIO_QUALITY_G711AB = 15; // 0xf - field public static final int AUDIO_QUALITY_G711U = 11; // 0xb - field public static final int AUDIO_QUALITY_G722 = 14; // 0xe - field public static final int AUDIO_QUALITY_G723 = 12; // 0xc - field public static final int AUDIO_QUALITY_G729 = 16; // 0x10 - field public static final int AUDIO_QUALITY_GSM_EFR = 8; // 0x8 - field public static final int AUDIO_QUALITY_GSM_FR = 9; // 0x9 - field public static final int AUDIO_QUALITY_GSM_HR = 10; // 0xa - field public static final int AUDIO_QUALITY_NONE = 0; // 0x0 - field public static final int AUDIO_QUALITY_QCELP13K = 3; // 0x3 - field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.ImsStreamMediaProfile> CREATOR; - field public static final int DIRECTION_INACTIVE = 0; // 0x0 - field public static final int DIRECTION_INVALID = -1; // 0xffffffff - field public static final int DIRECTION_RECEIVE = 1; // 0x1 - field public static final int DIRECTION_SEND = 2; // 0x2 - field public static final int DIRECTION_SEND_RECEIVE = 3; // 0x3 - field public static final int RTT_MODE_DISABLED = 0; // 0x0 - field public static final int RTT_MODE_FULL = 1; // 0x1 - field public static final int VIDEO_QUALITY_NONE = 0; // 0x0 - field public static final int VIDEO_QUALITY_QCIF = 1; // 0x1 - field public static final int VIDEO_QUALITY_QVGA_LANDSCAPE = 2; // 0x2 - field public static final int VIDEO_QUALITY_QVGA_PORTRAIT = 4; // 0x4 - field public static final int VIDEO_QUALITY_VGA_LANDSCAPE = 8; // 0x8 - field public static final int VIDEO_QUALITY_VGA_PORTRAIT = 16; // 0x10 - } - - public final class ImsSuppServiceNotification implements android.os.Parcelable { - ctor public ImsSuppServiceNotification(int, int, int, int, String, String[]); - method public int describeContents(); - method public void writeToParcel(android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.ImsSuppServiceNotification> CREATOR; - field public final int code; - field public final String[] history; - field public final int index; - field public final int notificationType; - field public final String number; - field public final int type; - } - - public class ImsUtListener { - method public void onLineIdentificationSupplementaryServiceResponse(int, @NonNull android.telephony.ims.ImsSsInfo); - method public void onSupplementaryServiceIndication(android.telephony.ims.ImsSsData); - method public void onUtConfigurationCallBarringQueried(int, android.telephony.ims.ImsSsInfo[]); - method public void onUtConfigurationCallForwardQueried(int, android.telephony.ims.ImsCallForwardInfo[]); - method public void onUtConfigurationCallWaitingQueried(int, android.telephony.ims.ImsSsInfo[]); - method @Deprecated public void onUtConfigurationQueried(int, android.os.Bundle); - method public void onUtConfigurationQueryFailed(int, android.telephony.ims.ImsReasonInfo); - method public void onUtConfigurationUpdateFailed(int, android.telephony.ims.ImsReasonInfo); - method public void onUtConfigurationUpdated(int); - field @Deprecated public static final String BUNDLE_KEY_CLIR = "queryClir"; - field @Deprecated public static final String BUNDLE_KEY_SSINFO = "imsSsInfo"; - } - - public abstract class ImsVideoCallProvider { - ctor public ImsVideoCallProvider(); - method public void changeCallDataUsage(long); - method public void changeCameraCapabilities(android.telecom.VideoProfile.CameraCapabilities); - method public void changePeerDimensions(int, int); - method public void changeVideoQuality(int); - method public void handleCallSessionEvent(int); - method public abstract void onRequestCallDataUsage(); - method public abstract void onRequestCameraCapabilities(); - method public abstract void onSendSessionModifyRequest(android.telecom.VideoProfile, android.telecom.VideoProfile); - method public abstract void onSendSessionModifyResponse(android.telecom.VideoProfile); - method public abstract void onSetCamera(String); - method public void onSetCamera(String, int); - method public abstract void onSetDeviceOrientation(int); - method public abstract void onSetDisplaySurface(android.view.Surface); - method public abstract void onSetPauseImage(android.net.Uri); - method public abstract void onSetPreviewSurface(android.view.Surface); - method public abstract void onSetZoom(float); - method public void receiveSessionModifyRequest(android.telecom.VideoProfile); - method public void receiveSessionModifyResponse(int, android.telecom.VideoProfile, android.telecom.VideoProfile); - } - - public class ProvisioningManager { - method @NonNull public static android.telephony.ims.ProvisioningManager createForSubscriptionId(int); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public int getProvisioningIntValue(int); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public boolean getProvisioningStatusForCapability(int, int); - method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public String getProvisioningStringValue(int); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public boolean getRcsProvisioningStatusForCapability(int); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyRcsAutoConfigurationReceived(@NonNull byte[], boolean); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerProvisioningChangedCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ProvisioningManager.Callback) throws android.telephony.ims.ImsException; - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningIntValue(int, int); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setProvisioningStatusForCapability(int, int, boolean); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningStringValue(int, @NonNull String); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setRcsProvisioningStatusForCapability(int, boolean); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterProvisioningChangedCallback(@NonNull android.telephony.ims.ProvisioningManager.Callback); - field public static final int KEY_VOICE_OVER_WIFI_ENTITLEMENT_ID = 67; // 0x43 - field public static final int KEY_VOICE_OVER_WIFI_MODE_OVERRIDE = 27; // 0x1b - field public static final int KEY_VOICE_OVER_WIFI_ROAMING_ENABLED_OVERRIDE = 26; // 0x1a - field public static final int PROVISIONING_VALUE_DISABLED = 0; // 0x0 - field public static final int PROVISIONING_VALUE_ENABLED = 1; // 0x1 - field public static final String STRING_QUERY_RESULT_ERROR_GENERIC = "STRING_QUERY_RESULT_ERROR_GENERIC"; - field public static final String STRING_QUERY_RESULT_ERROR_NOT_READY = "STRING_QUERY_RESULT_ERROR_NOT_READY"; - } - - public static class ProvisioningManager.Callback { - ctor public ProvisioningManager.Callback(); - method public void onProvisioningIntChanged(int, int); - method public void onProvisioningStringChanged(int, @NonNull String); - } - - public class RcsUceAdapter { - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUceSettingEnabled(boolean) throws android.telephony.ims.ImsException; - } - - public class SipDelegateManager { - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isSupported() throws android.telephony.ims.ImsException; - } - -} - -package android.telephony.ims.feature { - - public final class CapabilityChangeRequest implements android.os.Parcelable { - method public void addCapabilitiesToDisableForTech(int, int); - method public void addCapabilitiesToEnableForTech(int, int); - method public int describeContents(); - method public java.util.List<android.telephony.ims.feature.CapabilityChangeRequest.CapabilityPair> getCapabilitiesToDisable(); - method public java.util.List<android.telephony.ims.feature.CapabilityChangeRequest.CapabilityPair> getCapabilitiesToEnable(); - method public void writeToParcel(android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.feature.CapabilityChangeRequest> CREATOR; - } - - public static class CapabilityChangeRequest.CapabilityPair { - ctor public CapabilityChangeRequest.CapabilityPair(int, int); - method public int getCapability(); - method public int getRadioTech(); - } - - public abstract class ImsFeature { - ctor public ImsFeature(); - method public abstract void changeEnabledCapabilities(android.telephony.ims.feature.CapabilityChangeRequest, android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy); - method public int getFeatureState(); - method public final int getSlotIndex(); - method public abstract void onFeatureReady(); - method public abstract void onFeatureRemoved(); - method public final void setFeatureState(int); - field public static final int CAPABILITY_ERROR_GENERIC = -1; // 0xffffffff - field public static final int CAPABILITY_SUCCESS = 0; // 0x0 - field public static final int FEATURE_EMERGENCY_MMTEL = 0; // 0x0 - field public static final int FEATURE_MMTEL = 1; // 0x1 - field public static final int FEATURE_RCS = 2; // 0x2 - field public static final int STATE_INITIALIZING = 1; // 0x1 - field public static final int STATE_READY = 2; // 0x2 - field public static final int STATE_UNAVAILABLE = 0; // 0x0 - } - - @Deprecated public static class ImsFeature.Capabilities { - field @Deprecated protected int mCapabilities; - } - - protected static class ImsFeature.CapabilityCallbackProxy { - method public void onChangeCapabilityConfigurationError(int, int, int); - } - - public class MmTelFeature extends android.telephony.ims.feature.ImsFeature { - ctor public MmTelFeature(); - method public void changeEnabledCapabilities(@NonNull android.telephony.ims.feature.CapabilityChangeRequest, @NonNull android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy); - method @Nullable public android.telephony.ims.ImsCallProfile createCallProfile(int, int); - method @Nullable public android.telephony.ims.stub.ImsCallSessionImplBase createCallSession(@NonNull android.telephony.ims.ImsCallProfile); - method @NonNull public android.telephony.ims.stub.ImsEcbmImplBase getEcbm(); - method @NonNull public android.telephony.ims.stub.ImsMultiEndpointImplBase getMultiEndpoint(); - method @NonNull public android.telephony.ims.stub.ImsSmsImplBase getSmsImplementation(); - method @NonNull public android.telephony.ims.stub.ImsUtImplBase getUt(); - method public final void notifyCapabilitiesStatusChanged(@NonNull android.telephony.ims.feature.MmTelFeature.MmTelCapabilities); - method public final void notifyIncomingCall(@NonNull android.telephony.ims.stub.ImsCallSessionImplBase, @NonNull android.os.Bundle); - method public final void notifyRejectedCall(@NonNull android.telephony.ims.ImsCallProfile, @NonNull android.telephony.ims.ImsReasonInfo); - method public final void notifyVoiceMessageCountUpdate(int); - method public void onFeatureReady(); - method public void onFeatureRemoved(); - method public boolean queryCapabilityConfiguration(int, int); - method @NonNull public final android.telephony.ims.feature.MmTelFeature.MmTelCapabilities queryCapabilityStatus(); - method public void setUiTtyMode(int, @Nullable android.os.Message); - method public int shouldProcessCall(@NonNull String[]); - field public static final String EXTRA_IS_UNKNOWN_CALL = "android.telephony.ims.feature.extra.IS_UNKNOWN_CALL"; - field public static final String EXTRA_IS_USSD = "android.telephony.ims.feature.extra.IS_USSD"; - field public static final int PROCESS_CALL_CSFB = 1; // 0x1 - field public static final int PROCESS_CALL_IMS = 0; // 0x0 - } - - public static class MmTelFeature.MmTelCapabilities extends android.telephony.ims.feature.ImsFeature.Capabilities { - ctor public MmTelFeature.MmTelCapabilities(); - ctor @Deprecated public MmTelFeature.MmTelCapabilities(android.telephony.ims.feature.ImsFeature.Capabilities); - ctor public MmTelFeature.MmTelCapabilities(int); - method public final void addCapabilities(int); - method public final void removeCapabilities(int); - } - - public class RcsFeature extends android.telephony.ims.feature.ImsFeature { - ctor public RcsFeature(); - method public void changeEnabledCapabilities(@NonNull android.telephony.ims.feature.CapabilityChangeRequest, @NonNull android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy); - method public void onFeatureReady(); - method public void onFeatureRemoved(); - } - -} - -package android.telephony.ims.stub { - - public class ImsCallSessionImplBase implements java.lang.AutoCloseable { - ctor public ImsCallSessionImplBase(); - method public void accept(int, android.telephony.ims.ImsStreamMediaProfile); - method public void close(); - method public void deflect(String); - method public void extendToConference(String[]); - method public String getCallId(); - method public android.telephony.ims.ImsCallProfile getCallProfile(); - method public android.telephony.ims.ImsVideoCallProvider getImsVideoCallProvider(); - method public android.telephony.ims.ImsCallProfile getLocalCallProfile(); - method public String getProperty(String); - method public android.telephony.ims.ImsCallProfile getRemoteCallProfile(); - method public int getState(); - method public void hold(android.telephony.ims.ImsStreamMediaProfile); - method public void inviteParticipants(String[]); - method public boolean isInCall(); - method public boolean isMultiparty(); - method public void merge(); - method public void reject(int); - method public void removeParticipants(String[]); - method public void resume(android.telephony.ims.ImsStreamMediaProfile); - method public void sendDtmf(char, android.os.Message); - method public void sendRttMessage(String); - method public void sendRttModifyRequest(android.telephony.ims.ImsCallProfile); - method public void sendRttModifyResponse(boolean); - method public void sendUssd(String); - method public void setListener(android.telephony.ims.ImsCallSessionListener); - method public void setMute(boolean); - method public void start(String, android.telephony.ims.ImsCallProfile); - method public void startConference(String[], android.telephony.ims.ImsCallProfile); - method public void startDtmf(char); - method public void stopDtmf(); - method public void terminate(int); - method public void update(int, android.telephony.ims.ImsStreamMediaProfile); - field public static final int USSD_MODE_NOTIFY = 0; // 0x0 - field public static final int USSD_MODE_REQUEST = 1; // 0x1 - } - - public static class ImsCallSessionImplBase.State { - method public static String toString(int); - field public static final int ESTABLISHED = 4; // 0x4 - field public static final int ESTABLISHING = 3; // 0x3 - field public static final int IDLE = 0; // 0x0 - field public static final int INITIATED = 1; // 0x1 - field public static final int INVALID = -1; // 0xffffffff - field public static final int NEGOTIATING = 2; // 0x2 - field public static final int REESTABLISHING = 6; // 0x6 - field public static final int RENEGOTIATING = 5; // 0x5 - field public static final int TERMINATED = 8; // 0x8 - field public static final int TERMINATING = 7; // 0x7 - } - - public class ImsConfigImplBase { - ctor public ImsConfigImplBase(); - method public int getConfigInt(int); - method public String getConfigString(int); - method public final void notifyProvisionedValueChanged(int, int); - method public final void notifyProvisionedValueChanged(int, String); - method public void notifyRcsAutoConfigurationReceived(@NonNull byte[], boolean); - method public int setConfig(int, int); - method public int setConfig(int, String); - field public static final int CONFIG_RESULT_FAILED = 1; // 0x1 - field public static final int CONFIG_RESULT_SUCCESS = 0; // 0x0 - field public static final int CONFIG_RESULT_UNKNOWN = -1; // 0xffffffff - } - - public class ImsEcbmImplBase { - ctor public ImsEcbmImplBase(); - method public final void enteredEcbm(); - method public void exitEmergencyCallbackMode(); - method public final void exitedEcbm(); - } - - public final class ImsFeatureConfiguration implements android.os.Parcelable { - method public int describeContents(); - method public java.util.Set<android.telephony.ims.stub.ImsFeatureConfiguration.FeatureSlotPair> getServiceFeatures(); - method public void writeToParcel(android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.stub.ImsFeatureConfiguration> CREATOR; - } - - public static class ImsFeatureConfiguration.Builder { - ctor public ImsFeatureConfiguration.Builder(); - method public android.telephony.ims.stub.ImsFeatureConfiguration.Builder addFeature(int, int); - method public android.telephony.ims.stub.ImsFeatureConfiguration build(); - } - - public static final class ImsFeatureConfiguration.FeatureSlotPair { - ctor public ImsFeatureConfiguration.FeatureSlotPair(int, int); - field public final int featureType; - field public final int slotId; - } - - public class ImsMultiEndpointImplBase { - ctor public ImsMultiEndpointImplBase(); - method public final void onImsExternalCallStateUpdate(java.util.List<android.telephony.ims.ImsExternalCallState>); - method public void requestImsExternalCallStateInfo(); - } - - public class ImsRegistrationImplBase { - ctor public ImsRegistrationImplBase(); - method public final void onDeregistered(android.telephony.ims.ImsReasonInfo); - method public final void onRegistered(int); - method public final void onRegistering(int); - method public final void onSubscriberAssociatedUriChanged(android.net.Uri[]); - method public final void onTechnologyChangeFailed(int, android.telephony.ims.ImsReasonInfo); - field public static final int REGISTRATION_TECH_IWLAN = 1; // 0x1 - field public static final int REGISTRATION_TECH_LTE = 0; // 0x0 - field public static final int REGISTRATION_TECH_NONE = -1; // 0xffffffff - } - - public class ImsSmsImplBase { - ctor public ImsSmsImplBase(); - method public void acknowledgeSms(int, @IntRange(from=0, to=65535) int, int); - method public void acknowledgeSmsReport(int, @IntRange(from=0, to=65535) int, int); - method public String getSmsFormat(); - method public void onReady(); - method @Deprecated public final void onSendSmsResult(int, @IntRange(from=0, to=65535) int, int, int) throws java.lang.RuntimeException; - method public final void onSendSmsResultError(int, @IntRange(from=0, to=65535) int, int, int, int) throws java.lang.RuntimeException; - method public final void onSendSmsResultSuccess(int, @IntRange(from=0, to=65535) int) throws java.lang.RuntimeException; - method public final void onSmsReceived(int, String, byte[]) throws java.lang.RuntimeException; - method @Deprecated public final void onSmsStatusReportReceived(int, @IntRange(from=0, to=65535) int, String, byte[]) throws java.lang.RuntimeException; - method public final void onSmsStatusReportReceived(int, String, byte[]) throws java.lang.RuntimeException; - method public void sendSms(int, @IntRange(from=0, to=65535) int, String, String, boolean, byte[]); - field public static final int DELIVER_STATUS_ERROR_GENERIC = 2; // 0x2 - field public static final int DELIVER_STATUS_ERROR_NO_MEMORY = 3; // 0x3 - field public static final int DELIVER_STATUS_ERROR_REQUEST_NOT_SUPPORTED = 4; // 0x4 - field public static final int DELIVER_STATUS_OK = 1; // 0x1 - field public static final int RESULT_NO_NETWORK_ERROR = -1; // 0xffffffff - field public static final int SEND_STATUS_ERROR = 2; // 0x2 - field public static final int SEND_STATUS_ERROR_FALLBACK = 4; // 0x4 - field public static final int SEND_STATUS_ERROR_RETRY = 3; // 0x3 - field public static final int SEND_STATUS_OK = 1; // 0x1 - field public static final int STATUS_REPORT_STATUS_ERROR = 2; // 0x2 - field public static final int STATUS_REPORT_STATUS_OK = 1; // 0x1 - } - - public class ImsUtImplBase { - ctor public ImsUtImplBase(); - method public void close(); - method public int queryCallBarring(int); - method public int queryCallBarringForServiceClass(int, int); - method public int queryCallForward(int, String); - method public int queryCallWaiting(); - method public int queryClip(); - method public int queryClir(); - method public int queryColp(); - method public int queryColr(); - method public void setListener(android.telephony.ims.ImsUtListener); - method public int transact(android.os.Bundle); - method public int updateCallBarring(int, int, String[]); - method public int updateCallBarringForServiceClass(int, int, String[], int); - method public int updateCallForward(int, int, String, int, int); - method public int updateCallWaiting(boolean, int); - method public int updateClip(boolean); - method public int updateClir(int); - method public int updateColp(boolean); - method public int updateColr(int); - } - - public class SipTransportImplBase { - ctor public SipTransportImplBase(@NonNull java.util.concurrent.Executor); - } - -} - -package android.telephony.mbms { - - public static class DownloadRequest.Builder { - method public android.telephony.mbms.DownloadRequest.Builder setServiceId(String); - } - - public final class FileInfo implements android.os.Parcelable { - ctor public FileInfo(android.net.Uri, String); - } - - public final class FileServiceInfo extends android.telephony.mbms.ServiceInfo implements android.os.Parcelable { - ctor public FileServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date, java.util.List<android.telephony.mbms.FileInfo>); - } - - public class MbmsDownloadReceiver extends android.content.BroadcastReceiver { - field public static final int RESULT_APP_NOTIFICATION_ERROR = 6; // 0x6 - field public static final int RESULT_BAD_TEMP_FILE_ROOT = 3; // 0x3 - field public static final int RESULT_DOWNLOAD_FINALIZATION_ERROR = 4; // 0x4 - field public static final int RESULT_INVALID_ACTION = 1; // 0x1 - field public static final int RESULT_MALFORMED_INTENT = 2; // 0x2 - field public static final int RESULT_OK = 0; // 0x0 - field public static final int RESULT_TEMP_FILE_GENERATION_ERROR = 5; // 0x5 - } - - public final class StreamingServiceInfo extends android.telephony.mbms.ServiceInfo implements android.os.Parcelable { - ctor public StreamingServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date); - } - - public final class UriPathPair implements android.os.Parcelable { - method public int describeContents(); - method public android.net.Uri getContentUri(); - method public android.net.Uri getFilePathUri(); - method public void writeToParcel(android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.telephony.mbms.UriPathPair> CREATOR; - } - -} - -package android.telephony.mbms.vendor { - - public class MbmsDownloadServiceBase extends android.os.Binder implements android.os.IInterface { - ctor public MbmsDownloadServiceBase(); - method public int addProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener) throws android.os.RemoteException; - method public int addServiceAnnouncement(int, @NonNull byte[]); - method public int addStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener) throws android.os.RemoteException; - method public android.os.IBinder asBinder(); - method public int cancelDownload(android.telephony.mbms.DownloadRequest) throws android.os.RemoteException; - method public void dispose(int) throws android.os.RemoteException; - method public int download(android.telephony.mbms.DownloadRequest) throws android.os.RemoteException; - method public int initialize(int, android.telephony.mbms.MbmsDownloadSessionCallback) throws android.os.RemoteException; - method @NonNull public java.util.List<android.telephony.mbms.DownloadRequest> listPendingDownloads(int) throws android.os.RemoteException; - method public void onAppCallbackDied(int, int); - method public boolean onTransact(int, android.os.Parcel, android.os.Parcel, int) throws android.os.RemoteException; - method public int removeProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener) throws android.os.RemoteException; - method public int removeStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener) throws android.os.RemoteException; - method public int requestDownloadState(android.telephony.mbms.DownloadRequest, android.telephony.mbms.FileInfo) throws android.os.RemoteException; - method public int requestUpdateFileServices(int, java.util.List<java.lang.String>) throws android.os.RemoteException; - method public int resetDownloadKnowledge(android.telephony.mbms.DownloadRequest) throws android.os.RemoteException; - method public int setTempFileRootDirectory(int, String) throws android.os.RemoteException; - } - - public class MbmsGroupCallServiceBase extends android.app.Service { - ctor public MbmsGroupCallServiceBase(); - method public void dispose(int) throws android.os.RemoteException; - method public int initialize(@NonNull android.telephony.mbms.MbmsGroupCallSessionCallback, int) throws android.os.RemoteException; - method public void onAppCallbackDied(int, int); - method public android.os.IBinder onBind(android.content.Intent); - method public int startGroupCall(int, long, @NonNull java.util.List<java.lang.Integer>, @NonNull java.util.List<java.lang.Integer>, @NonNull android.telephony.mbms.GroupCallCallback); - method public void stopGroupCall(int, long); - method public void updateGroupCall(int, long, @NonNull java.util.List<java.lang.Integer>, @NonNull java.util.List<java.lang.Integer>); - } - - public class MbmsStreamingServiceBase extends android.os.Binder implements android.os.IInterface { - ctor public MbmsStreamingServiceBase(); - method public android.os.IBinder asBinder(); - method public void dispose(int) throws android.os.RemoteException; - method @Nullable public android.net.Uri getPlaybackUri(int, String) throws android.os.RemoteException; - method public int initialize(android.telephony.mbms.MbmsStreamingSessionCallback, int) throws android.os.RemoteException; - method public void onAppCallbackDied(int, int); - method public boolean onTransact(int, android.os.Parcel, android.os.Parcel, int) throws android.os.RemoteException; - method public int requestUpdateStreamingServices(int, java.util.List<java.lang.String>) throws android.os.RemoteException; - method public int startStreaming(int, String, android.telephony.mbms.StreamingServiceCallback) throws android.os.RemoteException; - method public void stopStreaming(int, String) throws android.os.RemoteException; - } - - public class VendorUtils { - ctor public VendorUtils(); - method public static android.content.ComponentName getAppReceiverFromPackageName(android.content.Context, String); - field public static final String ACTION_CLEANUP = "android.telephony.mbms.action.CLEANUP"; - field public static final String ACTION_DOWNLOAD_RESULT_INTERNAL = "android.telephony.mbms.action.DOWNLOAD_RESULT_INTERNAL"; - field public static final String ACTION_FILE_DESCRIPTOR_REQUEST = "android.telephony.mbms.action.FILE_DESCRIPTOR_REQUEST"; - field public static final String EXTRA_FD_COUNT = "android.telephony.mbms.extra.FD_COUNT"; - field public static final String EXTRA_FINAL_URI = "android.telephony.mbms.extra.FINAL_URI"; - field public static final String EXTRA_FREE_URI_LIST = "android.telephony.mbms.extra.FREE_URI_LIST"; - field public static final String EXTRA_PAUSED_LIST = "android.telephony.mbms.extra.PAUSED_LIST"; - field public static final String EXTRA_PAUSED_URI_LIST = "android.telephony.mbms.extra.PAUSED_URI_LIST"; - field public static final String EXTRA_SERVICE_ID = "android.telephony.mbms.extra.SERVICE_ID"; - field public static final String EXTRA_TEMP_FILES_IN_USE = "android.telephony.mbms.extra.TEMP_FILES_IN_USE"; - field public static final String EXTRA_TEMP_FILE_ROOT = "android.telephony.mbms.extra.TEMP_FILE_ROOT"; - field public static final String EXTRA_TEMP_LIST = "android.telephony.mbms.extra.TEMP_LIST"; - } - -} - diff --git a/telephony/api/system-removed.txt b/telephony/api/system-removed.txt deleted file mode 100644 index ae46075c4829..000000000000 --- a/telephony/api/system-removed.txt +++ /dev/null @@ -1,19 +0,0 @@ -// Signature format: 2.0 -package android.telephony { - - public class TelephonyManager { - method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void answerRingingCall(); - method @Deprecated @RequiresPermission(android.Manifest.permission.CALL_PHONE) public boolean endCall(); - method @Deprecated public void silenceRinger(); - } - -} - -package android.telephony.data { - - public final class DataCallResponse implements android.os.Parcelable { - ctor public DataCallResponse(int, int, int, int, int, @Nullable String, @Nullable java.util.List<android.net.LinkAddress>, @Nullable java.util.List<java.net.InetAddress>, @Nullable java.util.List<java.net.InetAddress>, @Nullable java.util.List<java.net.InetAddress>, int); - } - -} - diff --git a/telephony/framework-telephony-jarjar-rules.txt b/telephony/framework-telephony-jarjar-rules.txt deleted file mode 100644 index e1bb90194f69..000000000000 --- a/telephony/framework-telephony-jarjar-rules.txt +++ /dev/null @@ -1,10 +0,0 @@ -rule android.telephony.Annotation* android.telephony.framework.Annotation@1 -rule android.util.RecurrenceRule* android.telephony.RecurrenceRule@1 -rule com.android.i18n.phonenumbers.** com.android.telephony.framework.phonenumbers.@1 -rule com.android.internal.os.SomeArgs* android.telephony.SomeArgs@1 -rule com.android.internal.util.BitwiseInputStream* android.telephony.BitwiseInputStream@1 -rule com.android.internal.util.BitwiseOutputStream* android.telephony.BitwiseOutputStream@1 -rule com.android.internal.util.FunctionalUtils* android.telephony.FunctionalUtils@1 -rule com.android.internal.util.Preconditions* android.telephony.Preconditions@1 -rule com.android.internal.util.IndentingPrintWriter* android.telephony.IndentingPrintWriter@1 -rule com.android.internal.util.HexDump* android.telephony.HexDump@1 diff --git a/tests/ActivityViewTest/AndroidManifest.xml b/tests/ActivityViewTest/AndroidManifest.xml index c84b7d904f0a..7563a25424ad 100644 --- a/tests/ActivityViewTest/AndroidManifest.xml +++ b/tests/ActivityViewTest/AndroidManifest.xml @@ -17,7 +17,7 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.google.android.test.activityview"> <uses-permission android:name="android.permission.INJECT_EVENTS"/> - <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS"/> + <uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS"/> <uses-permission android:name="android.permission.ACTIVITY_EMBEDDING"/> <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW"/> diff --git a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java index 66e44e123c7e..1adbc2dc182c 100644 --- a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java +++ b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java @@ -32,7 +32,7 @@ public class HierrarchicalDataClassBase implements Parcelable { - // Code below generated by codegen v1.0.16. + // Code below generated by codegen v1.0.18. // // DO NOT MODIFY! // CHECKSTYLE:OFF Generated code @@ -51,7 +51,7 @@ public class HierrarchicalDataClassBase implements Parcelable { } @DataClass.Generated.Member - public HierrarchicalDataClassBase setBaseData( int value) { + public @android.annotation.NonNull HierrarchicalDataClassBase setBaseData( int value) { mBaseData = value; return this; } @@ -98,8 +98,8 @@ public class HierrarchicalDataClassBase implements Parcelable { }; @DataClass.Generated( - time = 1601950882280L, - codegenVersion = "1.0.16", + time = 1603836848866L, + codegenVersion = "1.0.18", sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java", inputSignatures = "private int mBaseData\nclass HierrarchicalDataClassBase extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genSetters=true)") @Deprecated diff --git a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java index 643abd8650d0..a4fdcd18aa3d 100644 --- a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java +++ b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java @@ -46,7 +46,7 @@ public class HierrarchicalDataClassChild extends HierrarchicalDataClassBase { - // Code below generated by codegen v1.0.16. + // Code below generated by codegen v1.0.18. // // DO NOT MODIFY! // CHECKSTYLE:OFF Generated code @@ -65,7 +65,7 @@ public class HierrarchicalDataClassChild extends HierrarchicalDataClassBase { } @DataClass.Generated.Member - public HierrarchicalDataClassChild setChildData(@NonNull String value) { + public @NonNull HierrarchicalDataClassChild setChildData(@NonNull String value) { mChildData = value; com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, mChildData); @@ -120,8 +120,8 @@ public class HierrarchicalDataClassChild extends HierrarchicalDataClassBase { }; @DataClass.Generated( - time = 1601950883222L, - codegenVersion = "1.0.16", + time = 1603836849753L, + codegenVersion = "1.0.18", sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java", inputSignatures = "private @android.annotation.NonNull java.lang.String mChildData\nclass HierrarchicalDataClassChild extends com.android.codegentest.HierrarchicalDataClassBase implements []\n@com.android.internal.util.DataClass(genParcelable=true, genConstructor=false, genSetters=true)") @Deprecated diff --git a/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java b/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java index 5e33a338f098..f0d728e2f604 100644 --- a/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java +++ b/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java @@ -54,7 +54,7 @@ public class ParcelAllTheThingsDataClass implements Parcelable { - // Code below generated by codegen v1.0.16. + // Code below generated by codegen v1.0.18. // // DO NOT MODIFY! // CHECKSTYLE:OFF Generated code @@ -412,8 +412,8 @@ public class ParcelAllTheThingsDataClass implements Parcelable { } @DataClass.Generated( - time = 1601950881327L, - codegenVersion = "1.0.16", + time = 1603836847927L, + codegenVersion = "1.0.18", sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java", inputSignatures = " @android.annotation.NonNull java.lang.String[] mStringArray\n @android.annotation.NonNull int[] mIntArray\n @android.annotation.NonNull java.util.List<java.lang.String> mStringList\n @android.annotation.NonNull java.util.Map<java.lang.String,com.android.codegentest.SampleWithCustomBuilder> mMap\n @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.String> mStringMap\n @android.annotation.NonNull android.util.SparseArray<com.android.codegentest.SampleWithCustomBuilder> mSparseArray\n @android.annotation.NonNull android.util.SparseIntArray mSparseIntArray\n @java.lang.SuppressWarnings({\"WeakerAccess\"}) @android.annotation.Nullable java.lang.Boolean mNullableBoolean\nclass ParcelAllTheThingsDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genAidl=false, genToString=true)") @Deprecated diff --git a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java index 9e5b1a974030..a3f458beebcc 100644 --- a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java +++ b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java @@ -23,6 +23,7 @@ import android.annotation.Size; import android.annotation.StringDef; import android.annotation.StringRes; import android.annotation.UserIdInt; +import android.content.pm.PackageManager; import android.net.LinkAddress; import android.os.Parcel; import android.os.Parcelable; @@ -86,9 +87,10 @@ public final class SampleDataClass implements Parcelable { * @see #toString() * @see State */ - public static final int STATE_UNDEFINED = -1; public static final int STATE_ON = 1; public static final int STATE_OFF = 0; + public static final int STATE_UNDEFINED + = PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED; /** * {@link IntDef}s with values specified in hex("0x...") are considered to be @@ -342,7 +344,7 @@ public final class SampleDataClass implements Parcelable { - // Code below generated by codegen v1.0.16. + // Code below generated by codegen v1.0.18. // // DO NOT MODIFY! // CHECKSTYLE:OFF Generated code @@ -356,9 +358,9 @@ public final class SampleDataClass implements Parcelable { @IntDef(prefix = "STATE_", value = { - STATE_UNDEFINED, STATE_ON, - STATE_OFF + STATE_OFF, + STATE_UNDEFINED }) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @DataClass.Generated.Member @@ -367,12 +369,12 @@ public final class SampleDataClass implements Parcelable { @DataClass.Generated.Member public static String stateToString(@State int value) { switch (value) { - case STATE_UNDEFINED: - return "STATE_UNDEFINED"; case STATE_ON: return "STATE_ON"; case STATE_OFF: return "STATE_OFF"; + case STATE_UNDEFINED: + return "STATE_UNDEFINED"; default: return Integer.toHexString(value); } } @@ -560,14 +562,14 @@ public final class SampleDataClass implements Parcelable { | FLAG_AUGMENTED_REQUEST); this.mState = state; - if (!(mState == STATE_UNDEFINED) - && !(mState == STATE_ON) - && !(mState == STATE_OFF)) { + if (!(mState == STATE_ON) + && !(mState == STATE_OFF) + && !(mState == STATE_UNDEFINED)) { throw new java.lang.IllegalArgumentException( "state was " + mState + " but must be one of: " - + "STATE_UNDEFINED(" + STATE_UNDEFINED + "), " + "STATE_ON(" + STATE_ON + "), " - + "STATE_OFF(" + STATE_OFF + ")"); + + "STATE_OFF(" + STATE_OFF + "), " + + "STATE_UNDEFINED(" + STATE_UNDEFINED + ")"); } this.charSeq = charSeq; @@ -820,7 +822,7 @@ public final class SampleDataClass implements Parcelable { * pieces in multiple places for each field. */ @DataClass.Generated.Member - public SampleDataClass setNum( int value) { + public @NonNull SampleDataClass setNum( int value) { mNum = value; return this; } @@ -832,7 +834,7 @@ public final class SampleDataClass implements Parcelable { * @see #mNum2 ..and so should blocks at the bottom, e.g. {@code @see} blocks. */ @DataClass.Generated.Member - public SampleDataClass setNum2( int value) { + public @NonNull SampleDataClass setNum2( int value) { mNum2 = value; return this; } @@ -846,7 +848,7 @@ public final class SampleDataClass implements Parcelable { * @hide */ @DataClass.Generated.Member - public SampleDataClass setNum4( int value) { + public @NonNull SampleDataClass setNum4( int value) { mNum4 = value; return this; } @@ -855,7 +857,7 @@ public final class SampleDataClass implements Parcelable { * {@link Nullable} or {@link NonNull} annotation is required on all non-primitive fields. */ @DataClass.Generated.Member - public SampleDataClass setName(@NonNull String value) { + public @NonNull SampleDataClass setName(@NonNull String value) { mName = value; return this; } @@ -868,7 +870,7 @@ public final class SampleDataClass implements Parcelable { * while mandatory fields are passed via {@link Builder#Builder constructor}. */ @DataClass.Generated.Member - public SampleDataClass setName2(@NonNull String value) { + public @NonNull SampleDataClass setName2(@NonNull String value) { mName2 = value; AnnotationValidations.validate( NonNull.class, null, mName2); @@ -880,7 +882,7 @@ public final class SampleDataClass implements Parcelable { * {@link #defaultName4 defaultFieldName()} can be defined to compute the default value. */ @DataClass.Generated.Member - public SampleDataClass setName4(@NonNull String value) { + public @NonNull SampleDataClass setName4(@NonNull String value) { mName4 = value; AnnotationValidations.validate( NonNull.class, null, mName4); @@ -892,7 +894,7 @@ public final class SampleDataClass implements Parcelable { * E.g. {@link Parcelable} subclasses, {@link String}, {@link int}, {@link boolean}, etc. */ @DataClass.Generated.Member - public SampleDataClass setOtherParcelable(@NonNull AccessibilityNodeInfo value) { + public @NonNull SampleDataClass setOtherParcelable(@NonNull AccessibilityNodeInfo value) { mOtherParcelable = value; return this; } @@ -904,7 +906,7 @@ public final class SampleDataClass implements Parcelable { * @see MyDateParcelling an example {@link Parcelling} implementation */ @DataClass.Generated.Member - public SampleDataClass setDate(@NonNull Date value) { + public @NonNull SampleDataClass setDate(@NonNull Date value) { mDate = value; AnnotationValidations.validate( NonNull.class, null, mDate); @@ -916,7 +918,7 @@ public final class SampleDataClass implements Parcelable { * to encourage its reuse. */ @DataClass.Generated.Member - public SampleDataClass setPattern(@NonNull Pattern value) { + public @NonNull SampleDataClass setPattern(@NonNull Pattern value) { mPattern = value; AnnotationValidations.validate( NonNull.class, null, mPattern); @@ -929,7 +931,7 @@ public final class SampleDataClass implements Parcelable { * {@link Builder#addLinkAddresses2(LinkAddress) add} method is generated for convenience. */ @DataClass.Generated.Member - public SampleDataClass setLinkAddresses2(@NonNull List<LinkAddress> value) { + public @NonNull SampleDataClass setLinkAddresses2(@NonNull List<LinkAddress> value) { mLinkAddresses2 = value; AnnotationValidations.validate( NonNull.class, null, mLinkAddresses2); @@ -943,7 +945,7 @@ public final class SampleDataClass implements Parcelable { * @see Builder#addLinkAddress(LinkAddress) */ @DataClass.Generated.Member - public SampleDataClass setLinkAddresses(@NonNull ArrayList<LinkAddress> value) { + public @NonNull SampleDataClass setLinkAddresses(@NonNull ArrayList<LinkAddress> value) { mLinkAddresses = value; AnnotationValidations.validate( NonNull.class, null, mLinkAddresses); @@ -957,7 +959,7 @@ public final class SampleDataClass implements Parcelable { * @see Builder#setLinkAddresses4(LinkAddress...) */ @DataClass.Generated.Member - public SampleDataClass setLinkAddresses4(@NonNull LinkAddress... value) { + public @NonNull SampleDataClass setLinkAddresses4(@NonNull LinkAddress... value) { mLinkAddresses4 = value; return this; } @@ -970,7 +972,7 @@ public final class SampleDataClass implements Parcelable { * @see Builder#setStateName */ @DataClass.Generated.Member - public SampleDataClass setStateName(@StateName @NonNull String value) { + public @NonNull SampleDataClass setStateName(@StateName @NonNull String value) { mStateName = value; if (!(Objects.equals(mStateName, STATE_NAME_UNDEFINED)) @@ -992,7 +994,7 @@ public final class SampleDataClass implements Parcelable { * Fields annotated with {@link IntDef} annotations also get a proper {@link #toString()} value. */ @DataClass.Generated.Member - public SampleDataClass setFlags(@RequestFlags int value) { + public @NonNull SampleDataClass setFlags(@RequestFlags int value) { mFlags = value; Preconditions.checkFlagsArgument( @@ -1007,17 +1009,17 @@ public final class SampleDataClass implements Parcelable { * Above is true for both {@link IntDef#flag flags} and enum-like {@link IntDef}s */ @DataClass.Generated.Member - public SampleDataClass setState(@State int value) { + public @NonNull SampleDataClass setState(@State int value) { mState = value; - if (!(mState == STATE_UNDEFINED) - && !(mState == STATE_ON) - && !(mState == STATE_OFF)) { + if (!(mState == STATE_ON) + && !(mState == STATE_OFF) + && !(mState == STATE_UNDEFINED)) { throw new java.lang.IllegalArgumentException( "state was " + mState + " but must be one of: " - + "STATE_UNDEFINED(" + STATE_UNDEFINED + "), " + "STATE_ON(" + STATE_ON + "), " - + "STATE_OFF(" + STATE_OFF + ")"); + + "STATE_OFF(" + STATE_OFF + "), " + + "STATE_UNDEFINED(" + STATE_UNDEFINED + ")"); } return this; @@ -1036,7 +1038,7 @@ public final class SampleDataClass implements Parcelable { * @see #SampleDataClass */ @DataClass.Generated.Member - public SampleDataClass setStringRes(@StringRes int value) { + public @NonNull SampleDataClass setStringRes(@StringRes int value) { mStringRes = value; AnnotationValidations.validate( StringRes.class, null, mStringRes); @@ -1051,7 +1053,7 @@ public final class SampleDataClass implements Parcelable { * @see AnnotationValidations#validate(Class, Size, int, String, int, String, int) */ @DataClass.Generated.Member - public SampleDataClass setDayOfWeek(@android.annotation.IntRange(from = 0, to = 6) int value) { + public @NonNull SampleDataClass setDayOfWeek(@android.annotation.IntRange(from = 0, to = 6) int value) { mDayOfWeek = value; AnnotationValidations.validate( android.annotation.IntRange.class, null, mDayOfWeek, @@ -1070,7 +1072,7 @@ public final class SampleDataClass implements Parcelable { * @see AnnotationValidations#validate(Class, Size, int, String, int) */ @DataClass.Generated.Member - public SampleDataClass setCoords(@Size(2) @NonNull @FloatRange(from = 0f) float... value) { + public @NonNull SampleDataClass setCoords(@Size(2) @NonNull @FloatRange(from = 0f) float... value) { mCoords = value; AnnotationValidations.validate( Size.class, null, mCoords.length, @@ -1372,14 +1374,14 @@ public final class SampleDataClass implements Parcelable { | FLAG_AUGMENTED_REQUEST); this.mState = state; - if (!(mState == STATE_UNDEFINED) - && !(mState == STATE_ON) - && !(mState == STATE_OFF)) { + if (!(mState == STATE_ON) + && !(mState == STATE_OFF) + && !(mState == STATE_UNDEFINED)) { throw new java.lang.IllegalArgumentException( "state was " + mState + " but must be one of: " - + "STATE_UNDEFINED(" + STATE_UNDEFINED + "), " + "STATE_ON(" + STATE_ON + "), " - + "STATE_OFF(" + STATE_OFF + ")"); + + "STATE_OFF(" + STATE_OFF + "), " + + "STATE_UNDEFINED(" + STATE_UNDEFINED + ")"); } this.charSeq = _charSeq; @@ -1872,10 +1874,10 @@ public final class SampleDataClass implements Parcelable { } @DataClass.Generated( - time = 1601950879293L, - codegenVersion = "1.0.16", + time = 1603836845952L, + codegenVersion = "1.0.18", sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleDataClass.java", - inputSignatures = "public static final java.lang.String STATE_NAME_UNDEFINED\npublic static final java.lang.String STATE_NAME_ON\npublic static final java.lang.String STATE_NAME_OFF\npublic static final int STATE_UNDEFINED\npublic static final int STATE_ON\npublic static final int STATE_OFF\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_AUGMENTED_REQUEST\nprivate int mNum\nprivate int mNum2\nprivate int mNum4\nprivate @android.annotation.Nullable java.lang.String mName\nprivate @android.annotation.NonNull java.lang.String mName2\nprivate @android.annotation.NonNull java.lang.String mName4\nprivate @android.annotation.Nullable android.view.accessibility.AccessibilityNodeInfo mOtherParcelable\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.codegentest.MyDateParcelling.class) @android.annotation.NonNull java.util.Date mDate\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForPattern.class) @android.annotation.NonNull java.util.regex.Pattern mPattern\nprivate @android.annotation.NonNull java.util.List<android.net.LinkAddress> mLinkAddresses2\nprivate @com.android.internal.util.DataClass.PluralOf(\"linkAddress\") @android.annotation.NonNull java.util.ArrayList<android.net.LinkAddress> mLinkAddresses\nprivate @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses4\nprivate @com.android.codegentest.SampleDataClass.StateName @android.annotation.NonNull java.lang.String mStateName\nprivate @com.android.codegentest.SampleDataClass.RequestFlags int mFlags\nprivate @com.android.codegentest.SampleDataClass.State int mState\npublic @android.annotation.NonNull java.lang.CharSequence charSeq\nprivate final @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses5\nprivate transient android.net.LinkAddress[] mLinkAddresses6\ntransient int[] mTmpStorage\nprivate @android.annotation.StringRes int mStringRes\nprivate @android.annotation.IntRange(from=0L, to=6L) int mDayOfWeek\nprivate @android.annotation.Size(2L) @android.annotation.NonNull @com.android.internal.util.DataClass.Each @android.annotation.FloatRange(from=0.0) float[] mCoords\nprivate static java.lang.String defaultName4()\nprivate int[] lazyInitTmpStorage()\npublic android.net.LinkAddress[] getLinkAddresses4()\nprivate boolean patternEquals(java.util.regex.Pattern)\nprivate int patternHashCode()\nprivate void onConstructed()\npublic void dump(java.io.PrintWriter)\nclass SampleDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genConstructor=true, genEqualsHashCode=true, genToString=true, genForEachField=true, genSetters=true)") + inputSignatures = "public static final java.lang.String STATE_NAME_UNDEFINED\npublic static final java.lang.String STATE_NAME_ON\npublic static final java.lang.String STATE_NAME_OFF\npublic static final int STATE_ON\npublic static final int STATE_OFF\npublic static final int STATE_UNDEFINED\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_AUGMENTED_REQUEST\nprivate int mNum\nprivate int mNum2\nprivate int mNum4\nprivate @android.annotation.Nullable java.lang.String mName\nprivate @android.annotation.NonNull java.lang.String mName2\nprivate @android.annotation.NonNull java.lang.String mName4\nprivate @android.annotation.Nullable android.view.accessibility.AccessibilityNodeInfo mOtherParcelable\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.codegentest.MyDateParcelling.class) @android.annotation.NonNull java.util.Date mDate\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForPattern.class) @android.annotation.NonNull java.util.regex.Pattern mPattern\nprivate @android.annotation.NonNull java.util.List<android.net.LinkAddress> mLinkAddresses2\nprivate @com.android.internal.util.DataClass.PluralOf(\"linkAddress\") @android.annotation.NonNull java.util.ArrayList<android.net.LinkAddress> mLinkAddresses\nprivate @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses4\nprivate @com.android.codegentest.SampleDataClass.StateName @android.annotation.NonNull java.lang.String mStateName\nprivate @com.android.codegentest.SampleDataClass.RequestFlags int mFlags\nprivate @com.android.codegentest.SampleDataClass.State int mState\npublic @android.annotation.NonNull java.lang.CharSequence charSeq\nprivate final @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses5\nprivate transient android.net.LinkAddress[] mLinkAddresses6\ntransient int[] mTmpStorage\nprivate @android.annotation.StringRes int mStringRes\nprivate @android.annotation.IntRange(from=0L, to=6L) int mDayOfWeek\nprivate @android.annotation.Size(2L) @android.annotation.NonNull @com.android.internal.util.DataClass.Each @android.annotation.FloatRange(from=0.0) float[] mCoords\nprivate static java.lang.String defaultName4()\nprivate int[] lazyInitTmpStorage()\npublic android.net.LinkAddress[] getLinkAddresses4()\nprivate boolean patternEquals(java.util.regex.Pattern)\nprivate int patternHashCode()\nprivate void onConstructed()\npublic void dump(java.io.PrintWriter)\nclass SampleDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genConstructor=true, genEqualsHashCode=true, genToString=true, genForEachField=true, genSetters=true)") @Deprecated private void __metadata() {} diff --git a/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java b/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java index 735f7047af9f..e3567044d361 100644 --- a/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java +++ b/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java @@ -85,7 +85,7 @@ public class SampleWithCustomBuilder implements Parcelable { - // Code below generated by codegen v1.0.16. + // Code below generated by codegen v1.0.18. // // DO NOT MODIFY! // CHECKSTYLE:OFF Generated code @@ -253,8 +253,8 @@ public class SampleWithCustomBuilder implements Parcelable { } @DataClass.Generated( - time = 1601950880290L, - codegenVersion = "1.0.16", + time = 1603836846970L, + codegenVersion = "1.0.18", sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java", inputSignatures = " long delayAmount\n @android.annotation.NonNull java.util.concurrent.TimeUnit delayUnit\n long creationTimestamp\nprivate static java.util.concurrent.TimeUnit unparcelDelayUnit(android.os.Parcel)\nprivate void parcelDelayUnit(android.os.Parcel,int)\nclass SampleWithCustomBuilder extends java.lang.Object implements [android.os.Parcelable]\nabstract com.android.codegentest.SampleWithCustomBuilder.Builder setDelayAmount(long)\npublic abstract com.android.codegentest.SampleWithCustomBuilder.Builder setDelayUnit(java.util.concurrent.TimeUnit)\npublic com.android.codegentest.SampleWithCustomBuilder.Builder setDelay(long,java.util.concurrent.TimeUnit)\nclass BaseBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=true, genAidl=false, genToString=true)\nabstract com.android.codegentest.SampleWithCustomBuilder.Builder setDelayAmount(long)\npublic abstract com.android.codegentest.SampleWithCustomBuilder.Builder setDelayUnit(java.util.concurrent.TimeUnit)\npublic com.android.codegentest.SampleWithCustomBuilder.Builder setDelay(long,java.util.concurrent.TimeUnit)\nclass BaseBuilder extends java.lang.Object implements []") @Deprecated diff --git a/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java b/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java index 51601213acce..07ec31ddc5e6 100644 --- a/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java +++ b/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java @@ -36,7 +36,7 @@ public class SampleWithNestedDataClasses { - // Code below generated by codegen v1.0.16. + // Code below generated by codegen v1.0.18. // // DO NOT MODIFY! // CHECKSTYLE:OFF Generated code @@ -135,8 +135,8 @@ public class SampleWithNestedDataClasses { }; @DataClass.Generated( - time = 1601950885147L, - codegenVersion = "1.0.16", + time = 1603836851627L, + codegenVersion = "1.0.18", sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java", inputSignatures = " @android.annotation.NonNull java.lang.String mBar\nclass NestedDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true)") @Deprecated @@ -160,7 +160,7 @@ public class SampleWithNestedDataClasses { - // Code below generated by codegen v1.0.16. + // Code below generated by codegen v1.0.18. // // DO NOT MODIFY! // CHECKSTYLE:OFF Generated code @@ -259,8 +259,8 @@ public class SampleWithNestedDataClasses { }; @DataClass.Generated( - time = 1601950885156L, - codegenVersion = "1.0.16", + time = 1603836851635L, + codegenVersion = "1.0.18", sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java", inputSignatures = " @android.annotation.NonNull long mBaz2\nclass NestedDataClass3 extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true)") @Deprecated @@ -274,7 +274,7 @@ public class SampleWithNestedDataClasses { - // Code below generated by codegen v1.0.16. + // Code below generated by codegen v1.0.18. // // DO NOT MODIFY! // CHECKSTYLE:OFF Generated code @@ -373,8 +373,8 @@ public class SampleWithNestedDataClasses { }; @DataClass.Generated( - time = 1601950885161L, - codegenVersion = "1.0.16", + time = 1603836851640L, + codegenVersion = "1.0.18", sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java", inputSignatures = " @android.annotation.NonNull java.lang.String mBaz\nclass NestedDataClass2 extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true)") @Deprecated diff --git a/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java b/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java index 5417c11c8fca..5cbc6b30d1fc 100644 --- a/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java +++ b/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java @@ -59,7 +59,7 @@ public class StaleDataclassDetectorFalsePositivesTest { - // Code below generated by codegen v1.0.16. + // Code below generated by codegen v1.0.18. // // DO NOT MODIFY! // CHECKSTYLE:OFF Generated code @@ -78,14 +78,14 @@ public class StaleDataclassDetectorFalsePositivesTest { } @DataClass.Generated.Member - public StaleDataclassDetectorFalsePositivesTest setUsesWildcards(@NonNull List<Set<?>> value) { + public @NonNull StaleDataclassDetectorFalsePositivesTest setUsesWildcards(@NonNull List<Set<?>> value) { mUsesWildcards = value; return this; } @DataClass.Generated( - time = 1601950884160L, - codegenVersion = "1.0.16", + time = 1603836850677L, + codegenVersion = "1.0.18", sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java", inputSignatures = "private @android.annotation.Nullable java.util.List<java.util.Set<?>> mUsesWildcards\npublic @android.annotation.NonNull java.lang.String someMethod(int)\nclass StaleDataclassDetectorFalsePositivesTest extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=false)") @Deprecated diff --git a/tests/Input/AndroidManifest.xml b/tests/Input/AndroidManifest.xml index 4195df72864c..20f564e80b3d 100644 --- a/tests/Input/AndroidManifest.xml +++ b/tests/Input/AndroidManifest.xml @@ -27,7 +27,6 @@ android:process=":externalProcess"> </activity> - </application> <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" android:targetPackage="com.android.test.input" diff --git a/tests/TaskOrganizerTest/AndroidManifest.xml b/tests/TaskOrganizerTest/AndroidManifest.xml index f0ba71a47d7e..451a55f13d8f 100644 --- a/tests/TaskOrganizerTest/AndroidManifest.xml +++ b/tests/TaskOrganizerTest/AndroidManifest.xml @@ -14,7 +14,7 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.test.taskembed"> <uses-permission android:name="android.permission.CHANGE_CONFIGURATION"/> - <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS"/> + <uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS"/> <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/> <application> <service android:name=".TaskOrganizerPipTest" diff --git a/tests/net/AndroidManifest.xml b/tests/net/AndroidManifest.xml index 009f817af407..6bed5a80d129 100644 --- a/tests/net/AndroidManifest.xml +++ b/tests/net/AndroidManifest.xml @@ -42,7 +42,7 @@ <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" /> <uses-permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD" /> <uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT" /> - <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" /> + <uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS" /> <uses-permission android:name="android.permission.INSTALL_PACKAGES" /> <uses-permission android:name="android.permission.NETWORK_STACK" /> <uses-permission android:name="android.permission.OBSERVE_NETWORK_POLICY" /> diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java index e1693129892f..11a83ebf6dd7 100644 --- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java +++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java @@ -30,6 +30,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID; +import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE; import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY; import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P; @@ -359,6 +360,33 @@ public class NetworkCapabilitiesTest { } @Test + public void testOemPrivate() { + NetworkCapabilities nc = new NetworkCapabilities(); + // By default OEM_PRIVATE is neither in the unwanted or required lists and the network is + // not restricted. + assertFalse(nc.hasUnwantedCapability(NET_CAPABILITY_OEM_PRIVATE)); + assertFalse(nc.hasCapability(NET_CAPABILITY_OEM_PRIVATE)); + nc.maybeMarkCapabilitiesRestricted(); + assertTrue(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)); + + // Adding OEM_PRIVATE to capability list should make network restricted. + nc.addCapability(NET_CAPABILITY_OEM_PRIVATE); + nc.addCapability(NET_CAPABILITY_INTERNET); // Combine with unrestricted capability. + nc.maybeMarkCapabilitiesRestricted(); + assertTrue(nc.hasCapability(NET_CAPABILITY_OEM_PRIVATE)); + assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)); + + // Now let's make request for OEM_PRIVATE network. + NetworkCapabilities nr = new NetworkCapabilities(); + nr.addCapability(NET_CAPABILITY_OEM_PRIVATE); + nr.maybeMarkCapabilitiesRestricted(); + assertTrue(nr.satisfiedByNetworkCapabilities(nc)); + + // Request fails for network with the default capabilities. + assertFalse(nr.satisfiedByNetworkCapabilities(new NetworkCapabilities())); + } + + @Test public void testUnwantedCapabilities() { NetworkCapabilities network = new NetworkCapabilities(); diff --git a/tools/codegen/src/com/android/codegen/Debug.kt b/tools/codegen/src/com/android/codegen/Debug.kt new file mode 100644 index 000000000000..de3184468540 --- /dev/null +++ b/tools/codegen/src/com/android/codegen/Debug.kt @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.codegen + +import com.github.javaparser.ast.Node + +fun Node.dump(indent: String = ""): String { + return buildString { + append(indent) + appendln(dumpOneLineNoChildren()) + childNodes.forEach { child -> + append(child.dump(indent + " ")) + } + } +} + +private fun Node.dumpOneLineNoChildren(): String { + val node = this + return buildString { + append(node::class.java.simpleName) + if (childNodes.isEmpty()) { + append(": ").append(node.toString()) + } + } +} diff --git a/tools/codegen/src/com/android/codegen/Generators.kt b/tools/codegen/src/com/android/codegen/Generators.kt index 6e1ab5944eb6..6c6d011cfede 100644 --- a/tools/codegen/src/com/android/codegen/Generators.kt +++ b/tools/codegen/src/com/android/codegen/Generators.kt @@ -16,10 +16,7 @@ import java.io.File fun ClassPrinter.generateConstDefs() { val consts = classAst.fields.filter { it.isStatic && it.isFinal && it.variables.all { variable -> - val initializer = variable.initializer.orElse(null) - val isLiteral = initializer is LiteralExpr - || (initializer is UnaryExpr && initializer.expression is LiteralExpr) - isLiteral && variable.type.asString() in listOf("int", "String") + variable.type.asString() in listOf("int", "String") } && it.annotations.none { it.nameAsString == DataClassSuppressConstDefs } }.flatMap { field -> field.variables.map { it to field } } val intConsts = consts.filter { it.first.type.asString() == "int" } diff --git a/tools/codegen/src/com/android/codegen/SharedConstants.kt b/tools/codegen/src/com/android/codegen/SharedConstants.kt index 785aa9107f90..ca658a972209 100644 --- a/tools/codegen/src/com/android/codegen/SharedConstants.kt +++ b/tools/codegen/src/com/android/codegen/SharedConstants.kt @@ -1,7 +1,7 @@ package com.android.codegen const val CODEGEN_NAME = "codegen" -const val CODEGEN_VERSION = "1.0.17" +const val CODEGEN_VERSION = "1.0.18" const val CANONICAL_BUILDER_CLASS = "Builder" const val BASE_BUILDER_CLASS = "BaseBuilder" diff --git a/tools/hiddenapi/generate_hiddenapi_lists.py b/tools/hiddenapi/generate_hiddenapi_lists.py index e4b96b1d4f5f..28ff606d0381 100755 --- a/tools/hiddenapi/generate_hiddenapi_lists.py +++ b/tools/hiddenapi/generate_hiddenapi_lists.py @@ -188,11 +188,10 @@ class FlagsDict: def _check_entries_set(self, keys_subset, source): assert isinstance(keys_subset, set) assert keys_subset.issubset(self._dict_keyset), ( - "Error processing: {}\n" - "The following entries were unexpected:\n" + "Error: {} specifies signatures not present in code:\n" "{}" "Please visit go/hiddenapi for more information.").format( - source, "".join(map(lambda x: " " + str(x), keys_subset - self._dict_keyset))) + source, "".join(map(lambda x: " " + str(x) + "\n", keys_subset - self._dict_keyset))) def _check_flags_set(self, flags_subset, source): assert isinstance(flags_subset, set) diff --git a/wifi/Android.bp b/wifi/Android.bp index 3040041038cb..52e3840c126e 100644 --- a/wifi/Android.bp +++ b/wifi/Android.bp @@ -75,25 +75,34 @@ test_access_hidden_api_whitelist = [ "//external/sl4a:__subpackages__", ] -// wifi-service needs pre-jarjared version of framework-wifi so it can reference copied utility -// classes before they are renamed. -java_library { - name: "framework-wifi-pre-jarjar", +// defaults shared between `framework-wifi` & `framework-wifi-pre-jarjar` +// java_sdk_library `framework-wifi` needs sources to generate stubs, so it cannot reuse +// `framework-wifi-pre-jarjar` +java_defaults { + name: "framework-wifi-defaults", defaults: ["wifi-module-sdk-version-defaults"], - sdk_version: "module_current", static_libs: [ "framework-wifi-util-lib", "android.hardware.wifi-V1.0-java-constants", + "modules-utils-build", ], libs: [ - "framework-annotations-lib", "unsupportedappusage", // for android.compat.annotation.UnsupportedAppUsage ], srcs: [ ":framework-wifi-updatable-sources", ":framework-wifi-util-lib-aidls", ], - // java_api_finder must accompany `srcs` +} + +// wifi-service needs pre-jarjared version of framework-wifi so it can reference copied utility +// classes before they are renamed. +java_library { + name: "framework-wifi-pre-jarjar", + defaults: ["framework-wifi-defaults"], + sdk_version: "module_current", + libs: ["framework-annotations-lib"], + // java_api_finder must accompany `srcs` (`srcs` defined in `framework-wifi-defaults`) plugins: ["java_api_finder"], installable: false, visibility: [ @@ -107,18 +116,7 @@ java_sdk_library { name: "framework-wifi", defaults: [ "framework-module-defaults", - "wifi-module-sdk-version-defaults", - ], - static_libs: [ - "framework-wifi-util-lib", - "android.hardware.wifi-V1.0-java-constants", - ], - libs: [ - "unsupportedappusage", // for android.compat.annotation.UnsupportedAppUsage - ], - srcs: [ - ":framework-wifi-updatable-sources", - ":framework-wifi-util-lib-aidls", + "framework-wifi-defaults", ], jarjar_rules: ":wifi-jarjar-rules", diff --git a/wifi/api/system-current.txt b/wifi/api/system-current.txt index da5888b6adee..5dc5dfc02bce 100644 --- a/wifi/api/system-current.txt +++ b/wifi/api/system-current.txt @@ -252,8 +252,10 @@ package android.net.wifi { public final class SoftApConfiguration implements android.os.Parcelable { method @NonNull public java.util.List<android.net.MacAddress> getAllowedClientList(); method public int getBand(); + method @NonNull public int[] getBands(); method @NonNull public java.util.List<android.net.MacAddress> getBlockedClientList(); method public int getChannel(); + method @NonNull public android.util.SparseIntArray getChannels(); method public int getMacRandomizationSetting(); method public int getMaxNumberOfClients(); method public long getShutdownTimeoutMillis(); @@ -275,9 +277,11 @@ package android.net.wifi { method @NonNull public android.net.wifi.SoftApConfiguration.Builder setAllowedClientList(@NonNull java.util.List<android.net.MacAddress>); method @NonNull public android.net.wifi.SoftApConfiguration.Builder setAutoShutdownEnabled(boolean); method @NonNull public android.net.wifi.SoftApConfiguration.Builder setBand(int); + method @NonNull public android.net.wifi.SoftApConfiguration.Builder setBands(@NonNull int[]); method @NonNull public android.net.wifi.SoftApConfiguration.Builder setBlockedClientList(@NonNull java.util.List<android.net.MacAddress>); method @NonNull public android.net.wifi.SoftApConfiguration.Builder setBssid(@Nullable android.net.MacAddress); method @NonNull public android.net.wifi.SoftApConfiguration.Builder setChannel(int, int); + method @NonNull public android.net.wifi.SoftApConfiguration.Builder setChannels(@NonNull android.util.SparseIntArray); method @NonNull public android.net.wifi.SoftApConfiguration.Builder setClientControlByUserEnabled(boolean); method @NonNull public android.net.wifi.SoftApConfiguration.Builder setHiddenSsid(boolean); method @NonNull public android.net.wifi.SoftApConfiguration.Builder setMacRandomizationSetting(int); diff --git a/wifi/jarjar-rules.txt b/wifi/jarjar-rules.txt index eef08b54f570..863678a80cee 100644 --- a/wifi/jarjar-rules.txt +++ b/wifi/jarjar-rules.txt @@ -123,3 +123,4 @@ rule com.android.internal.util.Preconditions* com.android.wifi.x.@0 rule com.android.internal.util.Protocol* com.android.wifi.x.@0 rule com.android.net.module.util.** com.android.wifi.x.@0 +rule com.android.modules.utils.** com.android.wifi.x.@0 diff --git a/wifi/java/android/net/wifi/SoftApCapability.java b/wifi/java/android/net/wifi/SoftApCapability.java index cf54f26fc5e4..6bd4211d8214 100644 --- a/wifi/java/android/net/wifi/SoftApCapability.java +++ b/wifi/java/android/net/wifi/SoftApCapability.java @@ -21,10 +21,11 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.net.wifi.SoftApConfiguration.BandType; -import android.net.wifi.util.SdkLevelUtil; import android.os.Parcel; import android.os.Parcelable; +import com.android.modules.utils.build.SdkLevel; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Arrays; @@ -176,7 +177,7 @@ public final class SoftApCapability implements Parcelable { */ @NonNull public int[] getSupportedChannelList(@BandType int band) { - if (!SdkLevelUtil.isAtLeastS()) { + if (!SdkLevel.isAtLeastS()) { throw new UnsupportedOperationException(); } switch (band) { diff --git a/wifi/java/android/net/wifi/SoftApConfiguration.java b/wifi/java/android/net/wifi/SoftApConfiguration.java index 2649b66c703f..2c53daaf55a7 100644 --- a/wifi/java/android/net/wifi/SoftApConfiguration.java +++ b/wifi/java/android/net/wifi/SoftApConfiguration.java @@ -22,14 +22,15 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.net.MacAddress; -import android.net.wifi.util.SdkLevelUtil; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; import android.util.Log; +import android.util.SparseIntArray; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; +import com.android.modules.utils.build.SdkLevel; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -167,16 +168,12 @@ public final class SoftApConfiguration implements Parcelable { private final boolean mHiddenSsid; /** - * The operating band of the AP. - * One or combination of the following band type: - * {@link #BAND_2GHZ}, {@link #BAND_5GHZ}, {@link #BAND_6GHZ}. - */ - private final @BandType int mBand; - - /** - * The operating channel of the AP. + * The operating channels of the dual APs. + * + * The SparseIntArray that consists the band and the channel of matching the band. */ - private final int mChannel; + @NonNull + private final SparseIntArray mChannels; /** * The maximim allowed number of clients that can associate to the AP. @@ -280,7 +277,7 @@ public final class SoftApConfiguration implements Parcelable { /** Private constructor for Builder and Parcelable implementation. */ private SoftApConfiguration(@Nullable String ssid, @Nullable MacAddress bssid, - @Nullable String passphrase, boolean hiddenSsid, @BandType int band, int channel, + @Nullable String passphrase, boolean hiddenSsid, @NonNull SparseIntArray channels, @SecurityType int securityType, int maxNumberOfClients, boolean shutdownTimeoutEnabled, long shutdownTimeoutMillis, boolean clientControlByUser, @NonNull List<MacAddress> blockedList, @NonNull List<MacAddress> allowedList, @@ -289,8 +286,12 @@ public final class SoftApConfiguration implements Parcelable { mBssid = bssid; mPassphrase = passphrase; mHiddenSsid = hiddenSsid; - mBand = band; - mChannel = channel; + if (channels.size() != 0) { + mChannels = channels.clone(); + } else { + mChannels = new SparseIntArray(1); + mChannels.put(BAND_2GHZ, 0); + } mSecurityType = securityType; mMaxNumberOfClients = maxNumberOfClients; mAutoShutdownEnabled = shutdownTimeoutEnabled; @@ -314,8 +315,7 @@ public final class SoftApConfiguration implements Parcelable { && Objects.equals(mBssid, other.mBssid) && Objects.equals(mPassphrase, other.mPassphrase) && mHiddenSsid == other.mHiddenSsid - && mBand == other.mBand - && mChannel == other.mChannel + && mChannels.toString().equals(other.mChannels.toString()) && mSecurityType == other.mSecurityType && mMaxNumberOfClients == other.mMaxNumberOfClients && mAutoShutdownEnabled == other.mAutoShutdownEnabled @@ -329,7 +329,7 @@ public final class SoftApConfiguration implements Parcelable { @Override public int hashCode() { return Objects.hash(mSsid, mBssid, mPassphrase, mHiddenSsid, - mBand, mChannel, mSecurityType, mMaxNumberOfClients, mAutoShutdownEnabled, + mChannels.toString(), mSecurityType, mMaxNumberOfClients, mAutoShutdownEnabled, mShutdownTimeoutMillis, mClientControlByUser, mBlockedClientList, mAllowedClientList, mMacRandomizationSetting); } @@ -337,21 +337,20 @@ public final class SoftApConfiguration implements Parcelable { @Override public String toString() { StringBuilder sbuf = new StringBuilder(); - sbuf.append("ssid=").append(mSsid); - if (mBssid != null) sbuf.append(" \n bssid=").append(mBssid.toString()); - sbuf.append(" \n Passphrase =").append( + sbuf.append("ssid = ").append(mSsid); + if (mBssid != null) sbuf.append(" \n bssid = ").append(mBssid.toString()); + sbuf.append(" \n Passphrase = ").append( TextUtils.isEmpty(mPassphrase) ? "<empty>" : "<non-empty>"); - sbuf.append(" \n HiddenSsid =").append(mHiddenSsid); - sbuf.append(" \n Band =").append(mBand); - sbuf.append(" \n Channel =").append(mChannel); - sbuf.append(" \n SecurityType=").append(getSecurityType()); - sbuf.append(" \n MaxClient=").append(mMaxNumberOfClients); - sbuf.append(" \n AutoShutdownEnabled=").append(mAutoShutdownEnabled); - sbuf.append(" \n ShutdownTimeoutMillis=").append(mShutdownTimeoutMillis); - sbuf.append(" \n ClientControlByUser=").append(mClientControlByUser); - sbuf.append(" \n BlockedClientList=").append(mBlockedClientList); - sbuf.append(" \n AllowedClientList=").append(mAllowedClientList); - sbuf.append(" \n MacRandomizationSetting=").append(mMacRandomizationSetting); + sbuf.append(" \n HiddenSsid = ").append(mHiddenSsid); + sbuf.append(" \n Channels = ").append(mChannels); + sbuf.append(" \n SecurityType = ").append(getSecurityType()); + sbuf.append(" \n MaxClient = ").append(mMaxNumberOfClients); + sbuf.append(" \n AutoShutdownEnabled = ").append(mAutoShutdownEnabled); + sbuf.append(" \n ShutdownTimeoutMillis = ").append(mShutdownTimeoutMillis); + sbuf.append(" \n ClientControlByUser = ").append(mClientControlByUser); + sbuf.append(" \n BlockedClientList = ").append(mBlockedClientList); + sbuf.append(" \n AllowedClientList= ").append(mAllowedClientList); + sbuf.append(" \n MacRandomizationSetting = ").append(mMacRandomizationSetting); return sbuf.toString(); } @@ -361,8 +360,7 @@ public final class SoftApConfiguration implements Parcelable { dest.writeParcelable(mBssid, flags); dest.writeString(mPassphrase); dest.writeBoolean(mHiddenSsid); - dest.writeInt(mBand); - dest.writeInt(mChannel); + writeSparseIntArray(dest, mChannels); dest.writeInt(mSecurityType); dest.writeInt(mMaxNumberOfClients); dest.writeBoolean(mAutoShutdownEnabled); @@ -373,6 +371,42 @@ public final class SoftApConfiguration implements Parcelable { dest.writeInt(mMacRandomizationSetting); } + /* Reference from frameworks/base/core/java/android/os/Parcel.java */ + private static void writeSparseIntArray(@NonNull Parcel dest, + @Nullable SparseIntArray val) { + if (val == null) { + dest.writeInt(-1); + return; + } + int n = val.size(); + dest.writeInt(n); + int i = 0; + while (i < n) { + dest.writeInt(val.keyAt(i)); + dest.writeInt(val.valueAt(i)); + i++; + } + } + + + /* Reference from frameworks/base/core/java/android/os/Parcel.java */ + @NonNull + private static SparseIntArray readSparseIntArray(@NonNull Parcel in) { + int n = in.readInt(); + if (n < 0) { + return new SparseIntArray(); + } + SparseIntArray sa = new SparseIntArray(n); + while (n > 0) { + int key = in.readInt(); + int value = in.readInt(); + sa.append(key, value); + n--; + } + return sa; + } + + @Override public int describeContents() { return 0; @@ -385,7 +419,7 @@ public final class SoftApConfiguration implements Parcelable { return new SoftApConfiguration( in.readString(), in.readParcelable(MacAddress.class.getClassLoader()), - in.readString(), in.readBoolean(), in.readInt(), in.readInt(), in.readInt(), + in.readString(), in.readBoolean(), readSparseIntArray(in), in.readInt(), in.readInt(), in.readBoolean(), in.readLong(), in.readBoolean(), in.createTypedArrayList(MacAddress.CREATOR), in.createTypedArrayList(MacAddress.CREATOR), in.readInt()); @@ -399,7 +433,7 @@ public final class SoftApConfiguration implements Parcelable { /** * Return String set to be the SSID for the AP. - * {@link Builder#setSsid(String)}. + * See also {@link Builder#setSsid(String)}. */ @Nullable public String getSsid() { @@ -408,7 +442,7 @@ public final class SoftApConfiguration implements Parcelable { /** * Returns MAC address set to be BSSID for the AP. - * {@link Builder#setBssid(MacAddress)}. + * See also {@link Builder#setBssid(MacAddress)}. */ @Nullable public MacAddress getBssid() { @@ -417,7 +451,7 @@ public final class SoftApConfiguration implements Parcelable { /** * Returns String set to be passphrase for current AP. - * {@link Builder#setPassphrase(String, int)}. + * See also {@link Builder#setPassphrase(String, int)}. */ @Nullable public String getPassphrase() { @@ -427,7 +461,7 @@ public final class SoftApConfiguration implements Parcelable { /** * Returns Boolean set to be indicate hidden (true: doesn't broadcast its SSID) or * not (false: broadcasts its SSID) for the AP. - * {@link Builder#setHiddenSsid(boolean)}. + * See also {@link Builder#setHiddenSsid(boolean)}. */ public boolean isHiddenSsid() { return mHiddenSsid; @@ -436,27 +470,75 @@ public final class SoftApConfiguration implements Parcelable { /** * Returns band type set to be the band for the AP. * - * One or combination of the following band type: - * {@link #BAND_2GHZ}, {@link #BAND_5GHZ}, {@link #BAND_6GHZ}. + * One or combination of {@code BAND_}, for instance + * {@link #BAND_2GHZ}, {@link #BAND_5GHZ}, or {@code BAND_2GHZ | BAND_5GHZ}. + * + * Note: Returns the lowest band when more than one band is set. + * Use {@link #getBands()} to get dual bands setting. * - * {@link Builder#setBand(int)}. + * See also {@link Builder#setBand(int)}. * * @hide */ @SystemApi public @BandType int getBand() { - return mBand; + return mChannels.keyAt(0); + } + + /** + * Returns a sorted array in ascending order that consists of the configured band types + * for the APs. + * + * The band type is one or combination of {@code BAND_}, for instance + * {@link #BAND_2GHZ}, {@link #BAND_5GHZ}, or {@code BAND_2GHZ | BAND_5GHZ}. + * + * Note: return array may only include one band when current setting is single AP mode. + * See also {@link Builder#setBands(int[])}. + * + * @hide + */ + @SystemApi + public @NonNull int[] getBands() { + if (!SdkLevel.isAtLeastS()) { + throw new UnsupportedOperationException(); + } + int[] bands = new int[mChannels.size()]; + for (int i = 0; i < bands.length; i++) { + bands[i] = mChannels.keyAt(i); + } + return bands; } /** * Returns Integer set to be the channel for the AP. - * {@link Builder#setChannel(int)}. + * + * Note: Returns the channel which associated to the lowest band if more than one channel + * is set. Use {@link Builder#getChannels()} to get dual channel setting. + * See also {@link Builder#setChannel(int, int)}. * * @hide */ @SystemApi public int getChannel() { - return mChannel; + return mChannels.valueAt(0); + } + + + /** + * Returns SparseIntArray (key: {@code BandType} , value: channel) that consists of + * the configured bands and channels for the AP(s). + * + * Note: return array may only include one channel when current setting is single AP mode. + * See also {@link Builder#setChannels(SparseIntArray)}. + * + * @hide + */ + @SystemApi + public @NonNull SparseIntArray getChannels() { + if (!SdkLevel.isAtLeastS()) { + throw new UnsupportedOperationException(); + } + return mChannels; } /** @@ -474,7 +556,7 @@ public final class SoftApConfiguration implements Parcelable { /** * Returns the maximum number of clients that can associate to the AP. - * {@link Builder#setMaxNumberOfClients(int)}. + * See also {@link Builder#setMaxNumberOfClients(int)}. * * @hide */ @@ -486,7 +568,7 @@ public final class SoftApConfiguration implements Parcelable { /** * Returns whether auto shutdown is enabled or not. * The Soft AP will shutdown when there are no devices associated to it for - * the timeout duration. See {@link Builder#setAutoShutdownEnabled(boolean)}. + * the timeout duration. See also {@link Builder#setAutoShutdownEnabled(boolean)}. * * @hide */ @@ -498,7 +580,7 @@ public final class SoftApConfiguration implements Parcelable { /** * Returns the shutdown timeout in milliseconds. * The Soft AP will shutdown when there are no devices associated to it for - * the timeout duration. See {@link Builder#setShutdownTimeoutMillis(long)}. + * the timeout duration. See also {@link Builder#setShutdownTimeoutMillis(long)}. * * @hide */ @@ -510,7 +592,7 @@ public final class SoftApConfiguration implements Parcelable { /** * Returns a flag indicating whether clients need to be pre-approved by the user. * (true: authorization required) or not (false: not required). - * {@link Builder#setClientControlByUserEnabled(Boolean)}. + * See also {@link Builder#setClientControlByUserEnabled(Boolean)}. * * @hide */ @@ -546,14 +628,14 @@ public final class SoftApConfiguration implements Parcelable { /** * Returns the level of MAC randomization for the AP BSSID. - * {@link Builder#setMacRandomizationSetting(int)}. + * See also {@link Builder#setMacRandomizationSetting(int)}. * * @hide */ @SystemApi @MacRandomizationSetting public int getMacRandomizationSetting() { - if (!SdkLevelUtil.isAtLeastS()) { + if (!SdkLevel.isAtLeastS()) { throw new UnsupportedOperationException(); } return mMacRandomizationSetting; @@ -578,7 +660,7 @@ public final class SoftApConfiguration implements Parcelable { wifiConfig.SSID = mSsid; wifiConfig.preSharedKey = mPassphrase; wifiConfig.hiddenSSID = mHiddenSsid; - wifiConfig.apChannel = mChannel; + wifiConfig.apChannel = getChannel(); switch (mSecurityType) { case SECURITY_TYPE_OPEN: wifiConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); @@ -592,7 +674,7 @@ public final class SoftApConfiguration implements Parcelable { return null; } - switch (mBand) { + switch (getBand()) { case BAND_2GHZ: wifiConfig.apBand = WifiConfiguration.AP_BAND_2GHZ; break; @@ -606,7 +688,7 @@ public final class SoftApConfiguration implements Parcelable { wifiConfig.apBand = WifiConfiguration.AP_BAND_ANY; break; default: - Log.e(TAG, "Convert fail, unsupported band setting :" + mBand); + Log.e(TAG, "Convert fail, unsupported band setting :" + getBand()); return null; } return wifiConfig; @@ -627,8 +709,7 @@ public final class SoftApConfiguration implements Parcelable { private MacAddress mBssid; private String mPassphrase; private boolean mHiddenSsid; - private int mBand; - private int mChannel; + private SparseIntArray mChannels; private int mMaxNumberOfClients; private int mSecurityType; private boolean mAutoShutdownEnabled; @@ -646,8 +727,8 @@ public final class SoftApConfiguration implements Parcelable { mBssid = null; mPassphrase = null; mHiddenSsid = false; - mBand = BAND_2GHZ; - mChannel = 0; + mChannels = new SparseIntArray(1); + mChannels.put(BAND_2GHZ, 0); mMaxNumberOfClients = 0; mSecurityType = SECURITY_TYPE_OPEN; mAutoShutdownEnabled = true; // enabled by default. @@ -668,8 +749,7 @@ public final class SoftApConfiguration implements Parcelable { mBssid = other.mBssid; mPassphrase = other.mPassphrase; mHiddenSsid = other.mHiddenSsid; - mBand = other.mBand; - mChannel = other.mChannel; + mChannels = other.mChannels.clone(); mMaxNumberOfClients = other.mMaxNumberOfClients; mSecurityType = other.mSecurityType; mAutoShutdownEnabled = other.mAutoShutdownEnabled; @@ -693,7 +773,7 @@ public final class SoftApConfiguration implements Parcelable { } } return new SoftApConfiguration(mSsid, mBssid, mPassphrase, - mHiddenSsid, mBand, mChannel, mSecurityType, mMaxNumberOfClients, + mHiddenSsid, mChannels, mSecurityType, mMaxNumberOfClients, mAutoShutdownEnabled, mShutdownTimeoutMillis, mClientControlByUser, mBlockedClientList, mAllowedClientList, mMacRandomizationSetting); } @@ -724,6 +804,22 @@ public final class SoftApConfiguration implements Parcelable { * Specifies a BSSID for the AP. * <p> * <li>If not set, defaults to null.</li> + * + * If multiple bands are requested via {@link #setBands(int[])} or + * {@link #setChannels(SparseIntArray)}, HAL will derive 2 MAC addresses since framework + * only sends down 1 MAC address. + * + * An example (but different implementation may perform a different mapping): + * <li>MAC address 1: copy value of MAC address, + * and set byte 1 = (0xFF - BSSID[1])</li> + * <li>MAC address 2: copy value of MAC address, + * and set byte 2 = (0xFF - BSSID[2])</li> + * + * Example BSSID argument: e2:38:60:c4:0e:b7 + * Derived MAC address 1: e2:c7:60:c4:0e:b7 + * Derived MAC address 2: e2:38:9f:c4:0e:b7 + * + * * @param bssid BSSID, or null to have the BSSID chosen by the framework. The caller is * responsible for avoiding collisions. * @return Builder for chaining. @@ -807,19 +903,48 @@ public final class SoftApConfiguration implements Parcelable { * @param band One or combination of the following band type: * {@link #BAND_2GHZ}, {@link #BAND_5GHZ}, {@link #BAND_6GHZ}. * @return Builder for chaining. + * @throws IllegalArgumentException when an invalid band type is provided. */ @NonNull public Builder setBand(@BandType int band) { if (!isBandValid(band)) { - throw new IllegalArgumentException("Invalid band type"); + throw new IllegalArgumentException("Invalid band type: " + band); } - mBand = band; - // Since band preference is specified, no specific channel is selected. - mChannel = 0; + mChannels = new SparseIntArray(1); + mChannels.put(band, 0); return this; } /** + * Specifies the bands for the APs. + * If more than 1 band is set, this will bring up concurrent APs. + * on the requested bands (if possible). + * <p> + * + * @param bands Array of the {@link #BandType}. + * @return Builder for chaining. + * @throws IllegalArgumentException when more than 2 bands are set or an invalid band type + * is provided. + */ + @NonNull + public Builder setBands(@NonNull int[] bands) { + if (bands.length == 0 || bands.length > 2) { + throw new IllegalArgumentException("Unsupported number of bands(" + + bands.length + ") configured"); + } + SparseIntArray channels = new SparseIntArray(bands.length); + for (int val : bands) { + if (!isBandValid(val)) { + throw new IllegalArgumentException("Invalid band type: " + val); + } + channels.put(val, 0); + } + mChannels = channels; + return this; + } + + + /** * Specifies the channel and associated band for the AP. * * The channel which AP resides on. Valid channels are country dependent. @@ -827,36 +952,86 @@ public final class SoftApConfiguration implements Parcelable { * valid channels. * * <p> - * The default for the channel is a the special value 0 to have the framework - * auto-select a valid channel from the band configured with + * If not set, the default for the channel is the special value 0 which has the + * framework auto-select a valid channel from the band configured with * {@link #setBand(int)}. * - * The channel auto selection will offload to driver when + * The channel auto selection will be offloaded to driver when * {@link SoftApCapability#areFeaturesSupported( * SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD)} - * return true. Driver will auto select best channel which based on environment - * interference to get best performance. Check {@link SoftApCapability} to get more detail. + * returns true. The driver will auto select the best channel (e.g. best performance) + * based on environment interference. Check {@link SoftApCapability} for more detail. * - * Note, since 6GHz band use the same channel numbering of 2.4GHz and 5GHZ bands, - * the caller needs to pass the band containing the selected channel. + * The API contains (band, channel) input since the 6GHz band uses the same channel + * numbering scheme as is used in the 2.4GHz and 5GHz band. Therefore, both are needed to + * uniquely identify individual channels. * * <p> - * <li>If not set, defaults to 0.</li> * @param channel operating channel of the AP. * @param band containing this channel. * @return Builder for chaining. + * @throws IllegalArgumentException when the invalid channel or band type is configured. */ @NonNull public Builder setChannel(int channel, @BandType int band) { if (!isChannelBandPairValid(channel, band)) { - throw new IllegalArgumentException("Invalid band type"); + throw new IllegalArgumentException("Invalid channel(" + channel + + ") & band (" + band + ") configured"); } - mBand = band; - mChannel = channel; + mChannels = new SparseIntArray(1); + mChannels.put(band, channel); return this; } /** + * Specifies the channels and associated bands for the APs. + * + * When more than 1 channel is set, this will bring up concurrent APs on the requested + * channels and bands (if possible). + * + * Valid channels are country dependent. + * The {@link SoftApCapability#getSupportedChannelList(int)} can be used to obtain + * valid channels in each band. + * + * <p> + * If not set, the default for the channel is the special value 0 which has the framework + * auto-select a valid channel from the band configured with {@link #setBands(int[])}. + * + * The channel auto selection will be offloaded to driver when + * {@link SoftApCapability#areFeaturesSupported( + * SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD)} + * returns true. The driver will auto select the best channel (e.g. best performance) + * based on environment interference. Check {@link SoftApCapability} for more detail. + * + * The API contains (band, channel) input since the 6GHz band uses the same channel + * numbering scheme as is used in the 2.4GHz and 5GHz band. Therefore, both are needed to + * uniquely identify individual channels. + * + * <p> + * @param channels SparseIntArray (key: {@code #BandType} , value: channel) consists of + * {@code BAND_} and corresponding channel. + * @return Builder for chaining. + * @throws IllegalArgumentException when more than 2 channels are set or the invalid + * channel or band type is configured. + */ + @NonNull + public Builder setChannels(@NonNull SparseIntArray channels) { + if (channels.size() == 0 || channels.size() > 2) { + throw new IllegalArgumentException("Unsupported number of channels(" + + channels.size() + ") configured"); + } + for (int i = 0; i < channels.size(); i++) { + if (!isChannelBandPairValid(channels.valueAt(i), channels.keyAt(i))) { + throw new IllegalArgumentException("Invalid channel(" + channels.valueAt(i) + + ") & band (" + channels.keyAt(i) + ") configured"); + } + } + mChannels = channels.clone(); + return this; + } + + + /** * Specifies the maximum number of clients that can associate to the AP. * * The maximum number of clients (STAs) which can associate to the AP. @@ -1044,7 +1219,7 @@ public final class SoftApConfiguration implements Parcelable { @NonNull public Builder setMacRandomizationSetting( @MacRandomizationSetting int macRandomizationSetting) { - if (!SdkLevelUtil.isAtLeastS()) { + if (!SdkLevel.isAtLeastS()) { throw new UnsupportedOperationException(); } mMacRandomizationSetting = macRandomizationSetting; diff --git a/wifi/java/android/net/wifi/SoftApInfo.java b/wifi/java/android/net/wifi/SoftApInfo.java index cf61f81e6d22..9a16facfec26 100644 --- a/wifi/java/android/net/wifi/SoftApInfo.java +++ b/wifi/java/android/net/wifi/SoftApInfo.java @@ -20,11 +20,11 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.net.MacAddress; -import android.net.wifi.util.SdkLevelUtil; import android.os.Parcel; import android.os.Parcelable; import com.android.internal.util.Preconditions; +import com.android.modules.utils.build.SdkLevel; import java.util.Objects; @@ -141,7 +141,7 @@ public final class SoftApInfo implements Parcelable { */ @Nullable public MacAddress getBssid() { - if (!SdkLevelUtil.isAtLeastS()) { + if (!SdkLevel.isAtLeastS()) { throw new UnsupportedOperationException(); } return mBssid; @@ -180,7 +180,7 @@ public final class SoftApInfo implements Parcelable { * @return valid values from {@link ScanResult}'s {@code WIFI_STANDARD_} */ public @WifiAnnotations.WifiStandard int getWifiStandard() { - if (!SdkLevelUtil.isAtLeastS()) { + if (!SdkLevel.isAtLeastS()) { throw new UnsupportedOperationException(); } return mWifiStandard; diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 2ca2d1e39049..8ef8fe1abb0d 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -44,7 +44,6 @@ import android.net.wifi.hotspot2.IProvisioningCallback; import android.net.wifi.hotspot2.OsuProvider; import android.net.wifi.hotspot2.PasspointConfiguration; import android.net.wifi.hotspot2.ProvisioningCallback; -import android.net.wifi.util.SdkLevelUtil; import android.os.Binder; import android.os.Build; import android.os.Handler; @@ -62,6 +61,7 @@ import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.modules.utils.build.SdkLevel; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -2493,7 +2493,7 @@ public class WifiManager { * @return true if this device supports multiple STA concurrency, false otherwise. */ public boolean isMultiStaConcurrencySupported() { - if (!SdkLevelUtil.isAtLeastS()) { + if (!SdkLevel.isAtLeastS()) { throw new UnsupportedOperationException(); } return isFeatureSupported(WIFI_FEATURE_ADDITIONAL_STA); diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java index 0b368708d283..acae218b74e0 100644 --- a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java +++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java @@ -26,7 +26,6 @@ import android.annotation.SystemApi; import android.net.MacAddress; import android.net.NetworkCapabilities; import android.net.wifi.hotspot2.PasspointConfiguration; -import android.net.wifi.util.SdkLevelUtil; import android.os.Parcel; import android.os.Parcelable; import android.telephony.SubscriptionInfo; @@ -34,6 +33,8 @@ import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.text.TextUtils; +import com.android.modules.utils.build.SdkLevel; + import java.nio.charset.CharsetEncoder; import java.nio.charset.StandardCharsets; import java.util.List; @@ -451,7 +452,7 @@ public final class WifiNetworkSuggestion implements Parcelable { * @return Instance of {@link Builder} to enable chaining of the builder method. */ public @NonNull Builder setSubscriptionId(int subId) { - if (!SdkLevelUtil.isAtLeastS()) { + if (!SdkLevel.isAtLeastS()) { throw new UnsupportedOperationException(); } mSubscriptionId = subId; @@ -466,7 +467,7 @@ public final class WifiNetworkSuggestion implements Parcelable { * @return Instance of {@link Builder} to enable chaining of the builder method. */ public @NonNull Builder setPriorityGroup(int priorityGroup) { - if (!SdkLevelUtil.isAtLeastS()) { + if (!SdkLevel.isAtLeastS()) { throw new UnsupportedOperationException(); } mPriorityGroup = priorityGroup; @@ -707,7 +708,7 @@ public final class WifiNetworkSuggestion implements Parcelable { */ @SystemApi public @NonNull Builder setOemPaid(boolean isOemPaid) { - if (!SdkLevelUtil.isAtLeastS()) { + if (!SdkLevel.isAtLeastS()) { throw new UnsupportedOperationException(); } mIsNetworkOemPaid = isOemPaid; @@ -1204,7 +1205,7 @@ public final class WifiNetworkSuggestion implements Parcelable { */ @SystemApi public boolean isOemPaid() { - if (!SdkLevelUtil.isAtLeastS()) { + if (!SdkLevel.isAtLeastS()) { throw new UnsupportedOperationException(); } return wifiConfiguration.oemPaid; @@ -1242,7 +1243,7 @@ public final class WifiNetworkSuggestion implements Parcelable { * @see Builder#setPriorityGroup(int) */ public int getPriorityGroup() { - if (!SdkLevelUtil.isAtLeastS()) { + if (!SdkLevel.isAtLeastS()) { throw new UnsupportedOperationException(); } return priorityGroup; @@ -1252,7 +1253,7 @@ public final class WifiNetworkSuggestion implements Parcelable { * @see Builder#setSubscriptionId(int) */ public int getSubscriptionId() { - if (!SdkLevelUtil.isAtLeastS()) { + if (!SdkLevel.isAtLeastS()) { throw new UnsupportedOperationException(); } return wifiConfiguration.subscriptionId; diff --git a/wifi/java/android/net/wifi/aware/Characteristics.java b/wifi/java/android/net/wifi/aware/Characteristics.java index 116786516b3b..9bdda7f7d323 100644 --- a/wifi/java/android/net/wifi/aware/Characteristics.java +++ b/wifi/java/android/net/wifi/aware/Characteristics.java @@ -17,11 +17,12 @@ package android.net.wifi.aware; import android.annotation.IntDef; -import android.net.wifi.util.SdkLevelUtil; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; +import com.android.modules.utils.build.SdkLevel; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -92,7 +93,7 @@ public final class Characteristics implements Parcelable { * @return True if supported, false otherwise. */ public boolean isInstantCommunicationModeSupported() { - if (!SdkLevelUtil.isAtLeastS()) { + if (!SdkLevel.isAtLeastS()) { throw new UnsupportedOperationException(); } return mCharacteristics.getBoolean(KEY_IS_INSTANT_COMMUNICATION_MODE_SUPPORTED); diff --git a/wifi/java/android/net/wifi/aware/WifiAwareManager.java b/wifi/java/android/net/wifi/aware/WifiAwareManager.java index bb146e37d48c..67c60322e47a 100644 --- a/wifi/java/android/net/wifi/aware/WifiAwareManager.java +++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java @@ -29,7 +29,6 @@ import android.net.ConnectivityManager; import android.net.NetworkRequest; import android.net.NetworkSpecifier; import android.net.wifi.util.HexEncoding; -import android.net.wifi.util.SdkLevelUtil; import android.os.Binder; import android.os.Build; import android.os.Bundle; @@ -39,6 +38,8 @@ import android.os.Message; import android.os.RemoteException; import android.util.Log; +import com.android.modules.utils.build.SdkLevel; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.ref.WeakReference; @@ -210,7 +211,7 @@ public class WifiAwareManager { * or not (false). */ public boolean isDeviceAttached() { - if (!SdkLevelUtil.isAtLeastS()) { + if (!SdkLevel.isAtLeastS()) { throw new UnsupportedOperationException(); } try { @@ -229,7 +230,7 @@ public class WifiAwareManager { */ @SystemApi public void enableInstantCommunicationMode(boolean enable) { - if (!SdkLevelUtil.isAtLeastS()) { + if (!SdkLevel.isAtLeastS()) { throw new UnsupportedOperationException(); } try { @@ -246,7 +247,7 @@ public class WifiAwareManager { * @return true if it is enabled, false otherwise. */ public boolean isInstantCommunicationModeEnabled() { - if (!SdkLevelUtil.isAtLeastS()) { + if (!SdkLevel.isAtLeastS()) { throw new UnsupportedOperationException(); } try { diff --git a/wifi/java/android/net/wifi/util/SdkLevelUtil.java b/wifi/java/android/net/wifi/util/SdkLevelUtil.java deleted file mode 100644 index d08d4fd742b7..000000000000 --- a/wifi/java/android/net/wifi/util/SdkLevelUtil.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.wifi.util; - -import android.os.Build; - -/** - * Utility to check the SDK version of the device that the code is running on. - * - * This can be used to disable new Wifi APIs added in Mainline updates on older SDK versions. - * - * Note: if certain functionality is gated with SdkLevelUtil, its corresponding unit tests should - * also be gated by the same condition. Then, those unit tests will only be exercised on a base - * system image satisfying that condition. - * Alternatively, it can be tested via static mocking. - * - * @hide - */ -public class SdkLevelUtil { - - /** This class is not instantiable. */ - private SdkLevelUtil() {} - - /** Returns true if the Android platform SDK is at least "S", false otherwise. */ - public static boolean isAtLeastS() { - // TODO(b/167575586): after S SDK finalization, this method should just be - // `return Build.VERSION.SDK_INT >= Build.VERSION_CODES.S;` - - // at least S: return true - // this condition only evaluates to true after S SDK finalization when VERSION_CODES.S - // is set to something like "31", before SDK finalization the value is "10000" - // Note that Build.VERSION_CODES.S is inlined at compile time. If it's inlined to 10000, - // this condition never evaluates to true. - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - return true; - } - - // Assume for now that S = R + 1 - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R) { - return true; - } - - // R: check CODENAME - // Before S SDK finalization, SDK_INT = R = 30 i.e. remains on the previous version - if (Build.VERSION.SDK_INT == Build.VERSION_CODES.R) { - // CODENAME = "REL" on R release builds - // CODENAME = "S" on S development builds - return "S".equals(Build.VERSION.CODENAME); - } - - // older than R: return false - return false; - } -} diff --git a/wifi/tests/Android.bp b/wifi/tests/Android.bp index 6a39959e8cfd..b710a1492d8c 100644 --- a/wifi/tests/Android.bp +++ b/wifi/tests/Android.bp @@ -31,10 +31,11 @@ android_test { static_libs: [ "androidx.test.rules", "core-test-rules", + "frameworks-base-testutils", "guava", "mockito-target-minus-junit4", + "modules-utils-build", "net-tests-utils", - "frameworks-base-testutils", "truth-prebuilt", ], @@ -47,4 +48,8 @@ android_test { "device-tests", "mts", ], + + // static libs used by both framework-wifi & FrameworksWifiApiTests. Need to rename test usage + // to a different package name to prevent conflict with the copy in production code. + jarjar_rules: "test-jarjar-rules.txt", } diff --git a/wifi/tests/src/android/net/wifi/SoftApCapabilityTest.java b/wifi/tests/src/android/net/wifi/SoftApCapabilityTest.java index 3c935058787b..702212b324f6 100644 --- a/wifi/tests/src/android/net/wifi/SoftApCapabilityTest.java +++ b/wifi/tests/src/android/net/wifi/SoftApCapabilityTest.java @@ -16,14 +16,15 @@ package android.net.wifi; -import android.net.wifi.util.SdkLevelUtil; -import android.os.Parcel; - import static org.junit.Assert.assertEquals; import static org.junit.Assume.assumeTrue; +import android.os.Parcel; + import androidx.test.filters.SmallTest; +import com.android.modules.utils.build.SdkLevel; + import org.junit.Test; /** @@ -93,7 +94,7 @@ public class SoftApCapabilityTest { @Test(expected = IllegalArgumentException.class) public void testGetSupportedChannelListWithInvalidBand() { - assumeTrue(SdkLevelUtil.isAtLeastS()); + assumeTrue(SdkLevel.isAtLeastS()); long testSoftApFeature = SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT | SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD; diff --git a/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java b/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java index 7877ea11ca1f..4a94f1f47962 100644 --- a/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java +++ b/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java @@ -19,16 +19,20 @@ package android.net.wifi; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import android.net.MacAddress; -import android.net.wifi.util.SdkLevelUtil; import android.os.Parcel; +import android.util.SparseIntArray; import androidx.test.filters.SmallTest; +import com.android.modules.utils.build.SdkLevel; + import org.junit.Test; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Random; @@ -81,7 +85,7 @@ public class SoftApConfigurationTest { assertThat(original.getChannel()).isEqualTo(0); assertThat(original.isHiddenSsid()).isEqualTo(false); assertThat(original.getMaxNumberOfClients()).isEqualTo(0); - if (SdkLevelUtil.isAtLeastS()) { + if (SdkLevel.isAtLeastS()) { assertThat(original.getMacRandomizationSetting()) .isEqualTo(SoftApConfiguration.RANDOMIZATION_PERSISTENT); } @@ -137,7 +141,7 @@ public class SoftApConfigurationTest { .setClientControlByUserEnabled(true) .setBlockedClientList(testBlockedClientList) .setAllowedClientList(testAllowedClientList); - if (SdkLevelUtil.isAtLeastS()) { + if (SdkLevel.isAtLeastS()) { originalBuilder.setMacRandomizationSetting(SoftApConfiguration.RANDOMIZATION_NONE); } SoftApConfiguration original = originalBuilder.build(); @@ -153,7 +157,7 @@ public class SoftApConfigurationTest { assertThat(original.isClientControlByUserEnabled()).isEqualTo(true); assertThat(original.getBlockedClientList()).isEqualTo(testBlockedClientList); assertThat(original.getAllowedClientList()).isEqualTo(testAllowedClientList); - if (SdkLevelUtil.isAtLeastS()) { + if (SdkLevel.isAtLeastS()) { assertThat(original.getMacRandomizationSetting()) .isEqualTo(SoftApConfiguration.RANDOMIZATION_NONE); } @@ -364,4 +368,135 @@ public class SoftApConfigurationTest { .isEqualTo(WifiConfiguration.KeyMgmt.WPA2_PSK); assertThat(wifiConfig_sae_transition.preSharedKey).isEqualTo("secretsecret"); } + + @Test + public void testDualBands() { + int[] dual_bands = new int[2]; + dual_bands[0] = SoftApConfiguration.BAND_2GHZ; + dual_bands[1] = SoftApConfiguration.BAND_5GHZ; + SoftApConfiguration dual_bands_config = new SoftApConfiguration.Builder() + .setSsid("ssid") + .setBands(dual_bands) + .build(); + assertTrue(Arrays.equals(dual_bands, dual_bands_config.getBands())); + assertThat(dual_bands_config.getBand()).isEqualTo(SoftApConfiguration.BAND_2GHZ); + } + + @Test + public void testDualChannels() { + int[] expected_dual_bands = new int[2]; + expected_dual_bands[0] = SoftApConfiguration.BAND_2GHZ; + expected_dual_bands[1] = SoftApConfiguration.BAND_5GHZ; + SparseIntArray dual_channels = new SparseIntArray(2); + dual_channels.put(SoftApConfiguration.BAND_5GHZ, 149); + dual_channels.put(SoftApConfiguration.BAND_2GHZ, 2); + SoftApConfiguration dual_channels_config = new SoftApConfiguration.Builder() + .setSsid("ssid") + .setChannels(dual_channels) + .build(); + assertTrue(Arrays.equals(expected_dual_bands, dual_channels_config.getBands())); + assertThat(dual_channels_config.getBand()).isEqualTo(SoftApConfiguration.BAND_2GHZ); + assertTrue(dual_channels.toString().equals(dual_channels_config.getChannels().toString())); + assertThat(dual_channels_config.getChannel()).isEqualTo(2); + } + + @Test + public void testInvalidBandWhenSetBands() { + boolean isIllegalArgumentExceptionHappened = false; + int[] dual_bands = new int[2]; + dual_bands[0] = SoftApConfiguration.BAND_2GHZ; + dual_bands[1] = -1; + try { + SoftApConfiguration dual_channels_config = new SoftApConfiguration.Builder() + .setSsid("ssid") + .setBands(dual_bands) + .build(); + isIllegalArgumentExceptionHappened = false; + } catch (IllegalArgumentException iae) { + isIllegalArgumentExceptionHappened = true; + } + assertTrue(isIllegalArgumentExceptionHappened); + + try { + SoftApConfiguration dual_channels_config = new SoftApConfiguration.Builder() + .setSsid("ssid") + .setBands(new int[0]) + .build(); + isIllegalArgumentExceptionHappened = false; + } catch (IllegalArgumentException iae) { + isIllegalArgumentExceptionHappened = true; + } + assertTrue(isIllegalArgumentExceptionHappened); + + try { + SoftApConfiguration dual_channels_config = new SoftApConfiguration.Builder() + .setSsid("ssid") + .setBands(new int[3]) + .build(); + isIllegalArgumentExceptionHappened = false; + } catch (IllegalArgumentException iae) { + isIllegalArgumentExceptionHappened = true; + } + assertTrue(isIllegalArgumentExceptionHappened); + } + + @Test + public void testInvalidConfigWhenSetChannels() { + boolean isIllegalArgumentExceptionHappened = false; + SparseIntArray invalid_channels = new SparseIntArray(); + try { + SoftApConfiguration zero_channels_config = new SoftApConfiguration.Builder() + .setSsid("ssid") + .setChannels(invalid_channels) + .build(); + isIllegalArgumentExceptionHappened = false; + } catch (IllegalArgumentException iae) { + isIllegalArgumentExceptionHappened = true; + } + assertTrue(isIllegalArgumentExceptionHappened); + + try { + invalid_channels.clear(); + invalid_channels.put(SoftApConfiguration.BAND_2GHZ, 2); + invalid_channels.put(SoftApConfiguration.BAND_5GHZ, 11); + SoftApConfiguration invalid_band_channels_config = new SoftApConfiguration.Builder() + .setSsid("ssid") + .setChannels(invalid_channels) + .build(); + isIllegalArgumentExceptionHappened = false; + } catch (IllegalArgumentException iae) { + isIllegalArgumentExceptionHappened = true; + } + assertTrue(isIllegalArgumentExceptionHappened); + + try { + invalid_channels.clear(); + invalid_channels.put(SoftApConfiguration.BAND_2GHZ, 2); + invalid_channels.put(SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ, + 149); + SoftApConfiguration invalid_dual_channels_config = new SoftApConfiguration.Builder() + .setSsid("ssid") + .setChannels(invalid_channels) + .build(); + isIllegalArgumentExceptionHappened = false; + } catch (IllegalArgumentException iae) { + isIllegalArgumentExceptionHappened = true; + } + assertTrue(isIllegalArgumentExceptionHappened); + + try { + invalid_channels.clear(); + invalid_channels.put(SoftApConfiguration.BAND_2GHZ, 2); + invalid_channels.put(SoftApConfiguration.BAND_5GHZ, 149); + invalid_channels.put(SoftApConfiguration.BAND_6GHZ, 2); + SoftApConfiguration three_channels_config = new SoftApConfiguration.Builder() + .setSsid("ssid") + .setChannels(invalid_channels) + .build(); + isIllegalArgumentExceptionHappened = false; + } catch (IllegalArgumentException iae) { + isIllegalArgumentExceptionHappened = true; + } + assertTrue(isIllegalArgumentExceptionHappened); + } } diff --git a/wifi/tests/src/android/net/wifi/SoftApInfoTest.java b/wifi/tests/src/android/net/wifi/SoftApInfoTest.java index 2821c35f9347..28758432119c 100644 --- a/wifi/tests/src/android/net/wifi/SoftApInfoTest.java +++ b/wifi/tests/src/android/net/wifi/SoftApInfoTest.java @@ -16,14 +16,15 @@ package android.net.wifi; +import static org.junit.Assert.assertEquals; + import android.net.MacAddress; -import android.net.wifi.util.SdkLevelUtil; import android.os.Parcel; -import static org.junit.Assert.assertEquals; - import androidx.test.filters.SmallTest; +import com.android.modules.utils.build.SdkLevel; + import org.junit.Test; /** @@ -84,7 +85,7 @@ public class SoftApInfoTest { SoftApInfo info = new SoftApInfo(); assertEquals(info.getFrequency(), 0); assertEquals(info.getBandwidth(), SoftApInfo.CHANNEL_WIDTH_INVALID); - if (SdkLevelUtil.isAtLeastS()) { + if (SdkLevel.isAtLeastS()) { assertEquals(info.getBssid(), null); assertEquals(info.getWifiStandard(), ScanResult.WIFI_STANDARD_UNKNOWN); } diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java index bda776db733c..7340b145e8b2 100644 --- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java +++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java @@ -86,7 +86,6 @@ import android.net.wifi.WifiManager.SoftApCallback; import android.net.wifi.WifiManager.SuggestionConnectionStatusListener; import android.net.wifi.WifiManager.TrafficStateCallback; import android.net.wifi.WifiManager.WifiConnectedNetworkScorer; -import android.net.wifi.util.SdkLevelUtil; import android.os.Build; import android.os.Handler; import android.os.HandlerExecutor; @@ -98,6 +97,8 @@ import android.util.SparseArray; import androidx.test.filters.SmallTest; +import com.android.modules.utils.build.SdkLevel; + import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; @@ -1729,7 +1730,7 @@ public class WifiManagerTest { */ @Test public void testIsMultiStaConcurrencyOpenSupported() throws Exception { - assumeTrue(SdkLevelUtil.isAtLeastS()); + assumeTrue(SdkLevel.isAtLeastS()); when(mWifiService.getSupportedFeatures()) .thenReturn(new Long(WIFI_FEATURE_ADDITIONAL_STA)); diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java index bb84120da6ed..56e79983817f 100644 --- a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java +++ b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java @@ -27,11 +27,12 @@ import static org.junit.Assume.assumeTrue; import android.net.MacAddress; import android.net.wifi.hotspot2.PasspointConfiguration; import android.net.wifi.hotspot2.PasspointTestUtils; -import android.net.wifi.util.SdkLevelUtil; import android.os.Parcel; import androidx.test.filters.SmallTest; +import com.android.modules.utils.build.SdkLevel; + import org.junit.Test; import java.security.cert.X509Certificate; @@ -198,7 +199,7 @@ public class WifiNetworkSuggestionTest { */ @Test public void testWifiNetworkSuggestionBuilderForOemPaidEnhancedOpenNetworkWithBssid() { - assumeTrue(SdkLevelUtil.isAtLeastS()); + assumeTrue(SdkLevel.isAtLeastS()); WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder() .setSsid(TEST_SSID) @@ -953,7 +954,7 @@ public class WifiNetworkSuggestionTest { */ @Test public void testSimCredentialNetworkWithSubId() { - assumeTrue(SdkLevelUtil.isAtLeastS()); + assumeTrue(SdkLevel.isAtLeastS()); WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig(); enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.SIM); enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.NONE); @@ -1254,7 +1255,7 @@ public class WifiNetworkSuggestionTest { */ @Test public void testSetIsNetworkAsOemPaid() { - assumeTrue(SdkLevelUtil.isAtLeastS()); + assumeTrue(SdkLevel.isAtLeastS()); WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder() .setSsid(TEST_SSID) @@ -1272,7 +1273,7 @@ public class WifiNetworkSuggestionTest { */ @Test public void testSetIsNetworkAsOemPaidOnPasspointNetwork() { - assumeTrue(SdkLevelUtil.isAtLeastS()); + assumeTrue(SdkLevel.isAtLeastS()); PasspointConfiguration passpointConfiguration = PasspointTestUtils.createConfig(); WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder() @@ -1307,7 +1308,7 @@ public class WifiNetworkSuggestionTest { */ @Test(expected = IllegalStateException.class) public void testSetCredentialSharedWithUserWithSetIsNetworkAsOemPaid() { - assumeTrue(SdkLevelUtil.isAtLeastS()); + assumeTrue(SdkLevel.isAtLeastS()); new WifiNetworkSuggestion.Builder() .setSsid(TEST_SSID) diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java index 2cf7f2c1b8cf..d0d0c57008fc 100644 --- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java +++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java @@ -39,7 +39,6 @@ import android.content.pm.PackageManager; import android.net.MacAddress; import android.net.wifi.RttManager; import android.net.wifi.util.HexEncoding; -import android.net.wifi.util.SdkLevelUtil; import android.os.Build; import android.os.Handler; import android.os.IBinder; @@ -48,6 +47,8 @@ import android.os.test.TestLooper; import androidx.test.filters.SmallTest; +import com.android.modules.utils.build.SdkLevel; + import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -164,7 +165,7 @@ public class WifiAwareManagerTest { */ @Test public void testEnableInstantCommunicationMode() throws Exception { - assumeTrue(SdkLevelUtil.isAtLeastS()); + assumeTrue(SdkLevel.isAtLeastS()); mDut.isInstantCommunicationModeEnabled(); verify(mockAwareService).isInstantCommunicationModeEnabled(); mDut.enableInstantCommunicationMode(true); diff --git a/wifi/tests/test-jarjar-rules.txt b/wifi/tests/test-jarjar-rules.txt new file mode 100644 index 000000000000..41b97abb87b5 --- /dev/null +++ b/wifi/tests/test-jarjar-rules.txt @@ -0,0 +1 @@ +rule com.android.modules.utils.** com.android.wifi.test.x.@0 |