diff options
159 files changed, 4420 insertions, 1754 deletions
diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb index cfcb4e7d69b1..80317e4634f3 100644 --- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb +++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb @@ -1,6 +1,6 @@ drops { android_build_drop { - build_id: "7351002" + build_id: "7396576" target: "CtsShim" source_file: "aosp_arm64/CtsShimPriv.apk" } @@ -9,4 +9,5 @@ drops { version_group: "" git_project: "platform/frameworks/base" git_branch: "sc-dev" + transform: TRANSFORM_NONE } diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb index 0948e47561a8..3605b6d0433b 100644 --- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb +++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb @@ -1,6 +1,6 @@ drops { android_build_drop { - build_id: "7351002" + build_id: "7396576" target: "CtsShim" source_file: "aosp_arm64/CtsShim.apk" } @@ -9,4 +9,5 @@ drops { version_group: "" git_project: "platform/frameworks/base" git_branch: "sc-dev" + transform: TRANSFORM_NONE } diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb index db6447525a18..025ec3a9fdaf 100644 --- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb +++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb @@ -1,6 +1,6 @@ drops { android_build_drop { - build_id: "7351002" + build_id: "7396576" target: "CtsShim" source_file: "aosp_x86_64/CtsShimPriv.apk" } @@ -9,4 +9,5 @@ drops { version_group: "" git_project: "platform/frameworks/base" git_branch: "sc-dev" + transform: TRANSFORM_NONE } diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb index 80812df718f8..e19235a12f8f 100644 --- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb +++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb @@ -1,6 +1,6 @@ drops { android_build_drop { - build_id: "7351002" + build_id: "7396576" target: "CtsShim" source_file: "aosp_x86_64/CtsShim.apk" } @@ -9,4 +9,5 @@ drops { version_group: "" git_project: "platform/frameworks/base" git_branch: "sc-dev" + transform: TRANSFORM_NONE } diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchConfig.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchConfig.java new file mode 100644 index 000000000000..6e81afcdc912 --- /dev/null +++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchConfig.java @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.appsearch; + +import android.annotation.NonNull; +import android.os.Bundle; +import android.provider.DeviceConfig; +import android.provider.DeviceConfig.OnPropertiesChangedListener; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; + +import java.util.Objects; +import java.util.concurrent.Executor; + +/** + * It contains all the keys for the flags, as well as caches some of latest flag values from + * DeviceConfig. + * + * <p>Though the latest flag values can always be retrieved by calling {@code + * DeviceConfig.getProperty}, we want to cache some of those values. For example, the sampling + * intervals for logging, they are needed for each api call and it would be a little expensive to + * call + * {@code DeviceConfig.getProperty} every time. + * + * <p>Listener is registered to DeviceConfig keep the cached value up to date. + * + * <p>This class is thread-safe. + * + * @hide + */ +public final class AppSearchConfig implements AutoCloseable { + /** + * It would be used as default min time interval between samples in millis if there is no value + * set for {@link AppSearchConfig#KEY_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS} in DeviceConfig. + */ + @VisibleForTesting + static final long DEFAULT_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS = 50; + + /** + * It would be used as default sampling interval if there is no value + * set for {@link AppSearchConfig#KEY_SAMPLING_INTERVAL_DEFAULT} in DeviceConfig. + */ + @VisibleForTesting + static final int DEFAULT_SAMPLING_INTERVAL = 10; + + /* + * Keys for ALL the flags stored in DeviceConfig. + */ + public static final String KEY_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS = + "min_time_interval_between_samples_millis"; + public static final String KEY_SAMPLING_INTERVAL_DEFAULT = "sampling_interval_default"; + public static final String KEY_SAMPLING_INTERVAL_FOR_BATCH_CALL_STATS = + "sampling_interval_for_batch_call_stats"; + public static final String KEY_SAMPLING_INTERVAL_FOR_PUT_DOCUMENT_STATS = + "sampling_interval_for_put_document_stats"; + + // Array contains all the corresponding keys for the cached values. + private static final String[] KEYS_TO_ALL_CACHED_VALUES = { + KEY_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS, + KEY_SAMPLING_INTERVAL_DEFAULT, + KEY_SAMPLING_INTERVAL_FOR_BATCH_CALL_STATS, + KEY_SAMPLING_INTERVAL_FOR_PUT_DOCUMENT_STATS + }; + + // Lock needed for all the operations in this class. + private final Object mLock = new Object(); + + /** + * Bundle to hold all the cached flag values corresponding to + * {@link AppSearchConfig#KEYS_TO_ALL_CACHED_VALUES}. + */ + @GuardedBy("mLock") + private final Bundle mBundleLocked = new Bundle(); + + + @GuardedBy("mLock") + private boolean mIsClosedLocked = false; + + /** Listener to update cached flag values from DeviceConfig. */ + private final OnPropertiesChangedListener mOnDeviceConfigChangedListener = + properties -> { + if (!properties.getNamespace().equals(DeviceConfig.NAMESPACE_APPSEARCH)) { + return; + } + + updateCachedValues(properties); + }; + + /** + * Creates an instance of {@link AppSearchConfig}. + * + * @param executor used to fetch and cache the flag values from DeviceConfig during creation or + * config change. + */ + @NonNull + public static AppSearchConfig create(@NonNull Executor executor) { + Objects.requireNonNull(executor); + AppSearchConfig configManager = new AppSearchConfig(); + configManager.initialize(executor); + return configManager; + } + + private AppSearchConfig() { + } + + /** + * Initializes the {@link AppSearchConfig} + * + * <p>It fetches the custom properties from DeviceConfig if available. + * + * @param executor listener would be run on to handle P/H flag change. + */ + private void initialize(@NonNull Executor executor) { + executor.execute(() -> { + // Attach the callback to get updates on those properties. + DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_APPSEARCH, + executor, + mOnDeviceConfigChangedListener); + + DeviceConfig.Properties properties = DeviceConfig.getProperties( + DeviceConfig.NAMESPACE_APPSEARCH, KEYS_TO_ALL_CACHED_VALUES); + updateCachedValues(properties); + }); + } + + // TODO(b/173532925) check this will be called. If we have a singleton instance for this + // class, probably we don't need it. + @Override + public void close() { + synchronized (mLock) { + if (mIsClosedLocked) { + return; + } + + DeviceConfig.removeOnPropertiesChangedListener(mOnDeviceConfigChangedListener); + mIsClosedLocked = true; + } + } + + /** Returns cached value for minTimeIntervalBetweenSamplesMillis. */ + public long getCachedMinTimeIntervalBetweenSamplesMillis() { + synchronized (mLock) { + throwIfClosedLocked(); + return mBundleLocked.getLong(KEY_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS, + DEFAULT_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS); + } + } + + /** + * Returns cached value for default sampling interval for all the stats NOT listed in + * the configuration. + * + * <p>For example, sampling_interval=10 means that one out of every 10 stats was logged. + */ + public int getCachedSamplingIntervalDefault() { + synchronized (mLock) { + throwIfClosedLocked(); + return mBundleLocked.getInt(KEY_SAMPLING_INTERVAL_DEFAULT, DEFAULT_SAMPLING_INTERVAL); + } + } + + /** + * Returns cached value for sampling interval for batch calls. + * + * <p>For example, sampling_interval=10 means that one out of every 10 stats was logged. + */ + public int getCachedSamplingIntervalForBatchCallStats() { + synchronized (mLock) { + throwIfClosedLocked(); + return mBundleLocked.getInt(KEY_SAMPLING_INTERVAL_FOR_BATCH_CALL_STATS, + getCachedSamplingIntervalDefault()); + } + } + + /** + * Returns cached value for sampling interval for putDocument. + * + * <p>For example, sampling_interval=10 means that one out of every 10 stats was logged. + */ + public int getCachedSamplingIntervalForPutDocumentStats() { + synchronized (mLock) { + throwIfClosedLocked(); + return mBundleLocked.getInt(KEY_SAMPLING_INTERVAL_FOR_PUT_DOCUMENT_STATS, + getCachedSamplingIntervalDefault()); + } + } + + @GuardedBy("mLock") + private void throwIfClosedLocked() { + if (mIsClosedLocked) { + throw new IllegalStateException("Trying to use a closed AppSearchConfig instance."); + } + } + + private void updateCachedValues(@NonNull DeviceConfig.Properties properties) { + for (String key : properties.getKeyset()) { + updateCachedValue(key, properties); + } + } + + private void updateCachedValue(@NonNull String key, + @NonNull DeviceConfig.Properties properties) { + if (properties.getString(key, /*defaultValue=*/ null) == null) { + // Key is missing or value is just null. That is not expected if the key is + // defined in the configuration. + // + // We choose NOT to put the default value in the bundle. + // Instead, we let the getters handle what default value should be returned. + // + // Also we keep the old value in the bundle. So getters can still + // return last valid value. + return; + } + + switch (key) { + case KEY_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS: + synchronized (mLock) { + mBundleLocked.putLong(key, + properties.getLong(key, + DEFAULT_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS)); + } + break; + case KEY_SAMPLING_INTERVAL_DEFAULT: + case KEY_SAMPLING_INTERVAL_FOR_BATCH_CALL_STATS: + case KEY_SAMPLING_INTERVAL_FOR_PUT_DOCUMENT_STATS: + synchronized (mLock) { + mBundleLocked.putInt(key, properties.getInt(key, DEFAULT_SAMPLING_INTERVAL)); + } + break; + default: + break; + } + } +} diff --git a/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java b/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java index abcf1611ab04..7d0ce415502b 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java @@ -72,7 +72,7 @@ public final class PlatformLogger implements AppSearchLogger { * * <p> We can have correct extrapolated number by adding those counts back when we log * the same type of stats next time. E.g. the true count of an event could be estimated as: - * SUM(sampling_ratio * (num_skipped_sample + 1)) as est_count + * SUM(sampling_interval * (num_skipped_sample + 1)) as est_count * * <p>The key to the SparseArray is {@link CallStats.CallType} */ @@ -105,42 +105,42 @@ public final class PlatformLogger implements AppSearchLogger { // logging again. private final long mMinTimeIntervalBetweenSamplesMillis; - // Default sampling ratio for all types of stats - private final int mDefaultSamplingRatio; + // Default sampling interval for all types of stats + private final int mDefaultSamplingInterval; /** - * Sampling ratios for different types of stats + * Sampling intervals for different types of stats * * <p>This SparseArray is passed by client and is READ-ONLY. The key to that SparseArray is * {@link CallStats.CallType} * - * <p>If sampling ratio is missing for certain stats type, - * {@link Config#mDefaultSamplingRatio} will be used. + * <p>If sampling interval is missing for certain stats type, + * {@link Config#mDefaultSamplingInterval} will be used. * - * <p>E.g. sampling ratio=10 means that one out of every 10 stats was logged. If sampling - * ratio is 1, we will log each sample and it acts as if the sampling is disabled. + * <p>E.g. sampling interval=10 means that one out of every 10 stats was logged. If sampling + * interval is 1, we will log each sample and it acts as if the sampling is disabled. */ @NonNull - private final SparseIntArray mSamplingRatios; + private final SparseIntArray mSamplingIntervals; /** * Configuration for {@link PlatformLogger} * * @param minTimeIntervalBetweenSamplesMillis minimum time interval apart in Milliseconds * required for two consecutive stats logged - * @param defaultSamplingRatio default sampling ratio - * @param samplingRatios SparseArray to customize sampling ratio for + * @param defaultSamplingInterval default sampling interval + * @param samplingIntervals SparseArray to customize sampling interval for * different stat types */ public Config(long minTimeIntervalBetweenSamplesMillis, - int defaultSamplingRatio, - @NonNull SparseIntArray samplingRatios) { + int defaultSamplingInterval, + @NonNull SparseIntArray samplingIntervals) { // TODO(b/173532925) Probably we can get rid of those three after we have p/h flags // for them. - // e.g. we can just call DeviceConfig.get(SAMPLING_RATIO_FOR_PUT_DOCUMENTS). + // e.g. we can just call DeviceConfig.get(SAMPLING_INTERVAL_FOR_PUT_DOCUMENTS). mMinTimeIntervalBetweenSamplesMillis = minTimeIntervalBetweenSamplesMillis; - mDefaultSamplingRatio = defaultSamplingRatio; - mSamplingRatios = samplingRatios; + mDefaultSamplingInterval = defaultSamplingInterval; + mSamplingIntervals = samplingIntervals; } } @@ -150,14 +150,14 @@ public final class PlatformLogger implements AppSearchLogger { static final class ExtraStats { // UID for the calling package of the stats. final int mPackageUid; - // sampling ratio for the call type of the stats. - final int mSamplingRatio; + // sampling interval for the call type of the stats. + final int mSamplingInterval; // number of samplings skipped before the current one for the same call type. final int mSkippedSampleCount; - ExtraStats(int packageUid, int samplingRatio, int skippedSampleCount) { + ExtraStats(int packageUid, int samplingInterval, int skippedSampleCount) { mPackageUid = packageUid; - mSamplingRatio = samplingRatio; + mSamplingInterval = samplingInterval; mSkippedSampleCount = skippedSampleCount; } } @@ -224,7 +224,7 @@ public final class PlatformLogger implements AppSearchLogger { * * @return removed UID for the package, or {@code INVALID_UID} if package was not previously * cached. - */ + */ public int removeCachedUidForPackage(@NonNull String packageName) { // TODO(b/173532925) This needs to be called when we get PACKAGE_REMOVED intent Objects.requireNonNull(packageName); @@ -243,7 +243,7 @@ public final class PlatformLogger implements AppSearchLogger { try { int hashCodeForDatabase = calculateHashCodeMd5(database); AppSearchStatsLog.write(AppSearchStatsLog.APP_SEARCH_CALL_STATS_REPORTED, - extraStats.mSamplingRatio, + extraStats.mSamplingInterval, extraStats.mSkippedSampleCount, extraStats.mPackageUid, hashCodeForDatabase, @@ -275,7 +275,7 @@ public final class PlatformLogger implements AppSearchLogger { try { int hashCodeForDatabase = calculateHashCodeMd5(database); AppSearchStatsLog.write(AppSearchStatsLog.APP_SEARCH_PUT_DOCUMENT_STATS_REPORTED, - extraStats.mSamplingRatio, + extraStats.mSamplingInterval, extraStats.mSkippedSampleCount, extraStats.mPackageUid, hashCodeForDatabase, @@ -312,7 +312,7 @@ public final class PlatformLogger implements AppSearchLogger { try { int hashCodeForDatabase = calculateHashCodeMd5(database); AppSearchStatsLog.write(AppSearchStatsLog.APP_SEARCH_QUERY_STATS_REPORTED, - extraStats.mSamplingRatio, + extraStats.mSamplingInterval, extraStats.mSkippedSampleCount, extraStats.mPackageUid, hashCodeForDatabase, @@ -355,7 +355,7 @@ public final class PlatformLogger implements AppSearchLogger { ExtraStats extraStats = createExtraStatsLocked(/*packageName=*/ null, CallStats.CALL_TYPE_INITIALIZE); AppSearchStatsLog.write(AppSearchStatsLog.APP_SEARCH_INITIALIZE_STATS_REPORTED, - extraStats.mSamplingRatio, + extraStats.mSamplingInterval, extraStats.mSkippedSampleCount, extraStats.mPackageUid, stats.getStatusCode(), @@ -428,14 +428,14 @@ public final class PlatformLogger implements AppSearchLogger { packageUid = getPackageUidAsUserLocked(packageName); } - int samplingRatio = mConfig.mSamplingRatios.get(callType, - mConfig.mDefaultSamplingRatio); + int samplingInterval = mConfig.mSamplingIntervals.get(callType, + mConfig.mDefaultSamplingInterval); int skippedSampleCount = mSkippedSampleCountLocked.get(callType, /*valueOfKeyIfNotFound=*/ 0); mSkippedSampleCountLocked.put(callType, 0); - return new ExtraStats(packageUid, samplingRatio, skippedSampleCount); + return new ExtraStats(packageUid, samplingInterval, skippedSampleCount); } /** @@ -450,11 +450,11 @@ public final class PlatformLogger implements AppSearchLogger { // rate limiting. @VisibleForTesting boolean shouldLogForTypeLocked(@CallStats.CallType int callType) { - int samplingRatio = mConfig.mSamplingRatios.get(callType, - mConfig.mDefaultSamplingRatio); + int samplingInterval = mConfig.mSamplingIntervals.get(callType, + mConfig.mDefaultSamplingInterval); // Sampling - if (!shouldSample(samplingRatio)) { + if (!shouldSample(samplingInterval)) { return false; } @@ -475,15 +475,15 @@ public final class PlatformLogger implements AppSearchLogger { /** * Checks if the stats should be "sampled" * - * @param samplingRatio sampling ratio + * @param samplingInterval sampling interval * @return if the stats should be sampled */ - private boolean shouldSample(int samplingRatio) { - if (samplingRatio <= 0) { + private boolean shouldSample(int samplingInterval) { + if (samplingInterval <= 0) { return false; } - return mRng.nextInt((int) samplingRatio) == 0; + return mRng.nextInt((int) samplingInterval) == 0; } /** diff --git a/core/api/current.txt b/core/api/current.txt index 4c61afea3b59..1de47b548a5c 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -246,7 +246,6 @@ package android { public static final class R.attr { ctor public R.attr(); - field public static final int __removed3; field public static final int absListViewStyle = 16842858; // 0x101006a field public static final int accessibilityEventTypes = 16843648; // 0x1010380 field public static final int accessibilityFeedbackType = 16843650; // 0x1010382 @@ -308,7 +307,7 @@ package android { field public static final int allowAudioPlaybackCapture = 16844289; // 0x1010601 field public static final int allowBackup = 16843392; // 0x1010280 field public static final int allowClearUserData = 16842757; // 0x1010005 - field public static final int allowClickWhenDisabled; + field public static final int allowClickWhenDisabled = 16844312; // 0x1010618 field public static final int allowEmbedded = 16843765; // 0x10103f5 field public static final int allowNativeHeapPointerTagging = 16844306; // 0x1010612 field public static final int allowParallelSyncs = 16843570; // 0x1010332 @@ -339,8 +338,8 @@ package android { field public static final int apiKey = 16843281; // 0x1010211 field public static final int appCategory = 16844101; // 0x1010545 field public static final int appComponentFactory = 16844154; // 0x101057a - field public static final int attributionTags; - field public static final int attributionsAreUserVisible; + field public static final int attributionTags = 16844354; // 0x1010642 + field public static final int attributionsAreUserVisible = 16844363; // 0x101064b field public static final int author = 16843444; // 0x10102b4 field public static final int authorities = 16842776; // 0x1010018 field public static final int autoAdvanceViewId = 16843535; // 0x101030f @@ -406,7 +405,7 @@ package android { field public static final int calendarViewShown = 16843596; // 0x101034c field public static final int calendarViewStyle = 16843613; // 0x101035d field public static final int canControlMagnification = 16844039; // 0x1010507 - field public static final int canPauseRecording; + field public static final int canPauseRecording = 16844314; // 0x101061a field public static final int canPerformGestures = 16844045; // 0x101050d field public static final int canRecord = 16844060; // 0x101051c field @Deprecated public static final int canRequestEnhancedWebAccessibility = 16843736; // 0x10103d8 @@ -448,7 +447,7 @@ package android { field public static final int clickable = 16842981; // 0x10100e5 field public static final int clipChildren = 16842986; // 0x10100ea field public static final int clipOrientation = 16843274; // 0x101020a - field public static final int clipToOutline; + field public static final int clipToOutline = 16844328; // 0x1010628 field public static final int clipToPadding = 16842987; // 0x10100eb field public static final int closeIcon = 16843905; // 0x1010481 field @Deprecated public static final int codes = 16843330; // 0x1010242 @@ -518,7 +517,7 @@ package android { field public static final int dashGap = 16843175; // 0x10101a7 field public static final int dashWidth = 16843174; // 0x10101a6 field public static final int data = 16842798; // 0x101002e - field public static final int dataExtractionRules; + field public static final int dataExtractionRules = 16844350; // 0x101063e field public static final int datePickerDialogTheme = 16843948; // 0x10104ac field public static final int datePickerMode = 16843955; // 0x10104b3 field public static final int datePickerStyle = 16843612; // 0x101035c @@ -540,8 +539,8 @@ package android { field public static final int detailSocialSummary = 16843428; // 0x10102a4 field public static final int detailsElementBackground = 16843598; // 0x101034e field public static final int dial = 16843010; // 0x1010102 - field public static final int dialTint; - field public static final int dialTintMode; + field public static final int dialTint = 16844342; // 0x1010636 + field public static final int dialTintMode = 16844343; // 0x1010637 field public static final int dialogCornerRadius = 16844145; // 0x1010571 field public static final int dialogIcon = 16843252; // 0x10101f4 field public static final int dialogLayout = 16843255; // 0x10101f7 @@ -595,7 +594,7 @@ package android { field public static final int editTextStyle = 16842862; // 0x101006e field @Deprecated public static final int editable = 16843115; // 0x101016b field public static final int editorExtras = 16843300; // 0x1010224 - field public static final int effectColor; + field public static final int effectColor = 16844361; // 0x1010649 field public static final int elegantTextHeight = 16843869; // 0x101045d field public static final int elevation = 16843840; // 0x1010440 field public static final int ellipsize = 16842923; // 0x10100ab @@ -675,7 +674,7 @@ package android { field @Deprecated public static final int fontProviderCerts = 16844125; // 0x101055d field @Deprecated public static final int fontProviderPackage = 16844119; // 0x1010557 field @Deprecated public static final int fontProviderQuery = 16844113; // 0x1010551 - field public static final int fontProviderSystemFontFamily; + field public static final int fontProviderSystemFontFamily = 16844322; // 0x1010622 field public static final int fontStyle = 16844095; // 0x101053f field public static final int fontVariationSettings = 16844144; // 0x1010570 field public static final int fontWeight = 16844083; // 0x1010533 @@ -739,14 +738,14 @@ package android { field public static final int groupIndicator = 16843019; // 0x101010b field public static final int gwpAsanMode = 16844310; // 0x1010616 field public static final int hand_hour = 16843011; // 0x1010103 - field public static final int hand_hourTint; - field public static final int hand_hourTintMode; + field public static final int hand_hourTint = 16844344; // 0x1010638 + field public static final int hand_hourTintMode = 16844345; // 0x1010639 field public static final int hand_minute = 16843012; // 0x1010104 - field public static final int hand_minuteTint; - field public static final int hand_minuteTintMode; - field public static final int hand_second; - field public static final int hand_secondTint; - field public static final int hand_secondTintMode; + field public static final int hand_minuteTint = 16844346; // 0x101063a + field public static final int hand_minuteTintMode = 16844347; // 0x101063b + field public static final int hand_second = 16844323; // 0x1010623 + field public static final int hand_secondTint = 16844348; // 0x101063c + field public static final int hand_secondTintMode = 16844349; // 0x101063d field public static final int handle = 16843354; // 0x101025a field public static final int handleProfiling = 16842786; // 0x1010022 field public static final int hapticFeedbackEnabled = 16843358; // 0x101025e @@ -830,7 +829,7 @@ package android { field public static final int installLocation = 16843447; // 0x10102b7 field public static final int interactiveUiTimeout = 16844181; // 0x1010595 field public static final int interpolator = 16843073; // 0x1010141 - field public static final int isAccessibilityTool; + field public static final int isAccessibilityTool = 16844353; // 0x1010641 field public static final int isAlwaysSyncable = 16843571; // 0x1010333 field public static final int isAsciiCapable = 16843753; // 0x10103e9 field public static final int isAuxiliary = 16843647; // 0x101037f @@ -872,8 +871,8 @@ package android { field public static final int keyboardNavigationCluster = 16844096; // 0x1010540 field public static final int keycode = 16842949; // 0x10100c5 field public static final int killAfterRestore = 16843420; // 0x101029c - field public static final int knownCerts; - field public static final int lStar; + field public static final int knownCerts = 16844330; // 0x101062a + field public static final int lStar = 16844359; // 0x1010647 field public static final int label = 16842753; // 0x1010001 field public static final int labelFor = 16843718; // 0x10103c6 field @Deprecated public static final int labelTextSize = 16843317; // 0x1010235 @@ -983,8 +982,8 @@ package android { field public static final int maxLines = 16843091; // 0x1010153 field public static final int maxLongVersionCode = 16844163; // 0x1010583 field public static final int maxRecents = 16843846; // 0x1010446 - field public static final int maxResizeHeight; - field public static final int maxResizeWidth; + field public static final int maxResizeHeight = 16844339; // 0x1010633 + field public static final int maxResizeWidth = 16844338; // 0x1010632 field public static final int maxRows = 16843059; // 0x1010133 field public static final int maxSdkVersion = 16843377; // 0x1010271 field public static final int maxWidth = 16843039; // 0x101011f @@ -993,7 +992,7 @@ package android { field public static final int measureWithLargestChild = 16843476; // 0x10102d4 field public static final int mediaRouteButtonStyle = 16843693; // 0x10103ad field public static final int mediaRouteTypes = 16843694; // 0x10103ae - field public static final int memtagMode; + field public static final int memtagMode = 16844324; // 0x1010624 field public static final int menuCategory = 16843230; // 0x10101de field public static final int mimeGroup = 16844309; // 0x1010615 field public static final int mimeType = 16842790; // 0x1010026 @@ -1017,7 +1016,7 @@ package android { field public static final int multiArch = 16843918; // 0x101048e field public static final int multiprocess = 16842771; // 0x1010013 field public static final int name = 16842755; // 0x1010003 - field public static final int nativeHeapZeroInitialized; + field public static final int nativeHeapZeroInitialized = 16844325; // 0x1010625 field public static final int navigationBarColor = 16843858; // 0x1010452 field public static final int navigationBarDividerColor = 16844141; // 0x101056d field public static final int navigationContentDescription = 16843969; // 0x10104c1 @@ -1087,13 +1086,13 @@ package android { field public static final int panelTextAppearance = 16842850; // 0x1010062 field public static final int parentActivityName = 16843687; // 0x10103a7 field @Deprecated public static final int password = 16843100; // 0x101015c - field public static final int passwordsActivity; + field public static final int passwordsActivity = 16844351; // 0x101063f field public static final int path = 16842794; // 0x101002a - field public static final int pathAdvancedPattern; + field public static final int pathAdvancedPattern = 16844320; // 0x1010620 field public static final int pathData = 16843781; // 0x1010405 field public static final int pathPattern = 16842796; // 0x101002c field public static final int pathPrefix = 16842795; // 0x101002b - field public static final int pathSuffix; + field public static final int pathSuffix = 16844318; // 0x101061e field public static final int patternPathData = 16843978; // 0x10104ca field public static final int permission = 16842758; // 0x1010006 field public static final int permissionFlags = 16843719; // 0x10103c7 @@ -1130,7 +1129,7 @@ package android { field public static final int presentationTheme = 16843712; // 0x10103c0 field public static final int preserveLegacyExternalStorage = 16844308; // 0x1010614 field public static final int previewImage = 16843482; // 0x10102da - field public static final int previewLayout; + field public static final int previewLayout = 16844327; // 0x1010627 field public static final int primaryContentAlpha = 16844114; // 0x1010552 field public static final int priority = 16842780; // 0x101001c field public static final int privateImeOptions = 16843299; // 0x1010223 @@ -1187,8 +1186,8 @@ package android { field public static final int reqNavigation = 16843306; // 0x101022a field public static final int reqTouchScreen = 16843303; // 0x1010227 field public static final int requestLegacyExternalStorage = 16844291; // 0x1010603 - field public static final int requestRawExternalStorageAccess; - field public static final int requireDeviceScreenOn; + field public static final int requestRawExternalStorageAccess = 16844357; // 0x1010645 + field public static final int requireDeviceScreenOn = 16844317; // 0x101061d field public static final int requireDeviceUnlock = 16843756; // 0x10103ec field public static final int required = 16843406; // 0x101028e field public static final int requiredAccountType = 16843734; // 0x10103d6 @@ -1213,7 +1212,7 @@ package android { field public static final int right = 16843183; // 0x10101af field public static final int ringtonePreferenceStyle = 16842899; // 0x1010093 field public static final int ringtoneType = 16843257; // 0x10101f9 - field public static final int rollbackDataPolicy; + field public static final int rollbackDataPolicy = 16844311; // 0x1010617 field public static final int rotation = 16843558; // 0x1010326 field public static final int rotationAnimation = 16844090; // 0x101053a field public static final int rotationX = 16843559; // 0x1010327 @@ -1274,7 +1273,7 @@ package android { field public static final int segmentedButtonStyle = 16843568; // 0x1010330 field public static final int selectAllOnFocus = 16843102; // 0x101015e field public static final int selectable = 16843238; // 0x10101e6 - field public static final int selectableAsDefault; + field public static final int selectableAsDefault = 16844352; // 0x1010640 field public static final int selectableItemBackground = 16843534; // 0x101030e field public static final int selectableItemBackgroundBorderless = 16843868; // 0x101045c field @Deprecated public static final int selectedDateVerticalBar = 16843591; // 0x1010347 @@ -1302,7 +1301,7 @@ package android { field public static final int showDefault = 16843258; // 0x10101fa field public static final int showDividers = 16843561; // 0x1010329 field public static final int showForAllUsers = 16844015; // 0x10104ef - field public static final int showInInputMethodPicker; + field public static final int showInInputMethodPicker = 16844360; // 0x1010648 field public static final int showMetadataInPreview = 16844079; // 0x101052f field @Deprecated public static final int showOnLockScreen = 16843721; // 0x10103c9 field public static final int showSilent = 16843259; // 0x10101fb @@ -1325,17 +1324,17 @@ package android { field public static final int spinnerMode = 16843505; // 0x10102f1 field public static final int spinnerStyle = 16842881; // 0x1010081 field public static final int spinnersShown = 16843595; // 0x101034b - field public static final int splashScreenTheme; + field public static final int splashScreenTheme = 16844337; // 0x1010631 field public static final int splitMotionEvents = 16843503; // 0x10102ef field public static final int splitName = 16844105; // 0x1010549 field public static final int splitTrack = 16843852; // 0x101044c field public static final int spotShadowAlpha = 16843967; // 0x10104bf field public static final int src = 16843033; // 0x1010119 field public static final int ssp = 16843747; // 0x10103e3 - field public static final int sspAdvancedPattern; + field public static final int sspAdvancedPattern = 16844321; // 0x1010621 field public static final int sspPattern = 16843749; // 0x10103e5 field public static final int sspPrefix = 16843748; // 0x10103e4 - field public static final int sspSuffix; + field public static final int sspSuffix = 16844319; // 0x101061f field public static final int stackFromBottom = 16843005; // 0x10100fd field public static final int stackViewStyle = 16843838; // 0x101043e field public static final int starStyle = 16842882; // 0x1010082 @@ -1408,7 +1407,7 @@ package android { field public static final int supportsRtl = 16843695; // 0x10103af field public static final int supportsSwitchingToNextInputMethod = 16843755; // 0x10103eb field public static final int supportsUploading = 16843419; // 0x101029b - field public static final int suppressesSpellChecker; + field public static final int suppressesSpellChecker = 16844355; // 0x1010643 field public static final int switchMinWidth = 16843632; // 0x1010370 field public static final int switchPadding = 16843633; // 0x1010371 field public static final int switchPreferenceStyle = 16843629; // 0x101036d @@ -1423,8 +1422,8 @@ package android { field public static final int tabWidgetStyle = 16842883; // 0x1010083 field public static final int tag = 16842961; // 0x10100d1 field public static final int targetActivity = 16843266; // 0x1010202 - field public static final int targetCellHeight; - field public static final int targetCellWidth; + field public static final int targetCellHeight = 16844341; // 0x1010635 + field public static final int targetCellWidth = 16844340; // 0x1010634 field public static final int targetClass = 16842799; // 0x101002f field @Deprecated public static final int targetDescriptions = 16843680; // 0x10103a0 field public static final int targetId = 16843740; // 0x10103dc @@ -1594,7 +1593,7 @@ package android { field public static final int useLevel = 16843167; // 0x101019f field public static final int userVisible = 16843409; // 0x1010291 field public static final int usesCleartextTraffic = 16844012; // 0x10104ec - field public static final int usesPermissionFlags; + field public static final int usesPermissionFlags = 16844356; // 0x1010644 field public static final int value = 16842788; // 0x1010024 field public static final int valueFrom = 16843486; // 0x10102de field public static final int valueTo = 16843487; // 0x10102df @@ -1649,10 +1648,10 @@ package android { field public static final int windowAllowReturnTransitionOverlap = 16843835; // 0x101043b field public static final int windowAnimationStyle = 16842926; // 0x10100ae field public static final int windowBackground = 16842836; // 0x1010054 - field public static final int windowBackgroundBlurRadius; + field public static final int windowBackgroundBlurRadius = 16844331; // 0x101062b field public static final int windowBackgroundFallback = 16844035; // 0x1010503 - field public static final int windowBlurBehindEnabled; - field public static final int windowBlurBehindRadius; + field public static final int windowBlurBehindEnabled = 16844316; // 0x101061c + field public static final int windowBlurBehindRadius = 16844315; // 0x101061b field public static final int windowClipToOutline = 16843947; // 0x10104ab field public static final int windowCloseOnTouchOutside = 16843611; // 0x101035b field public static final int windowContentOverlay = 16842841; // 0x1010059 @@ -1671,7 +1670,7 @@ package android { field public static final int windowHideAnimation = 16842935; // 0x10100b7 field public static final int windowIsFloating = 16842839; // 0x1010057 field public static final int windowIsTranslucent = 16842840; // 0x1010058 - field public static final int windowLayoutAffinity; + field public static final int windowLayoutAffinity = 16844313; // 0x1010619 field public static final int windowLayoutInDisplayCutoutMode = 16844166; // 0x1010586 field public static final int windowLightNavigationBar = 16844140; // 0x101056c field public static final int windowLightStatusBar = 16844000; // 0x10104e0 @@ -1690,11 +1689,11 @@ package android { field public static final int windowShowAnimation = 16842934; // 0x10100b6 field public static final int windowShowWallpaper = 16843410; // 0x1010292 field public static final int windowSoftInputMode = 16843307; // 0x101022b - field public static final int windowSplashScreenAnimatedIcon; - field public static final int windowSplashScreenAnimationDuration; - field public static final int windowSplashScreenBackground; - field public static final int windowSplashScreenBrandingImage; - field public static final int windowSplashScreenIconBackgroundColor; + field public static final int windowSplashScreenAnimatedIcon = 16844333; // 0x101062d + field public static final int windowSplashScreenAnimationDuration = 16844334; // 0x101062e + field public static final int windowSplashScreenBackground = 16844332; // 0x101062c + field public static final int windowSplashScreenBrandingImage = 16844335; // 0x101062f + field public static final int windowSplashScreenIconBackgroundColor = 16844336; // 0x1010630 field @Deprecated public static final int windowSplashscreenContent = 16844132; // 0x1010564 field @Deprecated public static final int windowSwipeToDismiss = 16843763; // 0x10103f3 field public static final int windowTitleBackgroundStyle = 16842844; // 0x101005c @@ -1742,71 +1741,71 @@ package android { field @Deprecated public static final int secondary_text_dark_nodisable = 17170438; // 0x1060006 field @Deprecated public static final int secondary_text_light = 17170439; // 0x1060007 field @Deprecated public static final int secondary_text_light_nodisable = 17170440; // 0x1060008 - field public static final int system_accent1_0; - field public static final int system_accent1_10; - field public static final int system_accent1_100; - field public static final int system_accent1_1000; - field public static final int system_accent1_200; - field public static final int system_accent1_300; - field public static final int system_accent1_400; - field public static final int system_accent1_50; - field public static final int system_accent1_500; - field public static final int system_accent1_600; - field public static final int system_accent1_700; - field public static final int system_accent1_800; - field public static final int system_accent1_900; - field public static final int system_accent2_0; - field public static final int system_accent2_10; - field public static final int system_accent2_100; - field public static final int system_accent2_1000; - field public static final int system_accent2_200; - field public static final int system_accent2_300; - field public static final int system_accent2_400; - field public static final int system_accent2_50; - field public static final int system_accent2_500; - field public static final int system_accent2_600; - field public static final int system_accent2_700; - field public static final int system_accent2_800; - field public static final int system_accent2_900; - field public static final int system_accent3_0; - field public static final int system_accent3_10; - field public static final int system_accent3_100; - field public static final int system_accent3_1000; - field public static final int system_accent3_200; - field public static final int system_accent3_300; - field public static final int system_accent3_400; - field public static final int system_accent3_50; - field public static final int system_accent3_500; - field public static final int system_accent3_600; - field public static final int system_accent3_700; - field public static final int system_accent3_800; - field public static final int system_accent3_900; - field public static final int system_neutral1_0; - field public static final int system_neutral1_10; - field public static final int system_neutral1_100; - field public static final int system_neutral1_1000; - field public static final int system_neutral1_200; - field public static final int system_neutral1_300; - field public static final int system_neutral1_400; - field public static final int system_neutral1_50; - field public static final int system_neutral1_500; - field public static final int system_neutral1_600; - field public static final int system_neutral1_700; - field public static final int system_neutral1_800; - field public static final int system_neutral1_900; - field public static final int system_neutral2_0; - field public static final int system_neutral2_10; - field public static final int system_neutral2_100; - field public static final int system_neutral2_1000; - field public static final int system_neutral2_200; - field public static final int system_neutral2_300; - field public static final int system_neutral2_400; - field public static final int system_neutral2_50; - field public static final int system_neutral2_500; - field public static final int system_neutral2_600; - field public static final int system_neutral2_700; - field public static final int system_neutral2_800; - field public static final int system_neutral2_900; + field public static final int system_accent1_0 = 17170487; // 0x1060037 + field public static final int system_accent1_10 = 17170488; // 0x1060038 + field public static final int system_accent1_100 = 17170490; // 0x106003a + field public static final int system_accent1_1000 = 17170499; // 0x1060043 + field public static final int system_accent1_200 = 17170491; // 0x106003b + field public static final int system_accent1_300 = 17170492; // 0x106003c + field public static final int system_accent1_400 = 17170493; // 0x106003d + field public static final int system_accent1_50 = 17170489; // 0x1060039 + field public static final int system_accent1_500 = 17170494; // 0x106003e + field public static final int system_accent1_600 = 17170495; // 0x106003f + field public static final int system_accent1_700 = 17170496; // 0x1060040 + field public static final int system_accent1_800 = 17170497; // 0x1060041 + field public static final int system_accent1_900 = 17170498; // 0x1060042 + field public static final int system_accent2_0 = 17170500; // 0x1060044 + field public static final int system_accent2_10 = 17170501; // 0x1060045 + field public static final int system_accent2_100 = 17170503; // 0x1060047 + field public static final int system_accent2_1000 = 17170512; // 0x1060050 + field public static final int system_accent2_200 = 17170504; // 0x1060048 + field public static final int system_accent2_300 = 17170505; // 0x1060049 + field public static final int system_accent2_400 = 17170506; // 0x106004a + field public static final int system_accent2_50 = 17170502; // 0x1060046 + field public static final int system_accent2_500 = 17170507; // 0x106004b + field public static final int system_accent2_600 = 17170508; // 0x106004c + field public static final int system_accent2_700 = 17170509; // 0x106004d + field public static final int system_accent2_800 = 17170510; // 0x106004e + field public static final int system_accent2_900 = 17170511; // 0x106004f + field public static final int system_accent3_0 = 17170513; // 0x1060051 + field public static final int system_accent3_10 = 17170514; // 0x1060052 + field public static final int system_accent3_100 = 17170516; // 0x1060054 + field public static final int system_accent3_1000 = 17170525; // 0x106005d + field public static final int system_accent3_200 = 17170517; // 0x1060055 + field public static final int system_accent3_300 = 17170518; // 0x1060056 + field public static final int system_accent3_400 = 17170519; // 0x1060057 + field public static final int system_accent3_50 = 17170515; // 0x1060053 + field public static final int system_accent3_500 = 17170520; // 0x1060058 + field public static final int system_accent3_600 = 17170521; // 0x1060059 + field public static final int system_accent3_700 = 17170522; // 0x106005a + field public static final int system_accent3_800 = 17170523; // 0x106005b + field public static final int system_accent3_900 = 17170524; // 0x106005c + field public static final int system_neutral1_0 = 17170461; // 0x106001d + field public static final int system_neutral1_10 = 17170462; // 0x106001e + field public static final int system_neutral1_100 = 17170464; // 0x1060020 + field public static final int system_neutral1_1000 = 17170473; // 0x1060029 + field public static final int system_neutral1_200 = 17170465; // 0x1060021 + field public static final int system_neutral1_300 = 17170466; // 0x1060022 + field public static final int system_neutral1_400 = 17170467; // 0x1060023 + field public static final int system_neutral1_50 = 17170463; // 0x106001f + field public static final int system_neutral1_500 = 17170468; // 0x1060024 + field public static final int system_neutral1_600 = 17170469; // 0x1060025 + field public static final int system_neutral1_700 = 17170470; // 0x1060026 + field public static final int system_neutral1_800 = 17170471; // 0x1060027 + field public static final int system_neutral1_900 = 17170472; // 0x1060028 + field public static final int system_neutral2_0 = 17170474; // 0x106002a + field public static final int system_neutral2_10 = 17170475; // 0x106002b + field public static final int system_neutral2_100 = 17170477; // 0x106002d + field public static final int system_neutral2_1000 = 17170486; // 0x1060036 + field public static final int system_neutral2_200 = 17170478; // 0x106002e + field public static final int system_neutral2_300 = 17170479; // 0x106002f + field public static final int system_neutral2_400 = 17170480; // 0x1060030 + field public static final int system_neutral2_50 = 17170476; // 0x106002c + field public static final int system_neutral2_500 = 17170481; // 0x1060031 + field public static final int system_neutral2_600 = 17170482; // 0x1060032 + field public static final int system_neutral2_700 = 17170483; // 0x1060033 + field public static final int system_neutral2_800 = 17170484; // 0x1060034 + field public static final int system_neutral2_900 = 17170485; // 0x1060035 field public static final int tab_indicator_text = 17170441; // 0x1060009 field @Deprecated public static final int tertiary_text_dark = 17170448; // 0x1060010 field @Deprecated public static final int tertiary_text_light = 17170449; // 0x1060011 @@ -1822,8 +1821,8 @@ package android { field public static final int dialog_min_width_minor = 17104900; // 0x1050004 field public static final int notification_large_icon_height = 17104902; // 0x1050006 field public static final int notification_large_icon_width = 17104901; // 0x1050005 - field public static final int system_app_widget_background_radius; - field public static final int system_app_widget_inner_radius; + field public static final int system_app_widget_background_radius = 17104904; // 0x1050008 + field public static final int system_app_widget_inner_radius = 17104905; // 0x1050009 field public static final int thumbnail_height = 17104897; // 0x1050001 field public static final int thumbnail_width = 17104898; // 0x1050002 } @@ -30797,7 +30796,7 @@ package android.os { field public static final int P = 28; // 0x1c field public static final int Q = 29; // 0x1d field public static final int R = 30; // 0x1e - field public static final int S = 10000; // 0x2710 + field public static final int S = 31; // 0x1f } public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable { diff --git a/core/api/removed.txt b/core/api/removed.txt index 57e1598b4c33..bf8642223ef5 100644 --- a/core/api/removed.txt +++ b/core/api/removed.txt @@ -1,12 +1,4 @@ // Signature format: 2.0 -package android { - - public static final class R.dimen { - field public static final int __removed_system_app_widget_internal_padding; - } - -} - package android.app { public class Notification implements android.os.Parcelable { diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 7072bbeade29..2d73aa67ed1a 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -317,10 +317,10 @@ package android { public static final class R.attr { field public static final int allowClearUserDataOnFailedRestore = 16844288; // 0x1010600 - field public static final int hotwordDetectionService; + field public static final int hotwordDetectionService = 16844326; // 0x1010626 field public static final int isVrOnly = 16844152; // 0x1010578 field public static final int minExtensionVersion = 16844305; // 0x1010611 - field public static final int playHomeTransitionSound; + field public static final int playHomeTransitionSound = 16844358; // 0x1010646 field public static final int requiredSystemPropertyName = 16844133; // 0x1010565 field public static final int requiredSystemPropertyValue = 16844134; // 0x1010566 field public static final int sdkVersion = 16844304; // 0x1010610 @@ -353,8 +353,8 @@ package android { } public static final class R.string { - field public static final int config_customMediaKeyDispatcher; - field public static final int config_customMediaSessionPolicyProvider; + field public static final int config_customMediaKeyDispatcher = 17039404; // 0x104002c + field public static final int config_customMediaSessionPolicyProvider = 17039405; // 0x104002d field public static final int config_defaultAssistant = 17039393; // 0x1040021 field public static final int config_defaultBrowser = 17039394; // 0x1040022 field public static final int config_defaultCallRedirection = 17039397; // 0x1040025 @@ -367,24 +367,24 @@ package android { field public static final int config_helpIntentNameKey = 17039390; // 0x104001e field public static final int config_helpPackageNameKey = 17039387; // 0x104001b field public static final int config_helpPackageNameValue = 17039388; // 0x104001c - field public static final int config_systemActivityRecognizer; - field public static final int config_systemAmbientAudioIntelligence; - field public static final int config_systemAudioIntelligence; - field public static final int config_systemAutomotiveCluster; - field public static final int config_systemAutomotiveProjection; - field public static final int config_systemCompanionDeviceProvider; - field public static final int config_systemContacts; + field public static final int config_systemActivityRecognizer = 17039416; // 0x1040038 + field public static final int config_systemAmbientAudioIntelligence = 17039411; // 0x1040033 + field public static final int config_systemAudioIntelligence = 17039412; // 0x1040034 + field public static final int config_systemAutomotiveCluster = 17039400; // 0x1040028 + field public static final int config_systemAutomotiveProjection = 17039401; // 0x1040029 + field public static final int config_systemCompanionDeviceProvider = 17039417; // 0x1040039 + field public static final int config_systemContacts = 17039403; // 0x104002b field public static final int config_systemGallery = 17039399; // 0x1040027 - field public static final int config_systemNotificationIntelligence; - field public static final int config_systemShell; - field public static final int config_systemSpeechRecognizer; - field public static final int config_systemTelevisionNotificationHandler; - field public static final int config_systemTextIntelligence; - field public static final int config_systemUi; - field public static final int config_systemUiIntelligence; - field public static final int config_systemVisualIntelligence; - field public static final int config_systemWellbeing; - field public static final int config_systemWifiCoexManager; + field public static final int config_systemNotificationIntelligence = 17039413; // 0x1040035 + field public static final int config_systemShell = 17039402; // 0x104002a + field public static final int config_systemSpeechRecognizer = 17039406; // 0x104002e + field public static final int config_systemTelevisionNotificationHandler = 17039409; // 0x1040031 + field public static final int config_systemTextIntelligence = 17039414; // 0x1040036 + field public static final int config_systemUi = 17039418; // 0x104003a + field public static final int config_systemUiIntelligence = 17039410; // 0x1040032 + field public static final int config_systemVisualIntelligence = 17039415; // 0x1040037 + field public static final int config_systemWellbeing = 17039408; // 0x1040030 + field public static final int config_systemWifiCoexManager = 17039407; // 0x104002f } public static final class R.style { diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 2f795f0e103f..2bae1907daec 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -51,7 +51,7 @@ package android { } public static final class R.attr { - field public static final int requestForegroundServiceExemption; + field public static final int requestForegroundServiceExemption = 16844362; // 0x101064a } public static final class R.bool { @@ -63,8 +63,8 @@ package android { public static final class R.string { field public static final int config_defaultAssistant = 17039393; // 0x1040021 field public static final int config_defaultDialer = 17039395; // 0x1040023 - field public static final int config_systemAutomotiveCluster; - field public static final int config_systemAutomotiveProjection; + field public static final int config_systemAutomotiveCluster = 17039400; // 0x1040028 + field public static final int config_systemAutomotiveProjection = 17039401; // 0x1040029 field public static final int config_systemGallery = 17039399; // 0x1040027 } @@ -201,6 +201,11 @@ package android.app { method @RequiresPermission("android.permission.MANAGE_APPOPS") public void setHistoryParameters(int, long, int); method @RequiresPermission("android.permission.MANAGE_APP_OPS_MODES") public void setMode(int, int, String, int); method public static int strOpToOp(@NonNull String); + field public static final int ATTRIBUTION_CHAIN_ID_NONE = -1; // 0xffffffff + field public static final int ATTRIBUTION_FLAGS_NONE = 0; // 0x0 + field public static final int ATTRIBUTION_FLAG_ACCESSOR = 1; // 0x1 + field public static final int ATTRIBUTION_FLAG_INTERMEDIARY = 2; // 0x2 + field public static final int ATTRIBUTION_FLAG_RECEIVER = 4; // 0x4 field public static final int HISTORICAL_MODE_DISABLED = 0; // 0x0 field public static final int HISTORICAL_MODE_ENABLED_ACTIVE = 1; // 0x1 field public static final int HISTORICAL_MODE_ENABLED_PASSIVE = 2; // 0x2 @@ -230,6 +235,10 @@ package android.app { method public void offsetBeginAndEndTime(long); } + public static interface AppOpsManager.OnOpActiveChangedListener { + method public default void onOpActiveChanged(@NonNull String, int, @NonNull String, @Nullable String, boolean, int, int); + } + public class BroadcastOptions { ctor public BroadcastOptions(@NonNull android.os.Bundle); method public int getMaxManifestReceiverApiLevel(); @@ -669,7 +678,7 @@ package android.content { public final class AttributionSource implements android.os.Parcelable { ctor public AttributionSource(int, @Nullable String, @Nullable String); - ctor public AttributionSource(int, @Nullable String, @Nullable String, @Nullable android.content.AttributionSource); + ctor public AttributionSource(int, @Nullable String, @Nullable String, @NonNull android.os.IBinder); ctor public AttributionSource(int, @Nullable String, @Nullable String, @Nullable java.util.Set<java.lang.String>, @Nullable android.content.AttributionSource); } @@ -2041,7 +2050,7 @@ package android.permission { public final class PermissionManager { method @NonNull @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public java.util.List<android.permission.PermGroupUsage> getIndicatorAppOpUsageData(); method @NonNull @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public java.util.List<android.permission.PermGroupUsage> getIndicatorAppOpUsageData(boolean); - method @NonNull public android.content.AttributionSource registerAttributionSource(@NonNull android.content.AttributionSource); + method public void registerAttributionSource(@NonNull android.content.AttributionSource); } } diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 6d2d0238ed37..91e2d88ad7cb 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -779,6 +779,9 @@ public class ActivityManager { /** @hide requestType for assist context: generate full AssistStructure for autofill. */ public static final int ASSIST_CONTEXT_AUTOFILL = 2; + /** @hide requestType for assist context: generate AssistContent but not AssistStructure. */ + public static final int ASSIST_CONTEXT_CONTENT = 3; + /** @hide Flag for registerUidObserver: report changes in process state. */ public static final int UID_OBSERVER_PROCSTATE = 1<<0; diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 7149096ee806..02ab3143eed9 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -3843,6 +3843,8 @@ public final class ActivityThread extends ClientTransactionHandler // - it does not call onProvideAssistData() // - it needs an IAutoFillCallback boolean forAutofill = cmd.requestType == ActivityManager.ASSIST_CONTEXT_AUTOFILL; + // When only the AssistContent is requested, omit the AsssistStructure + boolean requestedOnlyContent = cmd.requestType == ActivityManager.ASSIST_CONTEXT_CONTENT; // TODO: decide if lastSessionId logic applies to autofill sessions if (mLastSessionId != cmd.sessionId) { @@ -3869,8 +3871,11 @@ public final class ActivityThread extends ClientTransactionHandler r.activity.onProvideAssistData(data); referrer = r.activity.onProvideReferrer(); } - if (cmd.requestType == ActivityManager.ASSIST_CONTEXT_FULL || forAutofill) { - structure = new AssistStructure(r.activity, forAutofill, cmd.flags); + if (cmd.requestType == ActivityManager.ASSIST_CONTEXT_FULL || forAutofill + || requestedOnlyContent) { + if (!requestedOnlyContent) { + structure = new AssistStructure(r.activity, forAutofill, cmd.flags); + } Intent activityIntent = r.activity.getIntent(); boolean notSecure = r.window == null || (r.window.getAttributes().flags @@ -3892,18 +3897,21 @@ public final class ActivityThread extends ClientTransactionHandler r.activity.onProvideAssistContent(content); } } - - } - if (structure == null) { - structure = new AssistStructure(); } - // TODO: decide if lastSessionId logic applies to autofill sessions + if (!requestedOnlyContent) { + if (structure == null) { + structure = new AssistStructure(); + } + + // TODO: decide if lastSessionId logic applies to autofill sessions - structure.setAcquisitionStartTime(startTime); - structure.setAcquisitionEndTime(SystemClock.uptimeMillis()); + structure.setAcquisitionStartTime(startTime); + structure.setAcquisitionEndTime(SystemClock.uptimeMillis()); + + mLastAssistStructures.add(new WeakReference<>(structure)); + } - mLastAssistStructures.add(new WeakReference<>(structure)); IActivityTaskManager mgr = ActivityTaskManager.getService(); try { mgr.reportAssistContextExtras(cmd.requestToken, data, structure, content, referrer); diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 1415212ef07d..eb14c11e7e3c 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -708,6 +708,62 @@ public class AppOpsManager { } } + /** + * Attribution chain flag: specifies that this is the accessor. When + * an app A accesses the data that is then passed to app B that is then + * passed to C, we call app A accessor, app B intermediary, and app C + * receiver. If A accesses the data for itself, then it is the accessor + * and the receiver. + * @hide + */ + @TestApi + public static final int ATTRIBUTION_FLAG_ACCESSOR = 0x1; + + /** + * Attribution chain flag: specifies that this is the intermediary. When + * an app A accesses the data that is then passed to app B that is then + * passed to C, we call app A accessor, app B intermediary, and app C + * receiver. If A accesses the data for itself, then it is the accessor + * and the receiver. + * @hide + */ + @TestApi + public static final int ATTRIBUTION_FLAG_INTERMEDIARY = 0x2; + + /** + * Attribution chain flag: specifies that this is the receiver. When + * an app A accesses the data that is then passed to app B that is then + * passed to C, we call app A accessor, app B intermediary, and app C + * receiver. If A accesses the data for itself, then it is the accessor + * and the receiver. + * @hide + */ + @TestApi + public static final int ATTRIBUTION_FLAG_RECEIVER = 0x4; + + /** + * No attribution flags. + * @hide + */ + @TestApi + public static final int ATTRIBUTION_FLAGS_NONE = 0x0; + + /** + * No attribution chain id. + * @hide + */ + @TestApi + public static final int ATTRIBUTION_CHAIN_ID_NONE = -1; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(flag = true, prefix = { "FLAG_" }, value = { + ATTRIBUTION_FLAG_ACCESSOR, + ATTRIBUTION_FLAG_INTERMEDIARY, + ATTRIBUTION_FLAG_RECEIVER + }) + public @interface AttributionFlags {} + // These constants are redefined here to work around a metalava limitation/bug where // @IntDef is not able to see @hide symbols when they are hidden via package hiding: // frameworks/base/core/java/com/android/internal/package.html @@ -7063,6 +7119,25 @@ public class AppOpsManager { */ void onOpActiveChanged(@NonNull String op, int uid, @NonNull String packageName, boolean active); + + /** + * Called when the active state of an app-op changes. + * + * @param op The operation that changed. + * @param uid The UID performing the operation. + * @param packageName The package performing the operation. + * @param attributionTag The operation's attribution tag. + * @param active Whether the operation became active or inactive. + * @param attributionFlags the attribution flags for this operation. + * @param attributionChainId the unique id of the attribution chain this op is a part of. + * @hide + */ + @TestApi + default void onOpActiveChanged(@NonNull String op, int uid, @NonNull String packageName, + @Nullable String attributionTag, boolean active, @AttributionFlags + int attributionFlags, int attributionChainId) { + onOpActiveChanged(op, uid, packageName, active); + } } /** @@ -7684,14 +7759,17 @@ public class AppOpsManager { } cb = new IAppOpsActiveCallback.Stub() { @Override - public void opActiveChanged(int op, int uid, String packageName, boolean active) { + public void opActiveChanged(int op, int uid, String packageName, + String attributionTag, boolean active, @AttributionFlags + int attributionFlags, int attributionChainId) { executor.execute(() -> { if (callback instanceof OnOpActiveChangedInternalListener) { ((OnOpActiveChangedInternalListener) callback).onOpActiveChanged(op, uid, packageName, active); } if (sOpToString[op] != null) { - callback.onOpActiveChanged(sOpToString[op], uid, packageName, active); + callback.onOpActiveChanged(sOpToString[op], uid, packageName, + attributionTag, active, attributionFlags, attributionChainId); } }); } @@ -8169,8 +8247,9 @@ public class AppOpsManager { public int noteProxyOp(int op, @Nullable String proxiedPackageName, int proxiedUid, @Nullable String proxiedAttributionTag, @Nullable String message) { return noteProxyOp(op, new AttributionSource(mContext.getAttributionSource(), - new AttributionSource(proxiedUid, proxiedPackageName, proxiedAttributionTag)), - message, /*skipProxyOperation*/ false); + new AttributionSource(proxiedUid, proxiedPackageName, proxiedAttributionTag, + mContext.getAttributionSource().getToken())), message, + /*skipProxyOperation*/ false); } /** @@ -8255,8 +8334,8 @@ public class AppOpsManager { int proxiedUid, @Nullable String proxiedAttributionTag, @Nullable String message) { return noteProxyOpNoThrow(strOpToOp(op), new AttributionSource( mContext.getAttributionSource(), new AttributionSource(proxiedUid, - proxiedPackageName, proxiedAttributionTag)), message, - /*skipProxyOperation*/ false); + proxiedPackageName, proxiedAttributionTag, mContext.getAttributionSource() + .getToken())), message,/*skipProxyOperation*/ false); } /** @@ -8592,6 +8671,29 @@ public class AppOpsManager { */ public int startOpNoThrow(int op, int uid, @NonNull String packageName, boolean startIfModeDefault, @Nullable String attributionTag, @Nullable String message) { + return startOpNoThrow(mContext.getAttributionSource().getToken(), op, uid, packageName, + startIfModeDefault, attributionTag, message); + } + + /** + * @see #startOpNoThrow(String, int, String, String, String) + * + * @hide + */ + public int startOpNoThrow(@NonNull IBinder token, int op, int uid, @NonNull String packageName, + boolean startIfModeDefault, @Nullable String attributionTag, @Nullable String message) { + return startOpNoThrow(token, op, uid, packageName, startIfModeDefault, attributionTag, + message, ATTRIBUTION_FLAGS_NONE, ATTRIBUTION_CHAIN_ID_NONE); + } + + /** + * @see #startOpNoThrow(String, int, String, String, String) + * + * @hide + */ + public int startOpNoThrow(@NonNull IBinder token, int op, int uid, @NonNull String packageName, + boolean startIfModeDefault, @Nullable String attributionTag, @Nullable String message, + @AttributionFlags int attributionFlags, int attributionChainId) { try { collectNoteOpCallsForValidation(op); int collectionMode = getNotedOpCollectionMode(uid, packageName, op); @@ -8604,9 +8706,9 @@ public class AppOpsManager { } } - SyncNotedAppOp syncOp = mService.startOperation(getClientId(), op, uid, packageName, + SyncNotedAppOp syncOp = mService.startOperation(token, op, uid, packageName, attributionTag, startIfModeDefault, collectionMode == COLLECT_ASYNC, message, - shouldCollectMessage); + shouldCollectMessage, attributionFlags, attributionChainId); if (syncOp.getOpMode() == MODE_ALLOWED) { if (collectionMode == COLLECT_SELF) { @@ -8643,8 +8745,9 @@ public class AppOpsManager { public int startProxyOp(@NonNull String op, int proxiedUid, @NonNull String proxiedPackageName, @Nullable String proxiedAttributionTag, @Nullable String message) { return startProxyOp(op, new AttributionSource(mContext.getAttributionSource(), - new AttributionSource(proxiedUid, proxiedPackageName, proxiedAttributionTag)), - message, /*skipProxyOperation*/ false); + new AttributionSource(proxiedUid, proxiedPackageName, proxiedAttributionTag, + mContext.getAttributionSource().getToken())), message, + /*skipProxyOperation*/ false); } /** @@ -8690,8 +8793,9 @@ public class AppOpsManager { @Nullable String message) { return startProxyOpNoThrow(AppOpsManager.strOpToOp(op), new AttributionSource( mContext.getAttributionSource(), new AttributionSource(proxiedUid, - proxiedPackageName, proxiedAttributionTag)), message, - /*skipProxyOperation*/ false); + proxiedPackageName, proxiedAttributionTag, + mContext.getAttributionSource().getToken())), message, + /*skipProxyOperation*/ false); } /** @@ -8705,6 +8809,23 @@ public class AppOpsManager { */ public int startProxyOpNoThrow(int op, @NonNull AttributionSource attributionSource, @Nullable String message, boolean skipProxyOperation) { + return startProxyOpNoThrow(op, attributionSource, message, skipProxyOperation, + ATTRIBUTION_FLAGS_NONE, ATTRIBUTION_FLAGS_NONE, ATTRIBUTION_CHAIN_ID_NONE); + } + + /** + * Like {@link #startProxyOp(String, AttributionSource, String)} but instead + * of throwing a {@link SecurityException} it returns {@link #MODE_ERRORED} and + * the checks is for the attribution chain specified by the {@link AttributionSource}. + * + * @see #startProxyOp(String, AttributionSource, String) + * + * @hide + */ + public int startProxyOpNoThrow(int op, @NonNull AttributionSource attributionSource, + @Nullable String message, boolean skipProxyOperation, @AttributionFlags + int proxyAttributionFlags, @AttributionFlags int proxiedAttributionFlags, + int attributionChainId) { try { collectNoteOpCallsForValidation(op); int collectionMode = getNotedOpCollectionMode( @@ -8719,9 +8840,10 @@ public class AppOpsManager { } } - SyncNotedAppOp syncOp = mService.startProxyOperation(getClientId(), op, + SyncNotedAppOp syncOp = mService.startProxyOperation(op, attributionSource, false, collectionMode == COLLECT_ASYNC, message, - shouldCollectMessage, skipProxyOperation); + shouldCollectMessage, skipProxyOperation, proxyAttributionFlags, + proxiedAttributionFlags, attributionChainId); if (syncOp.getOpMode() == MODE_ALLOWED) { if (collectionMode == COLLECT_SELF) { @@ -8785,8 +8907,18 @@ public class AppOpsManager { */ public void finishOp(int op, int uid, @NonNull String packageName, @Nullable String attributionTag) { + finishOp(mContext.getAttributionSource().getToken(), op, uid, packageName, attributionTag); + } + + /** + * @see #finishOp(String, int, String, String) + * + * @hide + */ + public void finishOp(IBinder token, int op, int uid, @NonNull String packageName, + @Nullable String attributionTag) { try { - mService.finishOperation(getClientId(), op, uid, packageName, attributionTag); + mService.finishOperation(token, op, uid, packageName, attributionTag); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -8807,23 +8939,26 @@ public class AppOpsManager { public void finishProxyOp(@NonNull String op, int proxiedUid, @NonNull String proxiedPackageName, @Nullable String proxiedAttributionTag) { finishProxyOp(op, new AttributionSource(mContext.getAttributionSource(), - new AttributionSource(proxiedUid, proxiedPackageName, proxiedAttributionTag))); + new AttributionSource(proxiedUid, proxiedPackageName, proxiedAttributionTag, + mContext.getAttributionSource().getToken())), /*skipProxyOperation*/ false); } /** * Report that an application is no longer performing an operation that had previously - * been started with {@link #startProxyOp(String, AttributionSource, String)}. There is no - * validation of input or result; the parameters supplied here must be the exact same ones - * previously passed in when starting the operation. + * been started with {@link #startProxyOp(String, AttributionSource, String, boolean)}. There + * is no validation of input or result; the parameters supplied here must be the exact same + * ones previously passed in when starting the operation. * * @param op The operation which was started * @param attributionSource The permission identity for which to finish + * @param skipProxyOperation Whether to skip the proxy finish. * * @hide */ - public void finishProxyOp(@NonNull String op, @NonNull AttributionSource attributionSource) { + public void finishProxyOp(@NonNull String op, @NonNull AttributionSource attributionSource, + boolean skipProxyOperation) { try { - mService.finishProxyOperation(getClientId(), strOpToOp(op), attributionSource); + mService.finishProxyOperation(strOpToOp(op), attributionSource, skipProxyOperation); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/app/AppOpsManagerInternal.java b/core/java/android/app/AppOpsManagerInternal.java index 2de0ddb17646..a757e32d0d75 100644 --- a/core/java/android/app/AppOpsManagerInternal.java +++ b/core/java/android/app/AppOpsManagerInternal.java @@ -16,6 +16,7 @@ package android.app; +import android.app.AppOpsManager.AttributionFlags; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.AttributionSource; @@ -24,13 +25,13 @@ import android.util.SparseArray; import android.util.SparseIntArray; import com.android.internal.app.IAppOpsCallback; +import com.android.internal.util.function.DecFunction; import com.android.internal.util.function.HeptFunction; import com.android.internal.util.function.HexFunction; -import com.android.internal.util.function.NonaFunction; -import com.android.internal.util.function.OctFunction; import com.android.internal.util.function.QuadFunction; import com.android.internal.util.function.QuintFunction; import com.android.internal.util.function.TriFunction; +import com.android.internal.util.function.UndecFunction; /** * App ops service local interface. @@ -52,8 +53,8 @@ public abstract class AppOpsManagerInternal { * @return The app op check result. */ int checkOperation(int code, int uid, String packageName, @Nullable String attributionTag, - boolean raw, - QuintFunction<Integer, Integer, String, String, Boolean, Integer> superImpl); + boolean raw, QuintFunction<Integer, Integer, String, String, Boolean, Integer> + superImpl); /** * Allows overriding check audio operation behavior. @@ -116,20 +117,22 @@ public abstract class AppOpsManagerInternal { * @param shouldCollectAsyncNotedOp If an {@link AsyncNotedAppOp} should be collected * @param message The message in the async noted op * @param shouldCollectMessage whether to collect messages + * @param attributionFlags the attribution flags for this operation. + * @param attributionChainId the unique id of the attribution chain this op is a part of. * @param superImpl The super implementation. * @return The app op note result. */ SyncNotedAppOp startOperation(IBinder token, int code, int uid, @Nullable String packageName, @Nullable String attributionTag, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, - @Nullable String message, boolean shouldCollectMessage, @NonNull NonaFunction< - IBinder, Integer, Integer, String, String, Boolean, Boolean, String, - Boolean, SyncNotedAppOp> superImpl); + @Nullable String message, boolean shouldCollectMessage, + @AttributionFlags int attributionFlags, int attributionChainId, + @NonNull UndecFunction<IBinder, Integer, Integer, String, String, Boolean, + Boolean, String, Boolean, Integer, Integer, SyncNotedAppOp> superImpl); /** * Allows overriding start proxy operation behavior. * - * @param token The client state. * @param code The op code to start. * @param attributionSource The permission identity of the caller. * @param startIfModeDefault Whether to start the op of the mode is default. @@ -137,26 +140,29 @@ public abstract class AppOpsManagerInternal { * @param message The message in the async noted op * @param shouldCollectMessage whether to collect messages * @param skipProxyOperation Whether to skip the proxy portion of the operation + * @param proxyAttributionFlags The attribution flags for the proxy. + * @param proxiedAttributionFlags The attribution flags for the proxied. + * @oaram attributionChainId The id of the attribution chain this operation is a part of. * @param superImpl The super implementation. * @return The app op note result. */ - SyncNotedAppOp startProxyOperation(IBinder token, int code, - @NonNull AttributionSource attributionSource, boolean startIfModeDefault, - boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage, - boolean skipProxyOperation, @NonNull OctFunction<IBinder, Integer, - AttributionSource, Boolean, Boolean, String, Boolean, Boolean, + SyncNotedAppOp startProxyOperation(int code, @NonNull AttributionSource attributionSource, + boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, String message, + boolean shouldCollectMessage, boolean skipProxyOperation, @AttributionFlags + int proxyAttributionFlags, @AttributionFlags int proxiedAttributionFlags, + int attributionChainId, @NonNull DecFunction<Integer, AttributionSource, Boolean, + Boolean, String, Boolean, Boolean, Integer, Integer, Integer, SyncNotedAppOp> superImpl); /** * Allows overriding finish proxy op. * - * @param clientId Client state token. * @param code The op code to finish. * @param attributionSource The permission identity of the caller. */ - void finishProxyOperation(IBinder clientId, int code, - @NonNull AttributionSource attributionSource, - @NonNull TriFunction<IBinder, Integer, AttributionSource, Void> superImpl); + void finishProxyOperation(int code, @NonNull AttributionSource attributionSource, + boolean skipProxyOperation, + @NonNull TriFunction<Integer, AttributionSource, Boolean, Void> superImpl); } /** diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index daef8b1eae08..16b6ea5bcf42 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -3157,13 +3157,7 @@ class ContextImpl extends Context { // If we want to access protected data on behalf of another app we need to // tell the OS that we opt in to participate in the attribution chain. if (nextAttributionSource != null) { - // If an app happened to stub the internal OS for testing the registration method - // can return null. In this case we keep the current untrusted attribution source. - final AttributionSource registeredAttributionSource = getSystemService( - PermissionManager.class).registerAttributionSource(attributionSource); - if (registeredAttributionSource != null) { - return registeredAttributionSource; - } + getSystemService(PermissionManager.class).registerAttributionSource(attributionSource); } return attributionSource; } diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 64b100f838ba..30ddd20b312c 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -9804,10 +9804,6 @@ public class Notification implements Parcelable * <p>Apps sending bubbles may set this flag so that the bubble is posted <b>without</b> * the associated notification in the notification shade.</p> * - * <p>Apps sending bubbles can only apply this flag when the app is in the foreground, - * otherwise the flag is not respected. The app is considered foreground if it is visible - * and on the screen, note that a foreground service does not qualify.</p> - * * <p>Generally this flag should only be set by the app if the user has performed an * action to request or create a bubble, or if the user has seen the content in the * notification and the notification is no longer relevant. </p> @@ -9958,10 +9954,6 @@ public class Notification implements Parcelable * <p>Apps sending bubbles may set this flag so that the bubble is posted <b>without</b> * the associated notification in the notification shade.</p> * - * <p>Apps sending bubbles can only apply this flag when the app is in the foreground, - * otherwise the flag is not respected. The app is considered foreground if it is visible - * and on the screen, note that a foreground service does not qualify.</p> - * * <p>Generally the app should only set this flag if the user has performed an * action to request or create a bubble, or if the user has seen the content in the * notification and the notification is no longer relevant. </p> @@ -10349,11 +10341,6 @@ public class Notification implements Parcelable * Sets whether the bubble will be posted <b>without</b> the associated notification in * the notification shade. * - * <p>This flag has no effect if the app posting the bubble is not in the foreground. - * The app is considered foreground if it is visible and on the screen, note that - * a foreground service does not qualify. - * </p> - * * <p>Generally, this flag should only be set if the user has performed an action to * request or create a bubble, or if the user has seen the content in the notification * and the notification is no longer relevant.</p> diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index 91dad2a1f13c..871d48b07a20 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -186,6 +186,7 @@ import android.os.incremental.IIncrementalService; import android.os.incremental.IncrementalManager; import android.os.storage.StorageManager; import android.permission.LegacyPermissionManager; +import android.permission.PermissionCheckerManager; import android.permission.PermissionControllerManager; import android.permission.PermissionManager; import android.print.IPrintManager; @@ -1334,6 +1335,14 @@ public final class SystemServiceRegistry { ctx.getMainThreadHandler()); }}); + registerService(Context.PERMISSION_CHECKER_SERVICE, PermissionCheckerManager.class, + new CachedServiceFetcher<PermissionCheckerManager>() { + @Override + public PermissionCheckerManager createService(ContextImpl ctx) + throws ServiceNotFoundException { + return new PermissionCheckerManager(ctx.getOuterContext()); + }}); + registerService(Context.DYNAMIC_SYSTEM_SERVICE, DynamicSystemManager.class, new CachedServiceFetcher<DynamicSystemManager>() { @Override diff --git a/core/java/android/content/AttributionSource.java b/core/java/android/content/AttributionSource.java index 7ab731f15ad2..1dda6374a474 100644 --- a/core/java/android/content/AttributionSource.java +++ b/core/java/android/content/AttributionSource.java @@ -21,6 +21,7 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.TestApi; +import android.app.ActivityThread; import android.os.Binder; import android.os.Build; import android.os.IBinder; @@ -94,14 +95,22 @@ public final class AttributionSource implements Parcelable { @TestApi public AttributionSource(int uid, @Nullable String packageName, @Nullable String attributionTag) { - this(uid, packageName, attributionTag, /*next*/ null); + this(uid, packageName, attributionTag, new Binder()); } /** @hide */ @TestApi public AttributionSource(int uid, @Nullable String packageName, - @Nullable String attributionTag, @Nullable AttributionSource next) { - this(uid, packageName, attributionTag, /*renouncedPermissions*/ null, next); + @Nullable String attributionTag, @NonNull IBinder token) { + this(uid, packageName, attributionTag, token, /*renouncedPermissions*/ null, + /*next*/ null); + } + + /** @hide */ + public AttributionSource(int uid, @Nullable String packageName, + @Nullable String attributionTag, @NonNull IBinder token, + @Nullable AttributionSource next) { + this(uid, packageName, attributionTag, token, /*renouncedPermissions*/ null, next); } /** @hide */ @@ -109,28 +118,32 @@ public final class AttributionSource implements Parcelable { public AttributionSource(int uid, @Nullable String packageName, @Nullable String attributionTag, @Nullable Set<String> renouncedPermissions, @Nullable AttributionSource next) { - this(uid, packageName, attributionTag, /*token*/ null, (renouncedPermissions != null) + this(uid, packageName, attributionTag, (renouncedPermissions != null) ? renouncedPermissions.toArray(new String[0]) : null, next); } /** @hide */ - public AttributionSource(@NonNull AttributionSource current, - @Nullable AttributionSource next) { + public AttributionSource(@NonNull AttributionSource current, @Nullable AttributionSource next) { this(current.getUid(), current.getPackageName(), current.getAttributionTag(), - /*token*/ null, /*renouncedPermissions*/ null, next); + current.getToken(), current.mAttributionSourceState.renouncedPermissions, next); } AttributionSource(int uid, @Nullable String packageName, @Nullable String attributionTag, - @Nullable IBinder token, @Nullable String[] renouncedPermissions, + @Nullable String[] renouncedPermissions, @Nullable AttributionSource next) { + this(uid, packageName, attributionTag, new Binder(), renouncedPermissions, next); + } + + AttributionSource(int uid, @Nullable String packageName, @Nullable String attributionTag, + @NonNull IBinder token, @Nullable String[] renouncedPermissions, @Nullable AttributionSource next) { mAttributionSourceState = new AttributionSourceState(); mAttributionSourceState.uid = uid; + mAttributionSourceState.token = token; mAttributionSourceState.packageName = packageName; mAttributionSourceState.attributionTag = attributionTag; - mAttributionSourceState.token = token; mAttributionSourceState.renouncedPermissions = renouncedPermissions; mAttributionSourceState.next = (next != null) ? new AttributionSourceState[] - {next.mAttributionSourceState} : null; + {next.mAttributionSourceState} : new AttributionSourceState[0]; } AttributionSource(@NonNull Parcel in) { @@ -145,18 +158,12 @@ public final class AttributionSource implements Parcelable { /** @hide */ public AttributionSource withNextAttributionSource(@Nullable AttributionSource next) { return new AttributionSource(getUid(), getPackageName(), getAttributionTag(), - getToken(), mAttributionSourceState.renouncedPermissions, next); - } - - /** @hide */ - public AttributionSource withToken(@Nullable IBinder token) { - return new AttributionSource(getUid(), getPackageName(), getAttributionTag(), - token, mAttributionSourceState.renouncedPermissions, getNext()); + mAttributionSourceState.renouncedPermissions, next); } /** @hide */ public AttributionSource withPackageName(@Nullable String packageName) { - return new AttributionSource(getUid(), packageName, getAttributionTag(), getToken(), + return new AttributionSource(getUid(), packageName, getAttributionTag(), mAttributionSourceState.renouncedPermissions, getNext()); } @@ -165,6 +172,45 @@ public final class AttributionSource implements Parcelable { return mAttributionSourceState; } + /** @hide */ + public @NonNull ScopedParcelState asScopedParcelState() { + return new ScopedParcelState(this); + } + + /** @hide */ + public static AttributionSource myAttributionSource() { + return new AttributionSource(Process.myUid(), ActivityThread.currentOpPackageName(), + /*attributionTag*/ null, (String[]) /*renouncedPermissions*/ null, /*next*/ null); + } + + /** + * This is a scoped object that exposes the content of an attribution source + * as a parcel. This is useful when passing one to native and avoid custom + * conversion logic from Java to native state that needs to be kept in sync + * as attribution source evolves. This way we use the same logic for passing + * to native as the ones for passing in an IPC - in both cases this is the + * same auto generated code. + * + * @hide + */ + public static class ScopedParcelState implements AutoCloseable { + private final Parcel mParcel; + + public @NonNull Parcel getParcel() { + return mParcel; + } + + public ScopedParcelState(AttributionSource attributionSource) { + mParcel = Parcel.obtain(); + attributionSource.writeToParcel(mParcel, 0); + mParcel.setDataPosition(0); + } + + public void close() { + mParcel.recycle(); + } + } + /** * If you are handling an IPC and you don't trust the caller you need to validate * whether the attribution source is one for the calling app to prevent the caller @@ -209,7 +255,8 @@ public final class AttributionSource implements Parcelable { "attributionTag = " + mAttributionSourceState.attributionTag + ", " + "token = " + mAttributionSourceState.token + ", " + "next = " + (mAttributionSourceState.next != null - ? mAttributionSourceState.next[0]: null) + + && mAttributionSourceState.next.length > 0 + ? mAttributionSourceState.next[0] : null) + " }"; } return super.toString(); @@ -221,7 +268,8 @@ public final class AttributionSource implements Parcelable { * @hide */ public int getNextUid() { - if (mAttributionSourceState.next != null) { + if (mAttributionSourceState.next != null + && mAttributionSourceState.next.length > 0) { return mAttributionSourceState.next[0].uid; } return Process.INVALID_UID; @@ -233,26 +281,42 @@ public final class AttributionSource implements Parcelable { * @hide */ public @Nullable String getNextPackageName() { - if (mAttributionSourceState.next != null) { + if (mAttributionSourceState.next != null + && mAttributionSourceState.next.length > 0) { return mAttributionSourceState.next[0].packageName; } return null; } /** - * @return The nexxt package's attribution tag that would receive + * @return The next package's attribution tag that would receive * the permission protected data. * * @hide */ public @Nullable String getNextAttributionTag() { - if (mAttributionSourceState.next != null) { + if (mAttributionSourceState.next != null + && mAttributionSourceState.next.length > 0) { return mAttributionSourceState.next[0].attributionTag; } return null; } /** + * @return The next package's token that would receive + * the permission protected data. + * + * @hide + */ + public @Nullable IBinder getNextToken() { + if (mAttributionSourceState.next != null + && mAttributionSourceState.next.length > 0) { + return mAttributionSourceState.next[0].token; + } + return null; + } + + /** * Checks whether this attribution source can be trusted. That is whether * the app it refers to created it and provided to the attribution chain. * @@ -311,7 +375,7 @@ public final class AttributionSource implements Parcelable { * * @hide */ - public @Nullable IBinder getToken() { + public @NonNull IBinder getToken() { return mAttributionSourceState.token; } @@ -319,7 +383,8 @@ public final class AttributionSource implements Parcelable { * The next app to receive the permission protected data. */ public @Nullable AttributionSource getNext() { - if (mNextCached == null && mAttributionSourceState.next != null) { + if (mNextCached == null && mAttributionSourceState.next != null + && mAttributionSourceState.next.length > 0) { mNextCached = new AttributionSource(mAttributionSourceState.next[0]); } return mNextCached; @@ -442,7 +507,7 @@ public final class AttributionSource implements Parcelable { @RequiresPermission(android.Manifest.permission.RENOUNCE_PERMISSIONS) public @NonNull Builder setRenouncedPermissions(@Nullable Set<String> value) { checkNotUsed(); - mBuilderFieldsSet |= 0x10; + mBuilderFieldsSet |= 0x8; mAttributionSourceState.renouncedPermissions = (value != null) ? value.toArray(new String[0]) : null; return this; @@ -453,9 +518,9 @@ public final class AttributionSource implements Parcelable { */ public @NonNull Builder setNext(@Nullable AttributionSource value) { checkNotUsed(); - mBuilderFieldsSet |= 0x20; + mBuilderFieldsSet |= 0x10; mAttributionSourceState.next = (value != null) ? new AttributionSourceState[] - {value.mAttributionSourceState} : null; + {value.mAttributionSourceState} : mAttributionSourceState.next; return this; } @@ -471,14 +536,16 @@ public final class AttributionSource implements Parcelable { mAttributionSourceState.attributionTag = null; } if ((mBuilderFieldsSet & 0x8) == 0) { - mAttributionSourceState.token = null; - } - if ((mBuilderFieldsSet & 0x10) == 0) { mAttributionSourceState.renouncedPermissions = null; } - if ((mBuilderFieldsSet & 0x20) == 0) { + if ((mBuilderFieldsSet & 0x10) == 0) { mAttributionSourceState.next = null; } + mAttributionSourceState.token = new Binder(); + if (mAttributionSourceState.next == null) { + // The NDK aidl backend doesn't support null parcelable arrays. + mAttributionSourceState.next = new AttributionSourceState[0]; + } return new AttributionSource(mAttributionSourceState); } diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java index 88686a309ee4..dc29c5e25f3c 100644 --- a/core/java/android/content/ContentProvider.java +++ b/core/java/android/content/ContentProvider.java @@ -49,6 +49,7 @@ import android.os.RemoteException; import android.os.Trace; import android.os.UserHandle; import android.os.storage.StorageManager; +import android.permission.PermissionCheckerManager; import android.text.TextUtils; import android.util.Log; @@ -670,7 +671,7 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall } } - @PermissionChecker.PermissionResult + @PermissionCheckerManager.PermissionResult private void enforceFilePermission(@NonNull AttributionSource attributionSource, Uri uri, String mode) throws FileNotFoundException, SecurityException { @@ -687,7 +688,7 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall } } - @PermissionChecker.PermissionResult + @PermissionCheckerManager.PermissionResult private int enforceReadPermission(@NonNull AttributionSource attributionSource, Uri uri) throws SecurityException { final int result = enforceReadPermissionInner(uri, attributionSource); @@ -705,7 +706,7 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall return PermissionChecker.PERMISSION_GRANTED; } - @PermissionChecker.PermissionResult + @PermissionCheckerManager.PermissionResult private int enforceWritePermission(@NonNull AttributionSource attributionSource, Uri uri) throws SecurityException { final int result = enforceWritePermissionInner(uri, attributionSource); @@ -738,7 +739,7 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall * Verify that calling app holds both the given permission and any app-op * associated with that permission. */ - @PermissionChecker.PermissionResult + @PermissionCheckerManager.PermissionResult private int checkPermission(String permission, @NonNull AttributionSource attributionSource) { if (Binder.getCallingPid() == Process.myPid()) { @@ -753,7 +754,7 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall } /** {@hide} */ - @PermissionChecker.PermissionResult + @PermissionCheckerManager.PermissionResult protected int enforceReadPermissionInner(Uri uri, @NonNull AttributionSource attributionSource) throws SecurityException { final Context context = getContext(); @@ -836,7 +837,7 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall } /** {@hide} */ - @PermissionChecker.PermissionResult + @PermissionCheckerManager.PermissionResult protected int enforceWritePermissionInner(Uri uri, @NonNull AttributionSource attributionSource) throws SecurityException { final Context context = getContext(); diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 886cd7f48d35..ea0e321377c8 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -4836,6 +4836,14 @@ public abstract class Context { public static final String PERMISSION_CONTROLLER_SERVICE = "permission_controller"; /** + * Official published name of the (internal) permission checker service. + * + * @see #getSystemService(String) + * @hide + */ + public static final String PERMISSION_CHECKER_SERVICE = "permission_checker"; + + /** * Use with {@link #getSystemService(String) to retrieve an * {@link android.apphibernation.AppHibernationManager}} for * communicating with the hibernation service. diff --git a/core/java/android/content/PermissionChecker.java b/core/java/android/content/PermissionChecker.java index 66e088359459..a167cb3d851f 100644 --- a/core/java/android/content/PermissionChecker.java +++ b/core/java/android/content/PermissionChecker.java @@ -16,19 +16,14 @@ package android.content; -import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.AppOpsManager; import android.os.Binder; -import android.os.IBinder; import android.os.Process; -import android.os.RemoteException; -import android.os.ServiceManager; import android.permission.IPermissionChecker; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; +import android.permission.PermissionCheckerManager; +import android.permission.PermissionCheckerManager.PermissionResult; /** * This class provides permission check APIs that verify both the @@ -75,7 +70,7 @@ public final class PermissionChecker { * * @hide */ - public static final int PERMISSION_GRANTED = IPermissionChecker.PERMISSION_GRANTED; + public static final int PERMISSION_GRANTED = PermissionCheckerManager.PERMISSION_GRANTED; /** * The permission is denied. Applicable only to runtime and app op permissions. @@ -89,7 +84,8 @@ public final class PermissionChecker { * * @hide */ - public static final int PERMISSION_SOFT_DENIED = IPermissionChecker.PERMISSION_SOFT_DENIED; + public static final int PERMISSION_SOFT_DENIED = + PermissionCheckerManager.PERMISSION_SOFT_DENIED; /** * The permission is denied. @@ -103,18 +99,12 @@ public final class PermissionChecker { * * @hide */ - public static final int PERMISSION_HARD_DENIED = IPermissionChecker.PERMISSION_HARD_DENIED; + public static final int PERMISSION_HARD_DENIED = + PermissionCheckerManager.PERMISSION_HARD_DENIED; /** Constant when the PID for which we check permissions is unknown. */ public static final int PID_UNKNOWN = -1; - /** @hide */ - @IntDef({PERMISSION_GRANTED, - PERMISSION_SOFT_DENIED, - PERMISSION_HARD_DENIED}) - @Retention(RetentionPolicy.SOURCE) - public @interface PermissionResult {} - private static volatile IPermissionChecker sService; private PermissionChecker() { @@ -157,7 +147,7 @@ public final class PermissionChecker { * * @see #checkPermissionForPreflight(Context, String, int, int, String) */ - @PermissionResult + @PermissionCheckerManager.PermissionResult public static int checkPermissionForDataDelivery(@NonNull Context context, @NonNull String permission, int pid, int uid, @Nullable String packageName, @Nullable String attributionTag, @Nullable String message, boolean startDataDelivery) { @@ -321,19 +311,13 @@ public final class PermissionChecker { message, startDataDelivery, /*fromDatasource*/ false); } + @SuppressWarnings("ConstantConditions") private static int checkPermissionForDataDeliveryCommon(@NonNull Context context, @NonNull String permission, @NonNull AttributionSource attributionSource, @Nullable String message, boolean startDataDelivery, boolean fromDatasource) { - // If the check failed in the middle of the chain, finish any started op. - try { - final int result = getPermissionCheckerService().checkPermission(permission, - attributionSource.asState(), message, true /*forDataDelivery*/, - startDataDelivery, fromDatasource); - return result; - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } - return PERMISSION_HARD_DENIED; + return context.getSystemService(PermissionCheckerManager.class).checkPermission(permission, + attributionSource.asState(), message, true /*forDataDelivery*/, startDataDelivery, + fromDatasource, AppOpsManager.OP_NONE); } /** @@ -365,17 +349,13 @@ public final class PermissionChecker { * @see #checkPermissionForPreflight(Context, String, AttributionSource) */ @PermissionResult + @SuppressWarnings("ConstantConditions") public static int checkPermissionAndStartDataDelivery(@NonNull Context context, @NonNull String permission, @NonNull AttributionSource attributionSource, @Nullable String message) { - try { - return getPermissionCheckerService().checkPermission(permission, - attributionSource.asState(), message, true /*forDataDelivery*/, - /*startDataDelivery*/ true, /*fromDatasource*/ false); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } - return PERMISSION_HARD_DENIED; + return context.getSystemService(PermissionCheckerManager.class).checkPermission( + permission, attributionSource.asState(), message, true /*forDataDelivery*/, + /*startDataDelivery*/ true, /*fromDatasource*/ false, AppOpsManager.OP_NONE); } /** @@ -404,17 +384,13 @@ public final class PermissionChecker { * @see #finishDataDelivery(Context, String, AttributionSource) */ @PermissionResult + @SuppressWarnings("ConstantConditions") public static int startOpForDataDelivery(@NonNull Context context, @NonNull String opName, @NonNull AttributionSource attributionSource, @Nullable String message) { - try { - return getPermissionCheckerService().checkOp( - AppOpsManager.strOpToOp(opName), attributionSource.asState(), message, - true /*forDataDelivery*/, true /*startDataDelivery*/); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } - return PERMISSION_HARD_DENIED; + return context.getSystemService(PermissionCheckerManager.class).checkOp( + AppOpsManager.strOpToOp(opName), attributionSource.asState(), message, + true /*forDataDelivery*/, true /*startDataDelivery*/); } /** @@ -428,13 +404,32 @@ public final class PermissionChecker { * @see #startOpForDataDelivery(Context, String, AttributionSource, String) * @see #checkPermissionAndStartDataDelivery(Context, String, AttributionSource, String) */ + @SuppressWarnings("ConstantConditions") public static void finishDataDelivery(@NonNull Context context, @NonNull String op, @NonNull AttributionSource attributionSource) { - try { - getPermissionCheckerService().finishDataDelivery(op, attributionSource.asState()); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } + context.getSystemService(PermissionCheckerManager.class).finishDataDelivery( + AppOpsManager.strOpToOp(op), attributionSource.asState(), + /*fromDatasource*/ false); + } + + /** + * Finishes an ongoing op for data access chain described by the given {@link + * AttributionSource}. Call this method if you are the datasource which would + * not finish an op for your attribution source as it was not started. + * + * @param context Context for accessing resources. + * @param op The op to finish. + * @param attributionSource The identity for which finish op. + * + * @see #startOpForDataDelivery(Context, String, AttributionSource, String) + * @see #checkPermissionAndStartDataDelivery(Context, String, AttributionSource, String) + */ + @SuppressWarnings("ConstantConditions") + public static void finishDataDeliveryFromDatasource(@NonNull Context context, + @NonNull String op, @NonNull AttributionSource attributionSource) { + context.getSystemService(PermissionCheckerManager.class).finishDataDelivery( + AppOpsManager.strOpToOp(op), attributionSource.asState(), + /*fromDatasource*/ true); } /** @@ -466,17 +461,13 @@ public final class PermissionChecker { * @see #checkOpForDataDelivery(Context, String, AttributionSource, String) */ @PermissionResult + @SuppressWarnings("ConstantConditions") public static int checkOpForPreflight(@NonNull Context context, @NonNull String opName, @NonNull AttributionSource attributionSource, @Nullable String message) { - try { - return getPermissionCheckerService().checkOp(AppOpsManager.strOpToOp(opName), - attributionSource.asState(), message, false /*forDataDelivery*/, - false /*startDataDelivery*/); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } - return PERMISSION_HARD_DENIED; + return context.getSystemService(PermissionCheckerManager.class).checkOp( + AppOpsManager.strOpToOp(opName), attributionSource.asState(), message, + false /*forDataDelivery*/, false /*startDataDelivery*/); } /** @@ -505,17 +496,13 @@ public final class PermissionChecker { * @see #checkOpForPreflight(Context, String, AttributionSource, String) */ @PermissionResult + @SuppressWarnings("ConstantConditions") public static int checkOpForDataDelivery(@NonNull Context context, @NonNull String opName, @NonNull AttributionSource attributionSource, @Nullable String message) { - try { - return getPermissionCheckerService().checkOp(AppOpsManager.strOpToOp(opName), - attributionSource.asState(), message, true /*forDataDelivery*/, - false /*startDataDelivery*/); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } - return PERMISSION_HARD_DENIED; + return context.getSystemService(PermissionCheckerManager.class).checkOp( + AppOpsManager.strOpToOp(opName), attributionSource.asState(), message, + true /*forDataDelivery*/, false /*startDataDelivery*/); } /** @@ -584,16 +571,13 @@ public final class PermissionChecker { * String, boolean) */ @PermissionResult + @SuppressWarnings("ConstantConditions") public static int checkPermissionForPreflight(@NonNull Context context, @NonNull String permission, @NonNull AttributionSource attributionSource) { - try { - return getPermissionCheckerService().checkPermission(permission, - attributionSource.asState(), null /*message*/, false /*forDataDelivery*/, - /*startDataDelivery*/ false, /*fromDatasource*/ false); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } - return PERMISSION_HARD_DENIED; + return context.getSystemService(PermissionCheckerManager.class) + .checkPermission(permission, attributionSource.asState(), null /*message*/, + false /*forDataDelivery*/, /*startDataDelivery*/ false, /*fromDatasource*/ false, + AppOpsManager.OP_NONE); } /** @@ -827,13 +811,4 @@ public final class PermissionChecker { return checkPermissionForPreflight(context, permission, Binder.getCallingPid(), Binder.getCallingUid(), packageName); } - - private static @NonNull IPermissionChecker getPermissionCheckerService() { - // Race is fine, we may end up looking up the same instance twice, no big deal. - if (sService == null) { - final IBinder service = ServiceManager.getService("permission_checker"); - sService = IPermissionChecker.Stub.asInterface(service); - } - return sService; - } } diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java index 0662f160a009..8dfb787bb3ab 100644 --- a/core/java/android/hardware/camera2/params/OutputConfiguration.java +++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java @@ -846,6 +846,14 @@ public final class OutputConfiguration implements Parcelable { return 0; } + private static int[] convertIntegerToIntList(List<Integer> integerList) { + int[] integerArray = new int[integerList.size()]; + for (int i = 0; i < integerList.size(); i++) { + integerArray[i] = integerList.get(i); + } + return integerArray; + } + @Override public void writeToParcel(Parcel dest, int flags) { if (dest == null) { @@ -861,7 +869,9 @@ public final class OutputConfiguration implements Parcelable { dest.writeTypedList(mSurfaces); dest.writeString(mPhysicalCameraId); dest.writeInt(mIsMultiResolution ? 1 : 0); - dest.writeList(mSensorPixelModesUsed); + // writeList doesn't seem to work well with Integer list. + dest.writeIntArray(convertIntegerToIntList(mSensorPixelModesUsed)); + //dest.writeArray(mSensorPixelModesUsed.toArray()); } /** diff --git a/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl b/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl index d2cb5bfe6910..f18360ff4108 100644 --- a/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl +++ b/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl @@ -35,6 +35,10 @@ oneway interface IUdfpsOverlayController { // Hides the overlay. void hideUdfpsOverlay(int sensorId); + // Good image captured. Turn off HBM. Success/Reject comes after, which is when hideUdfpsOverlay + // will be called. + void onAcquiredGood(int sensorId); + // Notifies of enrollment progress changes. void onEnrollmentProgress(int sensorId, int remaining); diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index 900659b5ae54..a5b7e995293a 100755 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -1086,7 +1086,7 @@ public class Build { /** * S. */ - public static final int S = CUR_DEVELOPMENT; + public static final int S = 31; } /** The type of build, like "user" or "eng". */ diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java index 781800dd49ce..a0cbbfe3327b 100644 --- a/core/java/android/os/VibrationEffect.java +++ b/core/java/android/os/VibrationEffect.java @@ -182,6 +182,11 @@ public abstract class VibrationEffect implements Parcelable { * @return The desired effect. */ public static VibrationEffect createOneShot(long milliseconds, int amplitude) { + if (amplitude == 0) { + throw new IllegalArgumentException( + "amplitude must either be DEFAULT_AMPLITUDE, " + + "or between 1 and 255 inclusive (amplitude=" + amplitude + ")"); + } return createWaveform(new long[]{milliseconds}, new int[]{amplitude}, -1 /* repeat */); } @@ -581,22 +586,16 @@ public abstract class VibrationEffect implements Parcelable { public void validate() { int segmentCount = mSegments.size(); boolean hasNonZeroDuration = false; - boolean hasNonZeroAmplitude = false; for (int i = 0; i < segmentCount; i++) { VibrationEffectSegment segment = mSegments.get(i); segment.validate(); // A segment with unknown duration = -1 still counts as a non-zero duration. hasNonZeroDuration |= segment.getDuration() != 0; - hasNonZeroAmplitude |= segment.hasNonZeroAmplitude(); } if (!hasNonZeroDuration) { throw new IllegalArgumentException("at least one timing must be non-zero" + " (segments=" + mSegments + ")"); } - if (!hasNonZeroAmplitude) { - throw new IllegalArgumentException("at least one amplitude must be non-zero" - + " (segments=" + mSegments + ")"); - } if (mRepeatIndex != -1) { Preconditions.checkArgumentInRange(mRepeatIndex, 0, segmentCount - 1, "repeat index must be within the bounds of the segments (segments.length=" diff --git a/core/java/android/permission/IPermissionManager.aidl b/core/java/android/permission/IPermissionManager.aidl index ef075e1efbff..9ab69552f1a0 100644 --- a/core/java/android/permission/IPermissionManager.aidl +++ b/core/java/android/permission/IPermissionManager.aidl @@ -87,7 +87,7 @@ interface IPermissionManager { boolean isAutoRevokeExempted(String packageName, int userId); - AttributionSource registerAttributionSource(in AttributionSource source); + void registerAttributionSource(in AttributionSource source); boolean isRegisteredAttributionSource(in AttributionSource source); } diff --git a/core/java/android/permission/PermissionCheckerManager.java b/core/java/android/permission/PermissionCheckerManager.java new file mode 100644 index 000000000000..7523816250b0 --- /dev/null +++ b/core/java/android/permission/PermissionCheckerManager.java @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.permission; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.AppOpsManager; +import android.content.AttributionSourceState; +import android.content.Context; +import android.content.pm.PackageManager; +import android.os.RemoteException; +import android.os.ServiceManager; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Objects; + +/** + * Manager for checking runtime and app op permissions. This is a temporary + * class and we may fold its function in the PermissionManager once the + * permission re-architecture starts falling into place. The main benefit + * of this class is to allow context level caching. + * + * @hide + */ +public class PermissionCheckerManager { + + /** + * The permission is granted. + */ + public static final int PERMISSION_GRANTED = IPermissionChecker.PERMISSION_GRANTED; + + /** + * The permission is denied. Applicable only to runtime and app op permissions. + * + * <p>Returned when: + * <ul> + * <li>the runtime permission is granted, but the corresponding app op is denied + * for runtime permissions.</li> + * <li>the app ops is ignored for app op permissions.</li> + * </ul> + */ + public static final int PERMISSION_SOFT_DENIED = IPermissionChecker.PERMISSION_SOFT_DENIED; + + /** + * The permission is denied. + * + * <p>Returned when: + * <ul> + * <li>the permission is denied for non app op permissions.</li> + * <li>the app op is denied or app op is {@link AppOpsManager#MODE_DEFAULT} + * and permission is denied.</li> + * </ul> + */ + public static final int PERMISSION_HARD_DENIED = IPermissionChecker.PERMISSION_HARD_DENIED; + + /** @hide */ + @IntDef({PERMISSION_GRANTED, + PERMISSION_SOFT_DENIED, + PERMISSION_HARD_DENIED}) + @Retention(RetentionPolicy.SOURCE) + public @interface PermissionResult {} + + @NonNull + private final Context mContext; + + @NonNull + private final IPermissionChecker mService; + + @NonNull + private final PackageManager mPackageManager; + + public PermissionCheckerManager(@NonNull Context context) + throws ServiceManager.ServiceNotFoundException { + mContext = context; + mService = IPermissionChecker.Stub.asInterface(ServiceManager.getServiceOrThrow( + Context.PERMISSION_CHECKER_SERVICE)); + mPackageManager = context.getPackageManager(); + } + + /** + * Checks a permission by validating the entire attribution source chain. If the + * permission is associated with an app op the op is also noted/started for the + * entire attribution chain. + * + * @param permission The permission + * @param attributionSource The attribution chain to check. + * @param message Message associated with the permission if permission has an app op + * @param forDataDelivery Whether the check is for delivering data if permission has an app op + * @param startDataDelivery Whether to start data delivery (start op) if permission has + * an app op + * @param fromDatasource Whether the check is by a datasource (skip checks for the + * first attribution source in the chain as this is the datasource) + * @param attributedOp Alternative app op to attribute + * @return The permission check result. + */ + @PermissionResult + public int checkPermission(@NonNull String permission, + @NonNull AttributionSourceState attributionSource, @Nullable String message, + boolean forDataDelivery, boolean startDataDelivery, boolean fromDatasource, + int attributedOp) { + Objects.requireNonNull(permission); + Objects.requireNonNull(attributionSource); + // Fast path for non-runtime, non-op permissions where the attribution chain has + // length one. This is the majority of the cases and we want these to be fast by + // hitting the local in process permission cache. + if (AppOpsManager.permissionToOpCode(permission) == AppOpsManager.OP_NONE) { + if (fromDatasource) { + if (attributionSource.next != null && attributionSource.next.length > 0) { + return mContext.checkPermission(permission, attributionSource.next[0].pid, + attributionSource.next[0].uid) == PackageManager.PERMISSION_GRANTED + ? PERMISSION_GRANTED : PERMISSION_HARD_DENIED; + } + } else { + return (mContext.checkPermission(permission, attributionSource.pid, + attributionSource.uid) == PackageManager.PERMISSION_GRANTED) + ? PERMISSION_GRANTED : PERMISSION_HARD_DENIED; + } + } + try { + return mService.checkPermission(permission, attributionSource, message, forDataDelivery, + startDataDelivery, fromDatasource, attributedOp); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + return PERMISSION_HARD_DENIED; + } + + /** + * Finishes an app op by validating the entire attribution source chain. + * + * @param op The op to finish. + * @param attributionSource The attribution chain to finish. + * @param fromDatasource Whether the finish is by a datasource (skip finish for the + * first attribution source in the chain as this is the datasource) + */ + public void finishDataDelivery(int op, @NonNull AttributionSourceState attributionSource, + boolean fromDatasource) { + Objects.requireNonNull(attributionSource); + try { + mService.finishDataDelivery(op, attributionSource, fromDatasource); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + + /** + * Checks an app op by validating the entire attribution source chain. The op is + * also noted/started for the entire attribution chain. + * + * @param op The op to check. + * @param attributionSource The attribution chain to check. + * @param message Message associated with the permission if permission has an app op + * @param forDataDelivery Whether the check is for delivering data if permission has an app op + * @param startDataDelivery Whether to start data delivery (start op) if permission has + * an app op + * @return The op check result. + */ + @PermissionResult + public int checkOp(int op, @NonNull AttributionSourceState attributionSource, + @Nullable String message, boolean forDataDelivery, boolean startDataDelivery) { + Objects.requireNonNull(attributionSource); + try { + return mService.checkOp(op, attributionSource, message, forDataDelivery, + startDataDelivery); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + return PERMISSION_HARD_DENIED; + } +} diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java index d490e7a7b454..f3cc35b32223 100644 --- a/core/java/android/permission/PermissionManager.java +++ b/core/java/android/permission/PermissionManager.java @@ -1156,13 +1156,12 @@ public final class PermissionManager { * @hide */ @TestApi - public @NonNull AttributionSource registerAttributionSource(@NonNull AttributionSource source) { + public void registerAttributionSource(@NonNull AttributionSource source) { try { - return mPermissionManager.registerAttributionSource(source); + mPermissionManager.registerAttributionSource(source); } catch (RemoteException e) { e.rethrowFromSystemServer(); } - return null; } /** diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 13e5cda7cca3..cb87653718c2 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -6661,6 +6661,20 @@ public final class Settings { public static final String COMPLETED_CATEGORY_PREFIX = "suggested.completed_category."; /** + * Whether or not compress blocks should be released on install. + * <p>The setting only determines if the platform will attempt to release + * compress blocks; it does not guarantee that the files will have their + * compress blocks released. Compression is currently only supported on + * some f2fs filesystems. + * <p> + * Type: int (0 for false, 1 for true) + * + * @hide + */ + public static final String RELEASE_COMPRESS_BLOCKS_ON_INSTALL = + "release_compress_blocks_on_install"; + + /** * List of input methods that are currently enabled. This is a string * containing the IDs of all enabled input methods, each ID separated * by ':'. @@ -11060,7 +11074,7 @@ public final class Settings { * @hide */ @UnsupportedAppUsage - @Readable(maxTargetSdk = Build.VERSION_CODES.R) + @Readable public static final String MOBILE_DATA = "mobile_data"; /** diff --git a/core/java/android/speech/RecognitionService.java b/core/java/android/speech/RecognitionService.java index bb48757988e9..b9ff5e7be86a 100644 --- a/core/java/android/speech/RecognitionService.java +++ b/core/java/android/speech/RecognitionService.java @@ -65,22 +65,20 @@ public abstract class RecognitionService extends Service { private static final String TAG = "RecognitionService"; /** Debugging flag */ - private static final boolean DBG = true; - - private static final String RECORD_AUDIO_APP_OP = - AppOpsManager.permissionToOp(Manifest.permission.RECORD_AUDIO); - private static final int RECORD_AUDIO_APP_OP_CODE = - AppOpsManager.permissionToOpCode(Manifest.permission.RECORD_AUDIO); + private static final boolean DBG = false; /** Binder of the recognition service */ private RecognitionServiceBinder mBinder = new RecognitionServiceBinder(this); /** * The current callback of an application that invoked the + * * {@link RecognitionService#onStartListening(Intent, Callback)} method */ private Callback mCurrentCallback = null; + private boolean mStartedDataDelivery; + private static final int MSG_START_LISTENING = 1; private static final int MSG_STOP_LISTENING = 2; @@ -120,6 +118,11 @@ public abstract class RecognitionService extends Service { mCurrentCallback = new Callback(listener, attributionSource); RecognitionService.this.onStartListening(intent, mCurrentCallback); + if (!checkPermissionAndStartDataDelivery()) { + listener.onError(SpeechRecognizer.ERROR_INSUFFICIENT_PERMISSIONS); + Log.i(TAG, "caller doesn't have permission:" + + Manifest.permission.RECORD_AUDIO); + } } else { listener.onError(SpeechRecognizer.ERROR_RECOGNIZER_BUSY); Log.i(TAG, "concurrent startListening received - ignoring this call"); @@ -152,13 +155,15 @@ public abstract class RecognitionService extends Service { Log.w(TAG, "cancel called by client who did not call startListening - ignoring"); } else { // the correct state RecognitionService.this.onCancel(mCurrentCallback); - mCurrentCallback = null; + dispatchClearCallback(); if (DBG) Log.d(TAG, "canceling - setting mCurrentCallback to null"); } } private void dispatchClearCallback() { + finishDataDelivery(); mCurrentCallback = null; + mStartedDataDelivery = false; } private class StartListeningArgs { @@ -177,7 +182,30 @@ public abstract class RecognitionService extends Service { /** * Notifies the service that it should start listening for speech. - * + * + * <p> If you are recognizing speech from the microphone, in this callback you + * should create an attribution context for the caller such that when you access + * the mic the caller would be properly blamed (and their permission checked in + * the process) for accessing the microphone and that you served as a proxy for + * this sensitive data (and your permissions would be checked in the process). + * You should also open the mic in this callback via the attribution context + * and close the mic before returning the recognized result. If you don't do + * that then the caller would be blamed and you as being a proxy as well as you + * would get one more blame on yourself when you open the microphone. + * + * <pre> + * Context attributionContext = context.createContext(new ContextParams.Builder() + * .setNextAttributionSource(callback.getCallingAttributionSource()) + * .build()); + * + * AudioRecord recorder = AudioRecord.Builder() + * .setContext(attributionContext); + * . . . + * .build(); + * + * recorder.startRecording() + * </pre> + * * @param recognizerIntent contains parameters for the recognition to be performed. The intent * may also contain optional extras, see {@link RecognizerIntent}. If these values are * not set explicitly, default values should be used by the recognizer. @@ -335,57 +363,13 @@ public abstract class RecognitionService extends Service { return mCallingAttributionSource; } - boolean maybeStartAttribution() { - if (DBG) { - Log.i(TAG, "Starting attribution"); - } - - if (DBG && isProxyingRecordAudioToCaller()) { - Log.i(TAG, "Proxying already in progress, not starting the attribution"); - } - - if (!isProxyingRecordAudioToCaller()) { + @NonNull Context getAttributionContextForCaller() { + if (mAttributionContext == null) { mAttributionContext = createContext(new ContextParams.Builder() .setNextAttributionSource(mCallingAttributionSource) .build()); - - final int result = PermissionChecker.checkPermissionAndStartDataDelivery( - RecognitionService.this, - Manifest.permission.RECORD_AUDIO, - mAttributionContext.getAttributionSource(), - /*message*/ null); - - return result == PermissionChecker.PERMISSION_GRANTED; - } - return false; - } - - void maybeFinishAttribution() { - if (DBG) { - Log.i(TAG, "Finishing attribution"); - } - - if (DBG && !isProxyingRecordAudioToCaller()) { - Log.i(TAG, "Not proxying currently, not finishing the attribution"); - } - - if (isProxyingRecordAudioToCaller()) { - PermissionChecker.finishDataDelivery( - RecognitionService.this, - RECORD_AUDIO_APP_OP, - mAttributionContext.getAttributionSource()); - - mAttributionContext = null; } - } - - private boolean isProxyingRecordAudioToCaller() { - final AppOpsManager appOpsManager = getSystemService(AppOpsManager.class); - return appOpsManager.isProxying( - RECORD_AUDIO_APP_OP_CODE, - getAttributionTag(), - mCallingAttributionSource.getUid(), - mCallingAttributionSource.getPackageName()); + return mAttributionContext; } } @@ -435,4 +419,35 @@ public abstract class RecognitionService extends Service { mServiceRef.clear(); } } + + private boolean checkPermissionAndStartDataDelivery() { + if (isPerformingDataDelivery()) { + return true; + } + if (PermissionChecker.checkPermissionAndStartDataDelivery( + RecognitionService.this, Manifest.permission.RECORD_AUDIO, + mCurrentCallback.getAttributionContextForCaller().getAttributionSource(), + /*message*/ null) == PermissionChecker.PERMISSION_GRANTED) { + mStartedDataDelivery = true; + } + return mStartedDataDelivery; + } + + void finishDataDelivery() { + if (mStartedDataDelivery) { + mStartedDataDelivery = false; + final String op = AppOpsManager.permissionToOp(Manifest.permission.RECORD_AUDIO); + PermissionChecker.finishDataDelivery(RecognitionService.this, op, + mCurrentCallback.getAttributionContextForCaller().getAttributionSource()); + } + } + + @SuppressWarnings("ConstantCondition") + private boolean isPerformingDataDelivery() { + final int op = AppOpsManager.permissionToOpCode(Manifest.permission.RECORD_AUDIO); + final AppOpsManager appOpsManager = getSystemService(AppOpsManager.class); + return appOpsManager.isProxying(op, getAttributionTag(), + mCurrentCallback.getCallingAttributionSource().getUid(), + mCurrentCallback.getCallingAttributionSource().getPackageName()); + } } diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl index ce649cc7c2b2..7bad5cbfbdc3 100644 --- a/core/java/android/view/IWindowSession.aidl +++ b/core/java/android/view/IWindowSession.aidl @@ -267,20 +267,6 @@ interface IWindowSession { oneway void updatePointerIcon(IWindow window); /** - * Reparent the top layers for a display to the requested SurfaceControl. The display that is - * going to be re-parented (the displayId passed in) needs to have been created by the same - * process that is requesting the re-parent. This is to ensure clients can't just re-parent - * display content info to any SurfaceControl, as this would be a security issue. - * - * @param window The window which owns the SurfaceControl. This indicates the z-order of the - * windows of this display against the windows on the parent display. - * @param sc The SurfaceControl that the top level layers for the display should be re-parented - * to. - * @param displayId The id of the display to be re-parented. - */ - oneway void reparentDisplayContent(IWindow window, in SurfaceControl sc, int displayId); - - /** * Update the location of a child display in its parent window. This enables windows in the * child display to compute the global transformation matrix. * diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index 45c49352afff..f34cd8f9de50 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -34,7 +34,6 @@ import android.annotation.Size; import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Bitmap; -import android.graphics.BLASTBufferQueue; import android.graphics.ColorSpace; import android.graphics.GraphicBuffer; import android.graphics.Matrix; @@ -647,6 +646,12 @@ public final class SurfaceControl implements Parcelable { public static final int METADATA_OWNER_PID = 6; /** + * game mode for the layer - used for metrics + * @hide + */ + public static final int METADATA_GAME_MODE = 8; + + /** * A wrapper around HardwareBuffer that contains extra information about how to * interpret the screenshot HardwareBuffer. * diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index afd6878da429..67cf85cee9ac 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -2783,7 +2783,7 @@ public final class ViewRootImpl implements ViewParent, & WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING_DOCKED) != 0; final boolean dragResizing = freeformResizing || dockedResizing; if (mSurfaceControl.isValid()) { - updateOpacity(params, dragResizing); + updateOpacity(mWindowAttributes, dragResizing); } if (DEBUG_LAYOUT) Log.v(mTag, "relayout: frame=" + frame.toShortString() @@ -7749,9 +7749,10 @@ public final class ViewRootImpl implements ViewParent, return relayoutResult; } - private void updateOpacity(@Nullable WindowManager.LayoutParams params, boolean dragResizing) { + private void updateOpacity(WindowManager.LayoutParams params, boolean dragResizing) { boolean opaque = false; - if (params != null && !PixelFormat.formatHasAlpha(params.format) + + if (!PixelFormat.formatHasAlpha(params.format) // Don't make surface with surfaceInsets opaque as they display a // translucent shadow. && params.surfaceInsets.left == 0 diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java index 72d403e1f867..ae54f51f35d1 100644 --- a/core/java/android/view/WindowlessWindowManager.java +++ b/core/java/android/view/WindowlessWindowManager.java @@ -444,11 +444,6 @@ public class WindowlessWindowManager implements IWindowSession { } @Override - public void reparentDisplayContent(android.view.IWindow window, android.view.SurfaceControl sc, - int displayId) { - } - - @Override public void updateDisplayContentLocation(android.view.IWindow window, int x, int y, int displayId) { } diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java index 207385d12d90..f2827f3fec73 100644 --- a/core/java/android/widget/EdgeEffect.java +++ b/core/java/android/widget/EdgeEffect.java @@ -16,6 +16,7 @@ package android.widget; +import android.animation.ValueAnimator; import android.annotation.ColorInt; import android.annotation.IntDef; import android.annotation.NonNull; @@ -76,6 +77,11 @@ public class EdgeEffect { public static final BlendMode DEFAULT_BLEND_MODE = BlendMode.SRC_ATOP; /** + * Completely disable edge effect + */ + private static final int TYPE_NONE = -1; + + /** * Use a color edge glow for the edge effect. */ private static final int TYPE_GLOW = 0; @@ -114,7 +120,7 @@ public class EdgeEffect { private static final float ON_ABSORB_VELOCITY_ADJUSTMENT = 13f; /** @hide */ - @IntDef({TYPE_GLOW, TYPE_STRETCH}) + @IntDef({TYPE_NONE, TYPE_GLOW, TYPE_STRETCH}) @Retention(RetentionPolicy.SOURCE) public @interface EdgeEffectType { } @@ -195,6 +201,12 @@ public class EdgeEffect { private float mBaseGlowScale; private float mDisplacement = 0.5f; private float mTargetDisplacement = 0.5f; + + /** + * Current edge effect type, consumers should always query + * {@link #getCurrentEdgeEffectBehavior()} instead of this parameter + * directly in case animations have been disabled (ex. for accessibility reasons) + */ private @EdgeEffectType int mEdgeEffectType = TYPE_GLOW; private Matrix mTmpMatrix = null; private float[] mTmpPoints = null; @@ -227,6 +239,15 @@ public class EdgeEffect { mPaint.setBlendMode(DEFAULT_BLEND_MODE); } + @EdgeEffectType + private int getCurrentEdgeEffectBehavior() { + if (!ValueAnimator.areAnimatorsEnabled()) { + return TYPE_NONE; + } else { + return mEdgeEffectType; + } + } + /** * Set the size of this edge effect in pixels. * @@ -302,14 +323,19 @@ public class EdgeEffect { * Values may be from 0-1. */ public void onPull(float deltaDistance, float displacement) { + int edgeEffectBehavior = getCurrentEdgeEffectBehavior(); + if (edgeEffectBehavior == TYPE_NONE) { + finish(); + return; + } final long now = AnimationUtils.currentAnimationTimeMillis(); mTargetDisplacement = displacement; if (mState == STATE_PULL_DECAY && now - mStartTime < mDuration - && mEdgeEffectType == TYPE_GLOW) { + && edgeEffectBehavior == TYPE_GLOW) { return; } if (mState != STATE_PULL) { - if (mEdgeEffectType == TYPE_STRETCH) { + if (edgeEffectBehavior == TYPE_STRETCH) { // Restore the mPullDistance to the fraction it is currently showing -- we want // to "catch" the current stretch value. mPullDistance = mDistance; @@ -342,7 +368,7 @@ public class EdgeEffect { mGlowAlphaFinish = mGlowAlpha; mGlowScaleYFinish = mGlowScaleY; - if (mEdgeEffectType == TYPE_STRETCH && mDistance == 0) { + if (edgeEffectBehavior == TYPE_STRETCH && mDistance == 0) { mState = STATE_IDLE; } } @@ -377,13 +403,17 @@ public class EdgeEffect { * 0 and <code>deltaDistance</code>. */ public float onPullDistance(float deltaDistance, float displacement) { + int edgeEffectBehavior = getCurrentEdgeEffectBehavior(); + if (edgeEffectBehavior == TYPE_NONE) { + return 0f; + } float finalDistance = Math.max(0f, deltaDistance + mDistance); float delta = finalDistance - mDistance; if (delta == 0f && mDistance == 0f) { return 0f; // No pull, don't do anything. } - if (mState != STATE_PULL && mState != STATE_PULL_DECAY && mEdgeEffectType == TYPE_GLOW) { + if (mState != STATE_PULL && mState != STATE_PULL_DECAY && edgeEffectBehavior == TYPE_GLOW) { // Catch the edge glow in the middle of an animation. mPullDistance = mDistance; mState = STATE_PULL; @@ -442,11 +472,12 @@ public class EdgeEffect { * @param velocity Velocity at impact in pixels per second. */ public void onAbsorb(int velocity) { - if (mEdgeEffectType == TYPE_STRETCH) { + int edgeEffectBehavior = getCurrentEdgeEffectBehavior(); + if (edgeEffectBehavior == TYPE_STRETCH) { mState = STATE_RECEDE; mVelocity = velocity * ON_ABSORB_VELOCITY_ADJUSTMENT; mStartTime = AnimationUtils.currentAnimationTimeMillis(); - } else { + } else if (edgeEffectBehavior == TYPE_GLOW) { mState = STATE_ABSORB; mVelocity = 0; velocity = Math.min(Math.max(MIN_VELOCITY, Math.abs(velocity)), MAX_VELOCITY); @@ -470,6 +501,8 @@ public class EdgeEffect { mGlowAlphaStart, Math.min(velocity * VELOCITY_GLOW_FACTOR * .00001f, MAX_ALPHA)); mTargetDisplacement = 0.5f; + } else { + finish(); } } @@ -532,7 +565,8 @@ public class EdgeEffect { * animation */ public boolean draw(Canvas canvas) { - if (mEdgeEffectType == TYPE_GLOW) { + int edgeEffectBehavior = getCurrentEdgeEffectBehavior(); + if (edgeEffectBehavior == TYPE_GLOW) { update(); final int count = canvas.save(); @@ -549,7 +583,7 @@ public class EdgeEffect { mPaint.setAlpha((int) (0xff * mGlowAlpha)); canvas.drawCircle(centerX, centerY, mRadius, mPaint); canvas.restoreToCount(count); - } else if (canvas instanceof RecordingCanvas) { + } else if (edgeEffectBehavior == TYPE_STRETCH && canvas instanceof RecordingCanvas) { if (mState == STATE_RECEDE) { updateSpring(); } @@ -604,8 +638,8 @@ public class EdgeEffect { ); } } else { - // This is TYPE_STRETCH and drawing into a Canvas that isn't a Recording Canvas, - // so no effect can be shown. Just end the effect. + // Animations have been disabled or this is TYPE_STRETCH and drawing into a Canvas + // that isn't a Recording Canvas, so no effect can be shown. Just end the effect. mState = STATE_IDLE; mDistance = 0; mVelocity = 0; diff --git a/core/java/com/android/internal/app/AbstractResolverComparator.java b/core/java/com/android/internal/app/AbstractResolverComparator.java index ea3f1b1fc04c..40ada0b2ffdc 100644 --- a/core/java/com/android/internal/app/AbstractResolverComparator.java +++ b/core/java/com/android/internal/app/AbstractResolverComparator.java @@ -64,6 +64,7 @@ public abstract class AbstractResolverComparator implements Comparator<ResolvedC private static final int WATCHDOG_TIMEOUT_MILLIS = 500; private final Comparator<ResolveInfo> mAzComparator; + private ChooserActivityLogger mChooserActivityLogger; protected final Handler mHandler = new Handler(Looper.getMainLooper()) { public void handleMessage(Message msg) { @@ -85,6 +86,9 @@ public abstract class AbstractResolverComparator implements Comparator<ResolvedC } mHandler.removeMessages(RANKER_SERVICE_RESULT); afterCompute(); + if (mChooserActivityLogger != null) { + mChooserActivityLogger.logSharesheetAppShareRankingTimeout(); + } break; default: @@ -131,6 +135,14 @@ public abstract class AbstractResolverComparator implements Comparator<ResolvedC mAfterCompute = afterCompute; } + void setChooserActivityLogger(ChooserActivityLogger chooserActivityLogger) { + mChooserActivityLogger = chooserActivityLogger; + } + + ChooserActivityLogger getChooserActivityLogger() { + return mChooserActivityLogger; + } + protected final void afterCompute() { final AfterCompute afterCompute = mAfterCompute; if (afterCompute != null) { diff --git a/core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java b/core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java index b76ef0fd4ed8..bc9eff04636d 100644 --- a/core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java +++ b/core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java @@ -61,17 +61,19 @@ class AppPredictionServiceResolverComparator extends AbstractResolverComparator private ResolverRankerServiceResolverComparator mResolverRankerService; AppPredictionServiceResolverComparator( - Context context, - Intent intent, - String referrerPackage, - AppPredictor appPredictor, - UserHandle user) { + Context context, + Intent intent, + String referrerPackage, + AppPredictor appPredictor, + UserHandle user, + ChooserActivityLogger chooserActivityLogger) { super(context, intent); mContext = context; mIntent = intent; mAppPredictor = appPredictor; mUser = user; mReferrerPackage = referrerPackage; + setChooserActivityLogger(chooserActivityLogger); } @Override @@ -116,8 +118,9 @@ class AppPredictionServiceResolverComparator extends AbstractResolverComparator // APS for chooser is disabled. Fallback to resolver. mResolverRankerService = new ResolverRankerServiceResolverComparator( - mContext, mIntent, mReferrerPackage, - () -> mHandler.sendEmptyMessage(RANKER_SERVICE_RESULT)); + mContext, mIntent, mReferrerPackage, + () -> mHandler.sendEmptyMessage(RANKER_SERVICE_RESULT), + getChooserActivityLogger()); mResolverRankerService.compute(targets); } else { Log.i(TAG, "AppPredictionService response received"); diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index 28c2774cabb0..08db74f5e351 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -2591,7 +2591,8 @@ public class ChooserActivity extends ResolverActivity implements boolean filterLastUsed, ResolverListController resolverListController) { return new ChooserListAdapter(context, payloadIntents, initialIntents, rList, filterLastUsed, resolverListController, this, - this, context.getPackageManager()); + this, context.getPackageManager(), + getChooserActivityLogger()); } @VisibleForTesting @@ -2600,11 +2601,11 @@ public class ChooserActivity extends ResolverActivity implements AbstractResolverComparator resolverComparator; if (appPredictor != null) { resolverComparator = new AppPredictionServiceResolverComparator(this, getTargetIntent(), - getReferrerPackageName(), appPredictor, userHandle); + getReferrerPackageName(), appPredictor, userHandle, getChooserActivityLogger()); } else { resolverComparator = new ResolverRankerServiceResolverComparator(this, getTargetIntent(), - getReferrerPackageName(), null); + getReferrerPackageName(), null, getChooserActivityLogger()); } return new ChooserListController( diff --git a/core/java/com/android/internal/app/ChooserActivityLogger.java b/core/java/com/android/internal/app/ChooserActivityLogger.java index 47d83346d038..321730786471 100644 --- a/core/java/com/android/internal/app/ChooserActivityLogger.java +++ b/core/java/com/android/internal/app/ChooserActivityLogger.java @@ -75,6 +75,20 @@ public interface ChooserActivityLogger { } /** + * Logs a UiEventReported event for the system sharesheet app share ranking timing out. + */ + default void logSharesheetAppShareRankingTimeout() { + log(SharesheetStandardEvent.SHARESHEET_APP_SHARE_RANKING_TIMEOUT, getInstanceId()); + } + + /** + * Logs a UiEventReported event for the system sharesheet when direct share row is empty. + */ + default void logSharesheetEmptyDirectShareRow() { + log(SharesheetStandardEvent.SHARESHEET_EMPTY_DIRECT_SHARE_ROW, getInstanceId()); + } + + /** * Logs a UiEventReported event for a given share activity * @param event * @param instanceId @@ -168,7 +182,11 @@ public interface ChooserActivityLogger { @UiEvent(doc = "Sharesheet direct targets is fully populated.") SHARESHEET_DIRECT_LOAD_COMPLETE(323), @UiEvent(doc = "Sharesheet direct targets timed out.") - SHARESHEET_DIRECT_LOAD_TIMEOUT(324); + SHARESHEET_DIRECT_LOAD_TIMEOUT(324), + @UiEvent(doc = "Sharesheet app share ranking timed out.") + SHARESHEET_APP_SHARE_RANKING_TIMEOUT(831), + @UiEvent(doc = "Sharesheet empty direct share row.") + SHARESHEET_EMPTY_DIRECT_SHARE_ROW(828); private final int mId; SharesheetStandardEvent(int id) { diff --git a/core/java/com/android/internal/app/ChooserListAdapter.java b/core/java/com/android/internal/app/ChooserListAdapter.java index cc2b12a99d79..87737ca9c3af 100644 --- a/core/java/com/android/internal/app/ChooserListAdapter.java +++ b/core/java/com/android/internal/app/ChooserListAdapter.java @@ -79,6 +79,7 @@ public class ChooserListAdapter extends ResolverListAdapter { private final ChooserListCommunicator mChooserListCommunicator; private final SelectableTargetInfo.SelectableTargetInfoCommunicator mSelectableTargetInfoCommunicator; + private final ChooserActivityLogger mChooserActivityLogger; private int mNumShortcutResults = 0; private Map<DisplayResolveInfo, LoadIconTask> mIconLoaders = new HashMap<>(); @@ -104,7 +105,8 @@ public class ChooserListAdapter extends ResolverListAdapter { boolean filterLastUsed, ResolverListController resolverListController, ChooserListCommunicator chooserListCommunicator, SelectableTargetInfo.SelectableTargetInfoCommunicator selectableTargetInfoCommunicator, - PackageManager packageManager) { + PackageManager packageManager, + ChooserActivityLogger chooserActivityLogger) { // Don't send the initial intents through the shared ResolverActivity path, // we want to separate them into a different section. super(context, payloadIntents, null, rList, filterLastUsed, @@ -115,6 +117,7 @@ public class ChooserListAdapter extends ResolverListAdapter { mChooserListCommunicator = chooserListCommunicator; createPlaceHolders(); mSelectableTargetInfoCommunicator = selectableTargetInfoCommunicator; + mChooserActivityLogger = chooserActivityLogger; if (initialIntents != null) { for (int i = 0; i < initialIntents.length; i++) { @@ -590,6 +593,7 @@ public class ChooserListAdapter extends ResolverListAdapter { mServiceTargets.removeIf(o -> o instanceof ChooserActivity.PlaceHolderTargetInfo); if (mServiceTargets.isEmpty()) { mServiceTargets.add(new ChooserActivity.EmptyTargetInfo()); + mChooserActivityLogger.logSharesheetEmptyDirectShareRow(); } notifyDataSetChanged(); } diff --git a/core/java/com/android/internal/app/IAppOpsActiveCallback.aidl b/core/java/com/android/internal/app/IAppOpsActiveCallback.aidl index 510af770d126..ae6ad326e7b1 100644 --- a/core/java/com/android/internal/app/IAppOpsActiveCallback.aidl +++ b/core/java/com/android/internal/app/IAppOpsActiveCallback.aidl @@ -18,5 +18,6 @@ package com.android.internal.app; // Iterface to observe op active changes oneway interface IAppOpsActiveCallback { - void opActiveChanged(int op, int uid, String packageName, boolean active); + void opActiveChanged(int op, int uid, String packageName, String attributionTag, + boolean active, int attributionFlags, int attributionChainId); } diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl index c112d09d40e4..9ad457200700 100644 --- a/core/java/com/android/internal/app/IAppOpsService.aidl +++ b/core/java/com/android/internal/app/IAppOpsService.aidl @@ -41,7 +41,8 @@ interface IAppOpsService { boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage); SyncNotedAppOp startOperation(IBinder clientId, int code, int uid, String packageName, @nullable String attributionTag, boolean startIfModeDefault, - boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage); + boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage, + int attributionFlags, int attributionChainId); @UnsupportedAppUsage void finishOperation(IBinder clientId, int code, int uid, String packageName, @nullable String attributionTag); @@ -57,10 +58,12 @@ interface IAppOpsService { SyncNotedAppOp noteProxyOperation(int code, in AttributionSource attributionSource, boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage, boolean skipProxyOperation); - SyncNotedAppOp startProxyOperation(IBinder clientId, int code, in AttributionSource attributionSource, + SyncNotedAppOp startProxyOperation(int code, in AttributionSource attributionSource, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, String message, - boolean shouldCollectMessage, boolean skipProxyOperation); - void finishProxyOperation(IBinder clientId, int code, in AttributionSource attributionSource); + boolean shouldCollectMessage, boolean skipProxyOperation, int proxyAttributionFlags, + int proxiedAttributionFlags, int attributionChainId); + void finishProxyOperation(int code, in AttributionSource attributionSource, + boolean skipProxyOperation); // Remaining methods are only used in Java. int checkPackage(int uid, String packageName); diff --git a/core/java/com/android/internal/app/ResolverListController.java b/core/java/com/android/internal/app/ResolverListController.java index 2b59907cf86b..10ac1bc6ac3d 100644 --- a/core/java/com/android/internal/app/ResolverListController.java +++ b/core/java/com/android/internal/app/ResolverListController.java @@ -70,7 +70,7 @@ public class ResolverListController { UserHandle userHandle) { this(context, pm, targetIntent, referrerPackage, launchedFromUid, userHandle, new ResolverRankerServiceResolverComparator( - context, targetIntent, referrerPackage, null)); + context, targetIntent, referrerPackage, null, null)); } public ResolverListController( diff --git a/core/java/com/android/internal/app/ResolverRankerServiceResolverComparator.java b/core/java/com/android/internal/app/ResolverRankerServiceResolverComparator.java index 286945037ab7..cb946c0dcf99 100644 --- a/core/java/com/android/internal/app/ResolverRankerServiceResolverComparator.java +++ b/core/java/com/android/internal/app/ResolverRankerServiceResolverComparator.java @@ -85,7 +85,8 @@ class ResolverRankerServiceResolverComparator extends AbstractResolverComparator private CountDownLatch mConnectSignal; public ResolverRankerServiceResolverComparator(Context context, Intent intent, - String referrerPackage, AfterCompute afterCompute) { + String referrerPackage, AfterCompute afterCompute, + ChooserActivityLogger chooserActivityLogger) { super(context, intent); mCollator = Collator.getInstance(context.getResources().getConfiguration().locale); mReferrerPackage = referrerPackage; @@ -97,6 +98,7 @@ class ResolverRankerServiceResolverComparator extends AbstractResolverComparator mAction = intent.getAction(); mRankerServiceName = new ComponentName(mContext, this.getClass()); setCallBack(afterCompute); + setChooserActivityLogger(chooserActivityLogger); } @Override diff --git a/core/java/com/android/internal/content/F2fsUtils.java b/core/java/com/android/internal/content/F2fsUtils.java new file mode 100644 index 000000000000..27f1b308ed9c --- /dev/null +++ b/core/java/com/android/internal/content/F2fsUtils.java @@ -0,0 +1,296 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.content; + +import android.annotation.NonNull; +import android.content.ContentResolver; +import android.os.Environment; +import android.os.incremental.IncrementalManager; +import android.provider.Settings.Secure; +import android.text.TextUtils; +import android.util.Slog; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.List; + +/** + * Utility methods to work with the f2fs file system. + */ +public final class F2fsUtils { + private static final String TAG = "F2fsUtils"; + private static final boolean DEBUG_F2FS = false; + + /** Directory containing kernel features */ + private static final File sKernelFeatures = + new File("/sys/fs/f2fs/features"); + /** File containing features enabled on "/data" */ + private static final File sUserDataFeatures = + new File("/dev/sys/fs/by-name/userdata/features"); + private static final File sDataDirectory = Environment.getDataDirectory(); + /** Name of the compression feature */ + private static final String COMPRESSION_FEATURE = "compression"; + + private static final boolean sKernelCompressionAvailable; + private static final boolean sUserDataCompressionAvailable; + + static { + sKernelCompressionAvailable = isCompressionEnabledInKernel(); + if (!sKernelCompressionAvailable) { + if (DEBUG_F2FS) { + Slog.d(TAG, "f2fs compression DISABLED; feature not part of the kernel"); + } + } + sUserDataCompressionAvailable = isCompressionEnabledOnUserData(); + if (!sUserDataCompressionAvailable) { + if (DEBUG_F2FS) { + Slog.d(TAG, "f2fs compression DISABLED; feature not enabled on filesystem"); + } + } + } + + /** + * Releases compressed blocks from eligible installation artifacts. + * <p> + * Modern f2fs implementations starting in {@code S} support compression + * natively within the file system. The data blocks of specific installation + * artifacts [eg. .apk, .so, ...] can be compressed at the file system level, + * making them look and act like any other uncompressed file, but consuming + * a fraction of the space. + * <p> + * However, the unused space is not free'd automatically. Instead, we must + * manually tell the file system to release the extra blocks [the delta between + * the compressed and uncompressed block counts] back to the free pool. + * <p> + * Because of how compression works within the file system, once the blocks + * have been released, the file becomes read-only and cannot be modified until + * the free'd blocks have again been reserved from the free pool. + */ + public static void releaseCompressedBlocks(ContentResolver resolver, File file) { + if (!sKernelCompressionAvailable || !sUserDataCompressionAvailable) { + return; + } + + // NOTE: Retrieving this setting means we need to delay releasing cblocks + // of any APKs installed during the PackageManagerService constructor. Instead + // of being able to release them in the constructor, they can only be released + // immediately prior to the system being available. When we no longer need to + // read this setting, move cblock release back to the package manager constructor. + final boolean releaseCompressBlocks = + Secure.getInt(resolver, Secure.RELEASE_COMPRESS_BLOCKS_ON_INSTALL, 1) != 0; + if (!releaseCompressBlocks) { + if (DEBUG_F2FS) { + Slog.d(TAG, "SKIP; release compress blocks not enabled"); + } + return; + } + if (!isCompressionAllowed(file)) { + if (DEBUG_F2FS) { + Slog.d(TAG, "SKIP; compression not allowed"); + } + return; + } + final File[] files = getFilesToRelease(file); + if (files == null || files.length == 0) { + if (DEBUG_F2FS) { + Slog.d(TAG, "SKIP; no files to compress"); + } + return; + } + for (int i = files.length - 1; i >= 0; --i) { + final long releasedBlocks = nativeReleaseCompressedBlocks(files[i].getAbsolutePath()); + if (DEBUG_F2FS) { + Slog.d(TAG, "RELEASED " + releasedBlocks + " blocks" + + " from \"" + files[i] + "\""); + } + } + } + + /** + * Returns {@code true} if compression is allowed on the file system containing + * the given file. + * <p> + * NOTE: The return value does not mean if the given file, or any other file + * on the same file system, is actually compressed. It merely determines whether + * not files <em>may</em> be compressed. + */ + private static boolean isCompressionAllowed(@NonNull File file) { + final String filePath; + try { + filePath = file.getCanonicalPath(); + } catch (IOException e) { + if (DEBUG_F2FS) { + Slog.d(TAG, "f2fs compression DISABLED; could not determine path"); + } + return false; + } + if (IncrementalManager.isIncrementalPath(filePath)) { + if (DEBUG_F2FS) { + Slog.d(TAG, "f2fs compression DISABLED; file on incremental fs"); + } + return false; + } + if (!isChild(sDataDirectory, filePath)) { + if (DEBUG_F2FS) { + Slog.d(TAG, "f2fs compression DISABLED; file not on /data"); + } + return false; + } + if (DEBUG_F2FS) { + Slog.d(TAG, "f2fs compression ENABLED"); + } + return true; + } + + /** + * Returns {@code true} if the given child is a descendant of the base. + */ + private static boolean isChild(@NonNull File base, @NonNull String childPath) { + try { + base = base.getCanonicalFile(); + + File parentFile = new File(childPath).getCanonicalFile(); + while (parentFile != null) { + if (base.equals(parentFile)) { + return true; + } + parentFile = parentFile.getParentFile(); + } + return false; + } catch (IOException ignore) { + return false; + } + } + + /** + * Returns whether or not the compression feature is enabled in the kernel. + * <p> + * NOTE: This doesn't mean compression is enabled on a particular file system + * or any files have been compressed. Only that the functionality is enabled + * on the device. + */ + private static boolean isCompressionEnabledInKernel() { + final File[] features = sKernelFeatures.listFiles(); + if (features == null || features.length == 0) { + if (DEBUG_F2FS) { + Slog.d(TAG, "ERROR; no kernel features"); + } + return false; + } + for (int i = features.length - 1; i >= 0; --i) { + final File feature = features[i]; + if (COMPRESSION_FEATURE.equals(features[i].getName())) { + if (DEBUG_F2FS) { + Slog.d(TAG, "FOUND kernel compression feature"); + } + return true; + } + } + if (DEBUG_F2FS) { + Slog.d(TAG, "ERROR; kernel compression feature not found"); + } + return false; + } + + /** + * Returns whether or not the compression feature is enabled on user data [ie. "/data"]. + * <p> + * NOTE: This doesn't mean any files have been compressed. Only that the functionality + * is enabled on the file system. + */ + private static boolean isCompressionEnabledOnUserData() { + if (!sUserDataFeatures.exists() + || !sUserDataFeatures.isFile() + || !sUserDataFeatures.canRead()) { + if (DEBUG_F2FS) { + Slog.d(TAG, "ERROR; filesystem features not available"); + } + return false; + } + final List<String> configLines; + try { + configLines = Files.readAllLines(sUserDataFeatures.toPath()); + } catch (IOException ignore) { + if (DEBUG_F2FS) { + Slog.d(TAG, "ERROR; couldn't read filesystem features"); + } + return false; + } + if (configLines == null + || configLines.size() > 1 + || TextUtils.isEmpty(configLines.get(0))) { + if (DEBUG_F2FS) { + Slog.d(TAG, "ERROR; no filesystem features"); + } + return false; + } + final String[] features = configLines.get(0).split(","); + for (int i = features.length - 1; i >= 0; --i) { + if (COMPRESSION_FEATURE.equals(features[i].trim())) { + if (DEBUG_F2FS) { + Slog.d(TAG, "FOUND filesystem compression feature"); + } + return true; + } + } + if (DEBUG_F2FS) { + Slog.d(TAG, "ERROR; filesystem compression feature not found"); + } + return false; + } + + /** + * Returns all files contained within the directory at any depth from the given path. + */ + private static List<File> getFilesRecursive(@NonNull File path) { + final File[] allFiles = path.listFiles(); + if (allFiles == null) { + return null; + } + final ArrayList<File> files = new ArrayList<>(); + for (File f : allFiles) { + if (f.isDirectory()) { + files.addAll(getFilesRecursive(f)); + } else if (f.isFile()) { + files.add(f); + } + } + return files; + } + + /** + * Returns all files contained within the directory at any depth from the given path. + */ + private static File[] getFilesToRelease(@NonNull File codePath) { + final List<File> files = getFilesRecursive(codePath); + if (files == null) { + if (codePath.isFile()) { + return new File[] { codePath }; + } + return null; + } + if (files.size() == 0) { + return null; + } + return files.toArray(new File[files.size()]); + } + + private static native long nativeReleaseCompressedBlocks(String path); + +} diff --git a/core/java/com/android/internal/content/OWNERS b/core/java/com/android/internal/content/OWNERS new file mode 100644 index 000000000000..c42bee69410d --- /dev/null +++ b/core/java/com/android/internal/content/OWNERS @@ -0,0 +1,5 @@ +# Bug component: 36137 +include /core/java/android/content/pm/OWNERS + +per-file ReferrerIntent.aidl = file:/services/core/java/com/android/server/am/OWNERS +per-file ReferrerIntent.java = file:/services/core/java/com/android/server/am/OWNERS diff --git a/core/jni/Android.bp b/core/jni/Android.bp index 146863342f47..314299d83020 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -84,6 +84,7 @@ cc_library_shared { android: { srcs: [ "AndroidRuntime.cpp", + "com_android_internal_content_F2fsUtils.cpp", "com_android_internal_content_NativeLibraryHelper.cpp", "com_google_android_gles_jni_EGLImpl.cpp", "com_google_android_gles_jni_GLImpl.cpp", // TODO: .arm @@ -222,7 +223,6 @@ cc_library_shared { "fd_utils.cpp", "android_hardware_input_InputWindowHandle.cpp", "android_hardware_input_InputApplicationHandle.cpp", - "permission_utils.cpp", ], static_libs: [ @@ -241,7 +241,6 @@ cc_library_shared { "audioflinger-aidl-cpp", "av-types-aidl-cpp", "android.hardware.camera.device@3.2", - "media_permission-aidl-cpp", "libandroidicu", "libbpf_android", "libnetdbpf", @@ -258,6 +257,7 @@ cc_library_shared { "libgraphicsenv", "libgui", "libmediandk", + "libpermission", "libsensor", "libinput", "libcamera_client", diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 7e8fc7e6ba4f..00652ac99e58 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -98,7 +98,6 @@ extern int register_android_media_AudioVolumeGroupChangeHandler(JNIEnv *env); extern int register_android_media_MicrophoneInfo(JNIEnv *env); extern int register_android_media_ToneGenerator(JNIEnv *env); extern int register_android_media_midi(JNIEnv *env); -extern int register_android_media_permission_Identity(JNIEnv* env); namespace android { @@ -190,6 +189,7 @@ extern int register_android_content_res_ObbScanner(JNIEnv* env); extern int register_android_content_res_Configuration(JNIEnv* env); extern int register_android_animation_PropertyValuesHolder(JNIEnv *env); extern int register_android_security_Scrypt(JNIEnv *env); +extern int register_com_android_internal_content_F2fsUtils(JNIEnv* env); extern int register_com_android_internal_content_NativeLibraryHelper(JNIEnv *env); extern int register_com_android_internal_content_om_OverlayConfig(JNIEnv *env); extern int register_com_android_internal_net_NetworkUtilsInternal(JNIEnv* env); @@ -1591,7 +1591,6 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_media_RemoteDisplay), REG_JNI(register_android_media_ToneGenerator), REG_JNI(register_android_media_midi), - REG_JNI(register_android_media_permission_Identity), REG_JNI(register_android_opengl_classes), REG_JNI(register_android_server_NetworkManagementSocketTagger), @@ -1621,6 +1620,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_animation_PropertyValuesHolder), REG_JNI(register_android_security_Scrypt), + REG_JNI(register_com_android_internal_content_F2fsUtils), REG_JNI(register_com_android_internal_content_NativeLibraryHelper), REG_JNI(register_com_android_internal_os_DmabufInfoReader), REG_JNI(register_com_android_internal_os_FuseAppLoop), diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp index 83dc1e0bb0d9..bce4ed78eda1 100644 --- a/core/jni/android_media_AudioRecord.cpp +++ b/core/jni/android_media_AudioRecord.cpp @@ -22,13 +22,15 @@ #include <jni.h> #include <nativehelper/JNIHelp.h> #include "core_jni_helpers.h" -#include "permission_utils.h" #include <utils/Log.h> #include <media/AudioRecord.h> #include <media/MicrophoneInfo.h> #include <vector> +#include <android/content/AttributionSourceState.h> +#include <android_os_Parcel.h> + #include <nativehelper/ScopedUtfChars.h> #include "android_media_AudioFormat.h" @@ -38,10 +40,8 @@ #include "android_media_MicrophoneInfo.h" #include "android_media_AudioAttributes.h" -// ---------------------------------------------------------------------------- -using android::media::permission::convertIdentity; -using android::media::permission::Identity; +// ---------------------------------------------------------------------------- using namespace android; @@ -189,7 +189,7 @@ static jint android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject w jobject jaa, jintArray jSampleRate, jint channelMask, jint channelIndexMask, jint audioFormat, jint buffSizeInBytes, jintArray jSession, - jobject jIdentity, jlong nativeRecordInJavaObj, + jobject jAttributionSource, jlong nativeRecordInJavaObj, jint sharedAudioHistoryMs) { //ALOGV(">> Entering android_media_AudioRecord_setup"); //ALOGV("sampleRate=%d, audioFormat=%d, channel mask=%x, buffSizeInBytes=%d " @@ -260,14 +260,18 @@ static jint android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject w size_t bytesPerSample = audio_bytes_per_sample(format); if (buffSizeInBytes == 0) { - ALOGE("Error creating AudioRecord: frameCount is 0."); + ALOGE("Error creating AudioRecord: frameCount is 0."); return (jint) AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT; } size_t frameSize = channelCount * bytesPerSample; size_t frameCount = buffSizeInBytes / frameSize; // create an uninitialized AudioRecord object - lpRecorder = new AudioRecord(convertIdentity(env, jIdentity)); + Parcel* parcel = parcelForJavaObject(env, jAttributionSource); + android::content::AttributionSourceState attributionSource; + attributionSource.readFromParcel(parcel); + + lpRecorder = new AudioRecord(attributionSource); // read the AudioAttributes values auto paa = JNIAudioAttributeHelper::makeUnique(); @@ -912,7 +916,7 @@ static const JNINativeMethod gMethods[] = { {"native_start", "(II)I", (void *)android_media_AudioRecord_start}, {"native_stop", "()V", (void *)android_media_AudioRecord_stop}, {"native_setup", - "(Ljava/lang/Object;Ljava/lang/Object;[IIIII[ILandroid/media/permission/Identity;JI)I", + "(Ljava/lang/Object;Ljava/lang/Object;[IIIII[ILandroid/os/Parcel;JI)I", (void *)android_media_AudioRecord_setup}, {"native_finalize", "()V", (void *)android_media_AudioRecord_finalize}, {"native_release", "()V", (void *)android_media_AudioRecord_release}, diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp index de5df202ba4e..73d2d8d949cd 100644 --- a/core/jni/android_media_AudioTrack.cpp +++ b/core/jni/android_media_AudioTrack.cpp @@ -48,7 +48,6 @@ using namespace android; using ::android::media::VolumeShaper; -using ::android::media::permission::Identity; // ---------------------------------------------------------------------------- static const char* const kClassPathName = "android/media/AudioTrack"; @@ -330,9 +329,10 @@ static jint android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject we // create the native AudioTrack object ScopedUtfChars opPackageNameStr(env, opPackageName); // TODO b/182469354: make consistent with AudioRecord - Identity identity = Identity(); - identity.packageName = std::string(opPackageNameStr.c_str()); - lpTrack = new AudioTrack(identity); + AttributionSourceState attributionSource; + attributionSource.packageName = std::string(opPackageNameStr.c_str()); + attributionSource.token = sp<BBinder>::make(); + lpTrack = new AudioTrack(attributionSource); // read the AudioAttributes values auto paa = JNIAudioAttributeHelper::makeUnique(); @@ -395,7 +395,7 @@ static jint android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject we offload ? AudioTrack::TRANSFER_SYNC_NOTIF_CALLBACK : AudioTrack::TRANSFER_SYNC, (offload || encapsulationMode) ? &offloadInfo : NULL, - Identity(), // default uid, pid values + AttributionSourceState(), // default uid, pid values paa.get()); break; @@ -421,7 +421,7 @@ static jint android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject we sessionId, // audio session ID AudioTrack::TRANSFER_SHARED, NULL, // default offloadInfo - Identity(), // default uid, pid values + AttributionSourceState(), // default uid, pid values paa.get()); break; diff --git a/core/jni/com_android_internal_content_F2fsUtils.cpp b/core/jni/com_android_internal_content_F2fsUtils.cpp new file mode 100644 index 000000000000..8b9d59c416a0 --- /dev/null +++ b/core/jni/com_android_internal_content_F2fsUtils.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "F2fsUtils" + +#include "core_jni_helpers.h" + +#include <nativehelper/ScopedUtfChars.h> +#include <nativehelper/jni_macros.h> + +#include <sys/ioctl.h> +#include <sys/types.h> + +#include <linux/f2fs.h> +#include <linux/fs.h> + +#include <android-base/unique_fd.h> + +#include <utils/Log.h> + +#include <errno.h> +#include <fcntl.h> + +#include <array> + +using namespace std::literals; + +namespace android { + +static jlong com_android_internal_content_F2fsUtils_nativeReleaseCompressedBlocks(JNIEnv *env, + jclass clazz, + jstring path) { + unsigned long long blkcnt; + int ret; + ScopedUtfChars filePath(env, path); + + android::base::unique_fd fd(open(filePath.c_str(), O_RDONLY | O_CLOEXEC, 0)); + if (fd < 0) { + ALOGW("Failed to open file: %s (%d)\n", filePath.c_str(), errno); + return 0; + } + + long flags = 0; + ret = ioctl(fd, FS_IOC_GETFLAGS, &flags); + if (ret < 0) { + ALOGW("Failed to get flags for file: %s (%d)\n", filePath.c_str(), errno); + return 0; + } + if ((flags & FS_COMPR_FL) == 0) { + return 0; + } + + ret = ioctl(fd, F2FS_IOC_RELEASE_COMPRESS_BLOCKS, &blkcnt); + if (ret < 0) { + return -errno; + } + return blkcnt; +} + +static const std::array gMethods = { + MAKE_JNI_NATIVE_METHOD( + "nativeReleaseCompressedBlocks", "(Ljava/lang/String;)J", + com_android_internal_content_F2fsUtils_nativeReleaseCompressedBlocks), +}; + +int register_com_android_internal_content_F2fsUtils(JNIEnv *env) { + return RegisterMethodsOrDie(env, "com/android/internal/content/F2fsUtils", gMethods.data(), + gMethods.size()); +} + +}; // namespace android diff --git a/core/jni/permission_utils.cpp b/core/jni/permission_utils.cpp deleted file mode 100644 index 2b7ef9999491..000000000000 --- a/core/jni/permission_utils.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "permission_utils.h" -#include "core_jni_helpers.h" - -static struct { - jfieldID fieldUid; // Identity.uid - jfieldID fieldPid; // Identity.pid - jfieldID fieldPackageName; // Identity.packageName - jfieldID fieldAttributionTag; // Identity.attributionTag -} javaIdentityFields; - -static const JNINativeMethod method_table[] = { - // no static methods, currently -}; - -int register_android_media_permission_Identity(JNIEnv* env) { - jclass identityClass = android::FindClassOrDie(env, "android/media/permission/Identity"); - javaIdentityFields.fieldUid = android::GetFieldIDOrDie(env, identityClass, "uid", "I"); - javaIdentityFields.fieldPid = android::GetFieldIDOrDie(env, identityClass, "pid", "I"); - javaIdentityFields.fieldPackageName = - android::GetFieldIDOrDie(env, identityClass, "packageName", "Ljava/lang/String;"); - javaIdentityFields.fieldAttributionTag = - android::GetFieldIDOrDie(env, identityClass, "attributionTag", "Ljava/lang/String;"); - - return android::RegisterMethodsOrDie(env, "android/media/permission/Identity", method_table, - NELEM(method_table)); -} - -namespace android::media::permission { - -Identity convertIdentity(JNIEnv* env, const jobject& jIdentity) { - Identity identity; - - identity.uid = env->GetIntField(jIdentity, javaIdentityFields.fieldUid); - identity.pid = env->GetIntField(jIdentity, javaIdentityFields.fieldPid); - - jstring packageNameStr = static_cast<jstring>( - env->GetObjectField(jIdentity, javaIdentityFields.fieldPackageName)); - if (packageNameStr == nullptr) { - identity.packageName = std::nullopt; - } else { - identity.packageName = std::string(ScopedUtfChars(env, packageNameStr).c_str()); - } - - jstring attributionTagStr = static_cast<jstring>( - env->GetObjectField(jIdentity, javaIdentityFields.fieldAttributionTag)); - if (attributionTagStr == nullptr) { - identity.attributionTag = std::nullopt; - } else { - identity.attributionTag = std::string(ScopedUtfChars(env, attributionTagStr).c_str()); - } - - return identity; -} - -} // namespace android::media::permission diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index f457c5626fba..6b6cbea94009 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1625,16 +1625,16 @@ <eat-comment /> <!-- Allows an application to modify and remove existing voicemails in the system. - <p>Protection level: signature|privileged + <p>Protection level: signature|privileged|role --> <permission android:name="com.android.voicemail.permission.WRITE_VOICEMAIL" - android:protectionLevel="signature|privileged" /> + android:protectionLevel="signature|privileged|role" /> <!-- Allows an application to read voicemails in the system. - <p>Protection level: signature|privileged + <p>Protection level: signature|privileged|role --> <permission android:name="com.android.voicemail.permission.READ_VOICEMAIL" - android:protectionLevel="signature|privileged" /> + android:protectionLevel="signature|privileged|role" /> <!-- ======================================= --> <!-- Permissions for accessing location info --> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index c864cd66b117..e5f458849b9a 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1971,6 +1971,9 @@ <string name="config_systemActivityRecognizer" translatable="false"></string> <!-- The name of the package that will hold the system ui role --> <string name="config_systemUi" translatable="false">com.android.systemui</string> + <!-- The name of the package that will hold the television remote service role. + TODO(b/189347385) make this a @SystemAPI --> + <string name="config_systemTelevisionRemoteService" translatable="false">@string/config_tvRemoteServicePackage</string> <!-- The name of the package that will be allowed to change its components' label/icon. --> <string name="config_overrideComponentUiPackage" translatable="false">com.android.stk</string> diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index d3343060a819..ea93520502d5 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -939,4 +939,8 @@ <!-- System-provided padding for inner views on app widgets. The resolved value of this resource may change at runtime. @removed --> <dimen name="__removed_system_app_widget_internal_padding">16dp</dimen> + <!-- The width/height of the icon view on staring surface. --> + <dimen name="starting_surface_icon_size">160dp</dimen> + <!-- The default width/height of the icon on the spec of adaptive icon drawable. --> + <dimen name="starting_surface_default_icon_size">108dp</dimen> </resources> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index ef5cfe33c661..2403a605972e 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -3027,222 +3027,178 @@ <public type="bool" name="config_assistantOnTopOfDream" id="0x01110005" /> <!-- @hide @TestApi --> <public type="bool" name="config_remoteInsetsControllerControlsSystemBars" id="0x01110006" /> - <!-- =============================================================== - Resources added in version S of the platform - - NOTE: add <public> elements within a <staging-public-group> like so: - <staging-public-group type="attr" first-id="0x01010531"> - <public name="exampleAttr1" /> - <public name="exampleAttr2" /> - </staging-public-group> - - To add a new public-group block, choose an id value that is 1 greater - than the last of that item above. For example, the last "attr" id - value above is 0x01010530, so the public-group of attrs below has - the id value of 0x01010531. + <!-- =============================================================== + Resources added in version S of the platform =============================================================== --> - <eat-comment /> + <eat-comment /> - <staging-public-group type="attr" first-id="0x01010617"> - <public name="rollbackDataPolicy" /> - <public name="allowClickWhenDisabled" /> - <public name="windowLayoutAffinity" /> - <public name="canPauseRecording" /> - <public name="windowBlurBehindRadius"/> - <public name="windowBlurBehindEnabled"/> - <public name="requireDeviceScreenOn" /> - <public name="pathSuffix" /> - <public name="sspSuffix" /> - <public name="pathAdvancedPattern" /> - <public name="sspAdvancedPattern" /> - <public name="fontProviderSystemFontFamily" /> - <public name="hand_second" /> - <public name="memtagMode" /> - <public name="nativeHeapZeroInitialized" /> + <public type="attr" name="rollbackDataPolicy" id="0x01010617" /> + <public type="attr" name="allowClickWhenDisabled" id="0x01010618" /> + <public type="attr" name="windowLayoutAffinity" id="0x01010619" /> + <public type="attr" name="canPauseRecording" id="0x0101061a" /> + <public type="attr" name="windowBlurBehindRadius" id="0x0101061b" /> + <public type="attr" name="windowBlurBehindEnabled" id="0x0101061c" /> + <public type="attr" name="requireDeviceScreenOn" id="0x0101061d" /> + <public type="attr" name="pathSuffix" id="0x0101061e" /> + <public type="attr" name="sspSuffix" id="0x0101061f" /> + <public type="attr" name="pathAdvancedPattern" id="0x01010620" /> + <public type="attr" name="sspAdvancedPattern" id="0x01010621" /> + <public type="attr" name="fontProviderSystemFontFamily" id="0x01010622" /> + <public type="attr" name="hand_second" id="0x01010623" /> + <public type="attr" name="memtagMode" id="0x01010624" /> + <public type="attr" name="nativeHeapZeroInitialized" id="0x01010625" /> <!-- @hide @SystemApi --> - <public name="hotwordDetectionService" /> - <public name="previewLayout" /> - <public name="clipToOutline" /> - <public name="__removed3" /> - <public name="knownCerts" /> - <public name="windowBackgroundBlurRadius"/> - <public name="windowSplashScreenBackground"/> - <public name="windowSplashScreenAnimatedIcon"/> - <public name="windowSplashScreenAnimationDuration"/> - <public name="windowSplashScreenBrandingImage"/> - <public name="windowSplashScreenIconBackgroundColor"/> - <public name="splashScreenTheme" /> - <public name="maxResizeWidth" /> - <public name="maxResizeHeight" /> - <public name="targetCellWidth" /> - <public name="targetCellHeight" /> - <public name="dialTint"/> - <public name="dialTintMode"/> - <public name="hand_hourTint"/> - <public name="hand_hourTintMode"/> - <public name="hand_minuteTint"/> - <public name="hand_minuteTintMode"/> - <public name="hand_secondTint"/> - <public name="hand_secondTintMode"/> - <public name="dataExtractionRules"/> - <public name="passwordsActivity"/> - <public name="selectableAsDefault"/> - <public name="isAccessibilityTool"/> - <public name="attributionTags"/> - <public name="suppressesSpellChecker" /> - <public name="usesPermissionFlags" /> - <public name="requestRawExternalStorageAccess" /> + <public type="attr" name="hotwordDetectionService" id="0x01010626" /> + <public type="attr" name="previewLayout" id="0x01010627" /> + <public type="attr" name="clipToOutline" id="0x01010628" /> + <!-- <public type="attr" name="__removed3" id="0x01010629" /> --> + <public type="attr" name="knownCerts" id="0x0101062a" /> + <public type="attr" name="windowBackgroundBlurRadius" id="0x0101062b" /> + <public type="attr" name="windowSplashScreenBackground" id="0x0101062c" /> + <public type="attr" name="windowSplashScreenAnimatedIcon" id="0x0101062d" /> + <public type="attr" name="windowSplashScreenAnimationDuration" id="0x0101062e" /> + <public type="attr" name="windowSplashScreenBrandingImage" id="0x0101062f" /> + <public type="attr" name="windowSplashScreenIconBackgroundColor" id="0x01010630" /> + <public type="attr" name="splashScreenTheme" id="0x01010631" /> + <public type="attr" name="maxResizeWidth" id="0x01010632" /> + <public type="attr" name="maxResizeHeight" id="0x01010633" /> + <public type="attr" name="targetCellWidth" id="0x01010634" /> + <public type="attr" name="targetCellHeight" id="0x01010635" /> + <public type="attr" name="dialTint" id="0x01010636" /> + <public type="attr" name="dialTintMode" id="0x01010637" /> + <public type="attr" name="hand_hourTint" id="0x01010638" /> + <public type="attr" name="hand_hourTintMode" id="0x01010639" /> + <public type="attr" name="hand_minuteTint" id="0x0101063a" /> + <public type="attr" name="hand_minuteTintMode" id="0x0101063b" /> + <public type="attr" name="hand_secondTint" id="0x0101063c" /> + <public type="attr" name="hand_secondTintMode" id="0x0101063d" /> + <public type="attr" name="dataExtractionRules" id="0x0101063e" /> + <public type="attr" name="passwordsActivity" id="0x0101063f" /> + <public type="attr" name="selectableAsDefault" id="0x01010640" /> + <public type="attr" name="isAccessibilityTool" id="0x01010641" /> + <public type="attr" name="attributionTags" id="0x01010642" /> + <public type="attr" name="suppressesSpellChecker" id="0x01010643" /> + <public type="attr" name="usesPermissionFlags" id="0x01010644" /> + <public type="attr" name="requestRawExternalStorageAccess" id="0x01010645" /> <!-- @hide @SystemApi --> - <public name="playHomeTransitionSound" /> - <public name="lStar" /> - <public name="showInInputMethodPicker" /> - <public name="effectColor" /> + <public type="attr" name="playHomeTransitionSound" id="0x01010646" /> + <public type="attr" name="lStar" id="0x01010647" /> + <public type="attr" name="showInInputMethodPicker" id="0x01010648" /> + <public type="attr" name="effectColor" id="0x01010649" /> <!-- @hide @TestApi --> - <public name="requestForegroundServiceExemption" /> - <public name="attributionsAreUserVisible" /> - </staging-public-group> - - <staging-public-group type="drawable" first-id="0x010800b5"> - <!-- drawable definitions go here --> - </staging-public-group> - - <staging-public-group type="color" first-id="0x0106001d"> - <!-- color definitions go here --> - - <!-- Material design dynamic system palette:--> - <!-- Neutral colors for background and text --> - <public name="system_neutral1_0" /> - <public name="system_neutral1_10" /> - <public name="system_neutral1_50" /> - <public name="system_neutral1_100" /> - <public name="system_neutral1_200" /> - <public name="system_neutral1_300" /> - <public name="system_neutral1_400" /> - <public name="system_neutral1_500" /> - <public name="system_neutral1_600" /> - <public name="system_neutral1_700" /> - <public name="system_neutral1_800" /> - <public name="system_neutral1_900" /> - <public name="system_neutral1_1000" /> - <public name="system_neutral2_0" /> - <public name="system_neutral2_10" /> - <public name="system_neutral2_50" /> - <public name="system_neutral2_100" /> - <public name="system_neutral2_200" /> - <public name="system_neutral2_300" /> - <public name="system_neutral2_400" /> - <public name="system_neutral2_500" /> - <public name="system_neutral2_600" /> - <public name="system_neutral2_700" /> - <public name="system_neutral2_800" /> - <public name="system_neutral2_900" /> - <public name="system_neutral2_1000" /> - <!-- Accent colors, for buttons and UI decorations --> - <public name="system_accent1_0" /> - <public name="system_accent1_10" /> - <public name="system_accent1_50" /> - <public name="system_accent1_100" /> - <public name="system_accent1_200" /> - <public name="system_accent1_300" /> - <public name="system_accent1_400" /> - <public name="system_accent1_500" /> - <public name="system_accent1_600" /> - <public name="system_accent1_700" /> - <public name="system_accent1_800" /> - <public name="system_accent1_900" /> - <public name="system_accent1_1000" /> - <public name="system_accent2_0" /> - <public name="system_accent2_10" /> - <public name="system_accent2_50" /> - <public name="system_accent2_100" /> - <public name="system_accent2_200" /> - <public name="system_accent2_300" /> - <public name="system_accent2_400" /> - <public name="system_accent2_500" /> - <public name="system_accent2_600" /> - <public name="system_accent2_700" /> - <public name="system_accent2_800" /> - <public name="system_accent2_900" /> - <public name="system_accent2_1000" /> - <public name="system_accent3_0" /> - <public name="system_accent3_10" /> - <public name="system_accent3_50" /> - <public name="system_accent3_100" /> - <public name="system_accent3_200" /> - <public name="system_accent3_300" /> - <public name="system_accent3_400" /> - <public name="system_accent3_500" /> - <public name="system_accent3_600" /> - <public name="system_accent3_700" /> - <public name="system_accent3_800" /> - <public name="system_accent3_900" /> - <public name="system_accent3_1000" /> - </staging-public-group> - - <staging-public-group type="dimen" first-id="0x01050008"> - <!-- dimension definitions go here --> - - <!-- System-provided dimensions for app widgets. --> - <public name="system_app_widget_background_radius" /> - <public name="system_app_widget_inner_radius" /> - <public name="__removed_system_app_widget_internal_padding" /> - </staging-public-group> - - <staging-public-group type="bool" first-id="0x01110007"> - <!-- boolean definitions go here --> - </staging-public-group> - - <staging-public-group type="style" first-id="0x010302e5"> - <!-- style definitions go here --> - </staging-public-group> - - <staging-public-group type="string" first-id="0x01040028"> + <public type="attr" name="requestForegroundServiceExemption" id="0x0101064a" /> + <public type="attr" name="attributionsAreUserVisible" id="0x0101064b" /> + + <public type="color" name="system_neutral1_0" id="0x0106001d" /> + <public type="color" name="system_neutral1_10" id="0x0106001e" /> + <public type="color" name="system_neutral1_50" id="0x0106001f" /> + <public type="color" name="system_neutral1_100" id="0x01060020" /> + <public type="color" name="system_neutral1_200" id="0x01060021" /> + <public type="color" name="system_neutral1_300" id="0x01060022" /> + <public type="color" name="system_neutral1_400" id="0x01060023" /> + <public type="color" name="system_neutral1_500" id="0x01060024" /> + <public type="color" name="system_neutral1_600" id="0x01060025" /> + <public type="color" name="system_neutral1_700" id="0x01060026" /> + <public type="color" name="system_neutral1_800" id="0x01060027" /> + <public type="color" name="system_neutral1_900" id="0x01060028" /> + <public type="color" name="system_neutral1_1000" id="0x01060029" /> + <public type="color" name="system_neutral2_0" id="0x0106002a" /> + <public type="color" name="system_neutral2_10" id="0x0106002b" /> + <public type="color" name="system_neutral2_50" id="0x0106002c" /> + <public type="color" name="system_neutral2_100" id="0x0106002d" /> + <public type="color" name="system_neutral2_200" id="0x0106002e" /> + <public type="color" name="system_neutral2_300" id="0x0106002f" /> + <public type="color" name="system_neutral2_400" id="0x01060030" /> + <public type="color" name="system_neutral2_500" id="0x01060031" /> + <public type="color" name="system_neutral2_600" id="0x01060032" /> + <public type="color" name="system_neutral2_700" id="0x01060033" /> + <public type="color" name="system_neutral2_800" id="0x01060034" /> + <public type="color" name="system_neutral2_900" id="0x01060035" /> + <public type="color" name="system_neutral2_1000" id="0x01060036" /> + <public type="color" name="system_accent1_0" id="0x01060037" /> + <public type="color" name="system_accent1_10" id="0x01060038" /> + <public type="color" name="system_accent1_50" id="0x01060039" /> + <public type="color" name="system_accent1_100" id="0x0106003a" /> + <public type="color" name="system_accent1_200" id="0x0106003b" /> + <public type="color" name="system_accent1_300" id="0x0106003c" /> + <public type="color" name="system_accent1_400" id="0x0106003d" /> + <public type="color" name="system_accent1_500" id="0x0106003e" /> + <public type="color" name="system_accent1_600" id="0x0106003f" /> + <public type="color" name="system_accent1_700" id="0x01060040" /> + <public type="color" name="system_accent1_800" id="0x01060041" /> + <public type="color" name="system_accent1_900" id="0x01060042" /> + <public type="color" name="system_accent1_1000" id="0x01060043" /> + <public type="color" name="system_accent2_0" id="0x01060044" /> + <public type="color" name="system_accent2_10" id="0x01060045" /> + <public type="color" name="system_accent2_50" id="0x01060046" /> + <public type="color" name="system_accent2_100" id="0x01060047" /> + <public type="color" name="system_accent2_200" id="0x01060048" /> + <public type="color" name="system_accent2_300" id="0x01060049" /> + <public type="color" name="system_accent2_400" id="0x0106004a" /> + <public type="color" name="system_accent2_500" id="0x0106004b" /> + <public type="color" name="system_accent2_600" id="0x0106004c" /> + <public type="color" name="system_accent2_700" id="0x0106004d" /> + <public type="color" name="system_accent2_800" id="0x0106004e" /> + <public type="color" name="system_accent2_900" id="0x0106004f" /> + <public type="color" name="system_accent2_1000" id="0x01060050" /> + <public type="color" name="system_accent3_0" id="0x01060051" /> + <public type="color" name="system_accent3_10" id="0x01060052" /> + <public type="color" name="system_accent3_50" id="0x01060053" /> + <public type="color" name="system_accent3_100" id="0x01060054" /> + <public type="color" name="system_accent3_200" id="0x01060055" /> + <public type="color" name="system_accent3_300" id="0x01060056" /> + <public type="color" name="system_accent3_400" id="0x01060057" /> + <public type="color" name="system_accent3_500" id="0x01060058" /> + <public type="color" name="system_accent3_600" id="0x01060059" /> + <public type="color" name="system_accent3_700" id="0x0106005a" /> + <public type="color" name="system_accent3_800" id="0x0106005b" /> + <public type="color" name="system_accent3_900" id="0x0106005c" /> + <public type="color" name="system_accent3_1000" id="0x0106005d" /> + + <public type="dimen" name="system_app_widget_background_radius" id="0x01050008" /> + <public type="dimen" name="system_app_widget_inner_radius" id="0x01050009" /> + <!-- @hide @SystemApi @TestApi --> - <public name="config_systemAutomotiveCluster" /> + <public type="string" name="config_systemAutomotiveCluster" id="0x01040028" /> <!-- @hide @SystemApi @TestApi --> - <public name="config_systemAutomotiveProjection" /> + <public type="string" name="config_systemAutomotiveProjection" id="0x01040029" /> <!-- @hide @SystemApi --> - <public name="config_systemShell" /> + <public type="string" name="config_systemShell" id="0x0104002a" /> <!-- @hide @SystemApi --> - <public name="config_systemContacts" /> + <public type="string" name="config_systemContacts" id="0x0104002b" /> <!-- @hide @SystemApi --> - <public name="config_customMediaKeyDispatcher" /> + <public type="string" name="config_customMediaKeyDispatcher" id="0x0104002c" /> <!-- @hide @SystemApi --> - <public name="config_customMediaSessionPolicyProvider" /> + <public type="string" name="config_customMediaSessionPolicyProvider" id="0x0104002d" /> <!-- @hide @SystemApi --> - <public name="config_systemSpeechRecognizer" /> + <public type="string" name="config_systemSpeechRecognizer" id="0x0104002e" /> <!-- @hide @SystemApi --> - <public name="config_systemWifiCoexManager" /> + <public type="string" name="config_systemWifiCoexManager" id="0x0104002f" /> <!-- @hide @SystemApi --> - <public name="config_systemWellbeing" /> + <public type="string" name="config_systemWellbeing" id="0x01040030" /> <!-- @hide @SystemApi --> - <public name="config_systemTelevisionNotificationHandler" /> + <public type="string" name="config_systemTelevisionNotificationHandler" id="0x01040031" /> <!-- @hide @SystemApi --> - <public name="config_systemUiIntelligence" /> + <public type="string" name="config_systemUiIntelligence" id="0x01040032" /> <!-- @hide @SystemApi --> - <public name="config_systemAmbientAudioIntelligence" /> + <public type="string" name="config_systemAmbientAudioIntelligence" id="0x01040033" /> <!-- @hide @SystemApi --> - <public name="config_systemAudioIntelligence" /> + <public type="string" name="config_systemAudioIntelligence" id="0x01040034" /> <!-- @hide @SystemApi --> - <public name="config_systemNotificationIntelligence" /> + <public type="string" name="config_systemNotificationIntelligence" id="0x01040035" /> <!-- @hide @SystemApi --> - <public name="config_systemTextIntelligence" /> + <public type="string" name="config_systemTextIntelligence" id="0x01040036" /> <!-- @hide @SystemApi --> - <public name="config_systemVisualIntelligence" /> + <public type="string" name="config_systemVisualIntelligence" id="0x01040037" /> <!-- @hide @SystemApi --> - <public name="config_systemActivityRecognizer" /> + <public type="string" name="config_systemActivityRecognizer" id="0x01040038" /> <!-- @hide @SystemApi --> - <public name="config_systemCompanionDeviceProvider"/> + <public type="string" name="config_systemCompanionDeviceProvider" id="0x01040039" /> <!-- @hide @SystemApi --> - <public name="config_systemUi" /> + <public type="string" name="config_systemUi" id="0x0104003a" /> <!-- @hide For use by platform and tools only. Developers should not specify this value. --> - <public name="config_defaultRingtoneVibrationSound"/> - </staging-public-group> - - <staging-public-group type="id" first-id="0x01020055"> - <!-- id definitions go here --> - </staging-public-group> + <public type="string" name="config_defaultRingtoneVibrationSound" id="0x0104003b" /> <!-- =============================================================== DO NOT ADD UN-GROUPED ITEMS HERE diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index f30f40a3cfc2..374cea77f6a0 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -4389,4 +4389,7 @@ <java-symbol type="bool" name="config_supportsMicToggle" /> <java-symbol type="bool" name="config_supportsCamToggle" /> + + <java-symbol type="dimen" name="starting_surface_icon_size" /> + <java-symbol type="dimen" name="starting_surface_default_icon_size" /> </resources> diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml index 97acd5b9bf1e..9d0a42d8ecd4 100644 --- a/core/res/res/values/themes_device_defaults.xml +++ b/core/res/res/values/themes_device_defaults.xml @@ -232,6 +232,9 @@ easier. <item name="textColorPrimary">@color/text_color_primary_device_default_dark</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item> + <item name="textColorPrimaryInverse">@color/text_color_primary_device_default_light</item> + <item name="textColorSecondaryInverse">@color/text_color_secondary_device_default_light</item> + <item name="textColorTertiaryInverse">@color/text_color_tertiary_device_default_light</item> <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item> <item name="colorForeground">@color/foreground_device_default_dark</item> <item name="colorForegroundInverse">@color/foreground_device_default_light</item> @@ -261,6 +264,9 @@ easier. <item name="textColorPrimary">@color/text_color_primary_device_default_dark</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item> + <item name="textColorPrimaryInverse">@color/text_color_primary_device_default_light</item> + <item name="textColorSecondaryInverse">@color/text_color_secondary_device_default_light</item> + <item name="textColorTertiaryInverse">@color/text_color_tertiary_device_default_light</item> <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item> <item name="colorForeground">@color/foreground_device_default_dark</item> <item name="colorForegroundInverse">@color/foreground_device_default_light</item> @@ -307,6 +313,9 @@ easier. <item name="textColorPrimary">@color/text_color_primary_device_default_dark</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item> + <item name="textColorPrimaryInverse">@color/text_color_primary_device_default_light</item> + <item name="textColorSecondaryInverse">@color/text_color_secondary_device_default_light</item> + <item name="textColorTertiaryInverse">@color/text_color_tertiary_device_default_light</item> <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item> <item name="colorForeground">@color/foreground_device_default_dark</item> <item name="colorForegroundInverse">@color/foreground_device_default_light</item> @@ -355,6 +364,9 @@ easier. <item name="textColorPrimary">@color/text_color_primary_device_default_dark</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item> + <item name="textColorPrimaryInverse">@color/text_color_primary_device_default_light</item> + <item name="textColorSecondaryInverse">@color/text_color_secondary_device_default_light</item> + <item name="textColorTertiaryInverse">@color/text_color_tertiary_device_default_light</item> <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item> <item name="colorForeground">@color/foreground_device_default_dark</item> <item name="colorForegroundInverse">@color/foreground_device_default_light</item> @@ -402,6 +414,9 @@ easier. <item name="textColorPrimary">@color/text_color_primary_device_default_dark</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item> + <item name="textColorPrimaryInverse">@color/text_color_primary_device_default_light</item> + <item name="textColorSecondaryInverse">@color/text_color_secondary_device_default_light</item> + <item name="textColorTertiaryInverse">@color/text_color_tertiary_device_default_light</item> <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item> <item name="colorForeground">@color/foreground_device_default_dark</item> <item name="colorForegroundInverse">@color/foreground_device_default_light</item> @@ -464,6 +479,9 @@ easier. <item name="textColorPrimary">@color/text_color_primary_device_default_dark</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item> + <item name="textColorPrimaryInverse">@color/text_color_primary_device_default_light</item> + <item name="textColorSecondaryInverse">@color/text_color_secondary_device_default_light</item> + <item name="textColorTertiaryInverse">@color/text_color_tertiary_device_default_light</item> <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item> <item name="colorForeground">@color/foreground_device_default_dark</item> <item name="colorForegroundInverse">@color/foreground_device_default_light</item> @@ -503,6 +521,9 @@ easier. <item name="textColorPrimary">@color/text_color_primary_device_default_dark</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item> + <item name="textColorPrimaryInverse">@color/text_color_primary_device_default_light</item> + <item name="textColorSecondaryInverse">@color/text_color_secondary_device_default_light</item> + <item name="textColorTertiaryInverse">@color/text_color_tertiary_device_default_light</item> <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item> <item name="colorForeground">@color/foreground_device_default_dark</item> <item name="colorForegroundInverse">@color/foreground_device_default_light</item> @@ -548,6 +569,9 @@ easier. <item name="textColorPrimary">@color/text_color_primary_device_default_dark</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item> + <item name="textColorPrimaryInverse">@color/text_color_primary_device_default_light</item> + <item name="textColorSecondaryInverse">@color/text_color_secondary_device_default_light</item> + <item name="textColorTertiaryInverse">@color/text_color_tertiary_device_default_light</item> <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item> <item name="colorForeground">@color/foreground_device_default_dark</item> <item name="colorForegroundInverse">@color/foreground_device_default_light</item> @@ -594,6 +618,9 @@ easier. <item name="textColorPrimary">@color/text_color_primary_device_default_dark</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item> + <item name="textColorPrimaryInverse">@color/text_color_primary_device_default_light</item> + <item name="textColorSecondaryInverse">@color/text_color_secondary_device_default_light</item> + <item name="textColorTertiaryInverse">@color/text_color_tertiary_device_default_light</item> <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item> <item name="colorForeground">@color/foreground_device_default_dark</item> <item name="colorForegroundInverse">@color/foreground_device_default_light</item> @@ -656,6 +683,9 @@ easier. <item name="textColorPrimary">@color/text_color_primary_device_default_dark</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item> + <item name="textColorPrimaryInverse">@color/text_color_primary_device_default_light</item> + <item name="textColorSecondaryInverse">@color/text_color_secondary_device_default_light</item> + <item name="textColorTertiaryInverse">@color/text_color_tertiary_device_default_light</item> <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item> <item name="colorForeground">@color/foreground_device_default_dark</item> <item name="colorForegroundInverse">@color/foreground_device_default_light</item> @@ -703,6 +733,9 @@ easier. <item name="textColorPrimary">@color/text_color_primary_device_default_dark</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item> + <item name="textColorPrimaryInverse">@color/text_color_primary_device_default_light</item> + <item name="textColorSecondaryInverse">@color/text_color_secondary_device_default_light</item> + <item name="textColorTertiaryInverse">@color/text_color_tertiary_device_default_light</item> <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item> <item name="colorForeground">@color/foreground_device_default_dark</item> <item name="colorForegroundInverse">@color/foreground_device_default_light</item> @@ -748,6 +781,9 @@ easier. <item name="textColorPrimary">@color/text_color_primary_device_default_dark</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item> + <item name="textColorPrimaryInverse">@color/text_color_primary_device_default_light</item> + <item name="textColorSecondaryInverse">@color/text_color_secondary_device_default_light</item> + <item name="textColorTertiaryInverse">@color/text_color_tertiary_device_default_light</item> <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item> <item name="colorForeground">@color/foreground_device_default_dark</item> <item name="colorForegroundInverse">@color/foreground_device_default_light</item> @@ -795,6 +831,9 @@ easier. <item name="textColorPrimary">@color/text_color_primary_device_default_dark</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item> + <item name="textColorPrimaryInverse">@color/text_color_primary_device_default_light</item> + <item name="textColorSecondaryInverse">@color/text_color_secondary_device_default_light</item> + <item name="textColorTertiaryInverse">@color/text_color_tertiary_device_default_light</item> <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item> <item name="colorForeground">@color/foreground_device_default_dark</item> <item name="colorForegroundInverse">@color/foreground_device_default_light</item> @@ -841,6 +880,9 @@ easier. <item name="textColorPrimary">@color/text_color_primary_device_default_dark</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item> + <item name="textColorPrimaryInverse">@color/text_color_primary_device_default_light</item> + <item name="textColorSecondaryInverse">@color/text_color_secondary_device_default_light</item> + <item name="textColorTertiaryInverse">@color/text_color_tertiary_device_default_light</item> <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item> <item name="colorForeground">@color/foreground_device_default_dark</item> <item name="colorForegroundInverse">@color/foreground_device_default_light</item> @@ -887,6 +929,9 @@ easier. <item name="textColorPrimary">@color/text_color_primary_device_default_dark</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item> + <item name="textColorPrimaryInverse">@color/text_color_primary_device_default_light</item> + <item name="textColorSecondaryInverse">@color/text_color_secondary_device_default_light</item> + <item name="textColorTertiaryInverse">@color/text_color_tertiary_device_default_light</item> <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item> <item name="colorForeground">@color/foreground_device_default_dark</item> <item name="colorForegroundInverse">@color/foreground_device_default_light</item> @@ -933,6 +978,9 @@ easier. <item name="textColorPrimary">@color/text_color_primary_device_default_light</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_light</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item> + <item name="textColorPrimaryInverse">@color/text_color_primary_device_default_dark</item> + <item name="textColorSecondaryInverse">@color/text_color_secondary_device_default_dark</item> + <item name="textColorTertiaryInverse">@color/text_color_tertiary_device_default_dark</item> <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item> <item name="colorForeground">@color/foreground_device_default_light</item> <item name="colorForegroundInverse">@color/foreground_device_default_dark</item> @@ -979,6 +1027,9 @@ easier. <item name="textColorPrimary">@color/text_color_primary_device_default_light</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_light</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item> + <item name="textColorPrimaryInverse">@color/text_color_primary_device_default_dark</item> + <item name="textColorSecondaryInverse">@color/text_color_secondary_device_default_dark</item> + <item name="textColorTertiaryInverse">@color/text_color_tertiary_device_default_dark</item> <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item> <item name="colorForeground">@color/foreground_device_default_light</item> <item name="colorForegroundInverse">@color/foreground_device_default_dark</item> @@ -1029,6 +1080,9 @@ easier. <item name="textColorPrimary">@color/text_color_primary_device_default_dark</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item> + <item name="textColorPrimaryInverse">@color/text_color_primary_device_default_light</item> + <item name="textColorSecondaryInverse">@color/text_color_secondary_device_default_light</item> + <item name="textColorTertiaryInverse">@color/text_color_tertiary_device_default_light</item> <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item> <item name="colorForeground">@color/foreground_device_default_dark</item> <item name="colorForegroundInverse">@color/foreground_device_default_light</item> @@ -1076,6 +1130,9 @@ easier. <item name="textColorPrimary">@color/text_color_primary_device_default_dark</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item> + <item name="textColorPrimaryInverse">@color/text_color_primary_device_default_light</item> + <item name="textColorSecondaryInverse">@color/text_color_secondary_device_default_light</item> + <item name="textColorTertiaryInverse">@color/text_color_tertiary_device_default_light</item> <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item> <item name="colorForeground">@color/foreground_device_default_dark</item> <item name="colorForegroundInverse">@color/foreground_device_default_light</item> @@ -1120,6 +1177,9 @@ easier. <item name="textColorPrimary">@color/text_color_primary_device_default_dark</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item> + <item name="textColorPrimaryInverse">@color/text_color_primary_device_default_light</item> + <item name="textColorSecondaryInverse">@color/text_color_secondary_device_default_light</item> + <item name="textColorTertiaryInverse">@color/text_color_tertiary_device_default_light</item> <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item> <item name="colorForeground">@color/foreground_device_default_dark</item> <item name="colorForegroundInverse">@color/foreground_device_default_light</item> @@ -1318,6 +1378,9 @@ easier. <item name="textColorPrimary">@color/text_color_primary_device_default_light</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_light</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item> + <item name="textColorPrimaryInverse">@color/text_color_primary_device_default_dark</item> + <item name="textColorSecondaryInverse">@color/text_color_secondary_device_default_dark</item> + <item name="textColorTertiaryInverse">@color/text_color_tertiary_device_default_dark</item> <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item> <item name="colorForeground">@color/foreground_device_default_light</item> <item name="colorForegroundInverse">@color/foreground_device_default_dark</item> @@ -1348,6 +1411,9 @@ easier. <item name="textColorPrimary">@color/text_color_primary_device_default_light</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_light</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item> + <item name="textColorPrimaryInverse">@color/text_color_primary_device_default_dark</item> + <item name="textColorSecondaryInverse">@color/text_color_secondary_device_default_dark</item> + <item name="textColorTertiaryInverse">@color/text_color_tertiary_device_default_dark</item> <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item> <item name="colorForeground">@color/foreground_device_default_light</item> <item name="colorForegroundInverse">@color/foreground_device_default_dark</item> @@ -1393,6 +1459,9 @@ easier. <item name="textColorPrimary">@color/text_color_primary_device_default_light</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_light</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item> + <item name="textColorPrimaryInverse">@color/text_color_primary_device_default_dark</item> + <item name="textColorSecondaryInverse">@color/text_color_secondary_device_default_dark</item> + <item name="textColorTertiaryInverse">@color/text_color_tertiary_device_default_dark</item> <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item> <item name="colorForeground">@color/foreground_device_default_light</item> <item name="colorForegroundInverse">@color/foreground_device_default_dark</item> @@ -1439,6 +1508,9 @@ easier. <item name="textColorPrimary">@color/text_color_primary_device_default_light</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_light</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item> + <item name="textColorPrimaryInverse">@color/text_color_primary_device_default_dark</item> + <item name="textColorSecondaryInverse">@color/text_color_secondary_device_default_dark</item> + <item name="textColorTertiaryInverse">@color/text_color_tertiary_device_default_dark</item> <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item> <item name="colorForeground">@color/foreground_device_default_light</item> <item name="colorForegroundInverse">@color/foreground_device_default_dark</item> @@ -1487,6 +1559,9 @@ easier. <item name="textColorPrimary">@color/text_color_primary_device_default_light</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_light</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item> + <item name="textColorPrimaryInverse">@color/text_color_primary_device_default_dark</item> + <item name="textColorSecondaryInverse">@color/text_color_secondary_device_default_dark</item> + <item name="textColorTertiaryInverse">@color/text_color_tertiary_device_default_dark</item> <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item> <item name="colorForeground">@color/foreground_device_default_light</item> <item name="colorForegroundInverse">@color/foreground_device_default_dark</item> @@ -1534,6 +1609,9 @@ easier. <item name="textColorPrimary">@color/text_color_primary_device_default_light</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_light</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item> + <item name="textColorPrimaryInverse">@color/text_color_primary_device_default_dark</item> + <item name="textColorSecondaryInverse">@color/text_color_secondary_device_default_dark</item> + <item name="textColorTertiaryInverse">@color/text_color_tertiary_device_default_dark</item> <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item> <item name="colorForeground">@color/foreground_device_default_light</item> <item name="colorForegroundInverse">@color/foreground_device_default_dark</item> @@ -1598,6 +1676,9 @@ easier. <item name="textColorPrimary">@color/text_color_primary_device_default_light</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_light</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item> + <item name="textColorPrimaryInverse">@color/text_color_primary_device_default_dark</item> + <item name="textColorSecondaryInverse">@color/text_color_secondary_device_default_dark</item> + <item name="textColorTertiaryInverse">@color/text_color_tertiary_device_default_dark</item> <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item> <item name="colorForeground">@color/foreground_device_default_light</item> <item name="colorForegroundInverse">@color/foreground_device_default_dark</item> @@ -1636,6 +1717,9 @@ easier. <item name="textColorPrimary">@color/text_color_primary_device_default_light</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_light</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item> + <item name="textColorPrimaryInverse">@color/text_color_primary_device_default_dark</item> + <item name="textColorSecondaryInverse">@color/text_color_secondary_device_default_dark</item> + <item name="textColorTertiaryInverse">@color/text_color_tertiary_device_default_dark</item> <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item> <item name="colorForeground">@color/foreground_device_default_light</item> <item name="colorForegroundInverse">@color/foreground_device_default_dark</item> @@ -1684,6 +1768,9 @@ easier. <item name="textColorPrimary">@color/text_color_primary_device_default_light</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_light</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item> + <item name="textColorPrimaryInverse">@color/text_color_primary_device_default_dark</item> + <item name="textColorSecondaryInverse">@color/text_color_secondary_device_default_dark</item> + <item name="textColorTertiaryInverse">@color/text_color_tertiary_device_default_dark</item> <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item> <item name="colorForeground">@color/foreground_device_default_light</item> <item name="colorForegroundInverse">@color/foreground_device_default_dark</item> @@ -1733,6 +1820,9 @@ easier. <item name="textColorPrimary">@color/text_color_primary_device_default_light</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_light</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item> + <item name="textColorPrimaryInverse">@color/text_color_primary_device_default_dark</item> + <item name="textColorSecondaryInverse">@color/text_color_secondary_device_default_dark</item> + <item name="textColorTertiaryInverse">@color/text_color_tertiary_device_default_dark</item> <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item> <item name="colorForeground">@color/foreground_device_default_light</item> <item name="colorForegroundInverse">@color/foreground_device_default_dark</item> @@ -1781,6 +1871,9 @@ easier. <item name="textColorPrimary">@color/text_color_primary_device_default_light</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_light</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item> + <item name="textColorPrimaryInverse">@color/text_color_primary_device_default_dark</item> + <item name="textColorSecondaryInverse">@color/text_color_secondary_device_default_dark</item> + <item name="textColorTertiaryInverse">@color/text_color_tertiary_device_default_dark</item> <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item> <item name="colorForeground">@color/foreground_device_default_light</item> <item name="colorForegroundInverse">@color/foreground_device_default_dark</item> @@ -1811,6 +1904,9 @@ easier. <item name="textColorPrimary">@color/text_color_primary_device_default_light</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_light</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item> + <item name="textColorPrimaryInverse">@color/text_color_primary_device_default_dark</item> + <item name="textColorSecondaryInverse">@color/text_color_secondary_device_default_dark</item> + <item name="textColorTertiaryInverse">@color/text_color_tertiary_device_default_dark</item> <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item> <item name="colorForeground">@color/foreground_device_default_light</item> <item name="colorForegroundInverse">@color/foreground_device_default_dark</item> @@ -1842,6 +1938,9 @@ easier. <item name="textColorPrimary">@color/text_color_primary_device_default_light</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_light</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item> + <item name="textColorPrimaryInverse">@color/text_color_primary_device_default_dark</item> + <item name="textColorSecondaryInverse">@color/text_color_secondary_device_default_dark</item> + <item name="textColorTertiaryInverse">@color/text_color_tertiary_device_default_dark</item> <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item> <item name="colorForeground">@color/foreground_device_default_light</item> <item name="colorForegroundInverse">@color/foreground_device_default_dark</item> @@ -1892,6 +1991,9 @@ easier. <item name="textColorPrimary">@color/text_color_primary_device_default_light</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_light</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item> + <item name="textColorPrimaryInverse">@color/text_color_primary_device_default_dark</item> + <item name="textColorSecondaryInverse">@color/text_color_secondary_device_default_dark</item> + <item name="textColorTertiaryInverse">@color/text_color_tertiary_device_default_dark</item> <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item> <item name="colorForeground">@color/foreground_device_default_light</item> <item name="colorForegroundInverse">@color/foreground_device_default_dark</item> @@ -1940,6 +2042,9 @@ easier. <item name="textColorPrimary">@color/text_color_primary_device_default_light</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_light</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item> + <item name="textColorPrimaryInverse">@color/text_color_primary_device_default_dark</item> + <item name="textColorSecondaryInverse">@color/text_color_secondary_device_default_dark</item> + <item name="textColorTertiaryInverse">@color/text_color_tertiary_device_default_dark</item> <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item> <item name="colorForeground">@color/foreground_device_default_light</item> <item name="colorForegroundInverse">@color/foreground_device_default_dark</item> @@ -1987,6 +2092,9 @@ easier. <item name="textColorPrimary">@color/text_color_primary_device_default_light</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_light</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item> + <item name="textColorPrimaryInverse">@color/text_color_primary_device_default_dark</item> + <item name="textColorSecondaryInverse">@color/text_color_secondary_device_default_dark</item> + <item name="textColorTertiaryInverse">@color/text_color_tertiary_device_default_dark</item> <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item> <item name="colorForeground">@color/foreground_device_default_light</item> <item name="colorForegroundInverse">@color/foreground_device_default_dark</item> @@ -2033,6 +2141,9 @@ easier. <item name="textColorPrimary">@color/text_color_primary_device_default_light</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_light</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item> + <item name="textColorPrimaryInverse">@color/text_color_primary_device_default_dark</item> + <item name="textColorSecondaryInverse">@color/text_color_secondary_device_default_dark</item> + <item name="textColorTertiaryInverse">@color/text_color_tertiary_device_default_dark</item> <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item> <item name="colorForeground">@color/foreground_device_default_light</item> <item name="colorForegroundInverse">@color/foreground_device_default_dark</item> @@ -2079,6 +2190,9 @@ easier. <item name="textColorPrimary">@color/text_color_primary_device_default_light</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_light</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item> + <item name="textColorPrimaryInverse">@color/text_color_primary_device_default_dark</item> + <item name="textColorSecondaryInverse">@color/text_color_secondary_device_default_dark</item> + <item name="textColorTertiaryInverse">@color/text_color_tertiary_device_default_dark</item> <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item> <item name="colorForeground">@color/foreground_device_default_light</item> <item name="colorForegroundInverse">@color/foreground_device_default_dark</item> @@ -2123,6 +2237,9 @@ easier. <item name="textColorPrimary">@color/text_color_primary_device_default_light</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_light</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item> + <item name="textColorPrimaryInverse">@color/text_color_primary_device_default_dark</item> + <item name="textColorSecondaryInverse">@color/text_color_secondary_device_default_dark</item> + <item name="textColorTertiaryInverse">@color/text_color_tertiary_device_default_dark</item> <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item> <item name="colorForeground">@color/foreground_device_default_light</item> <item name="colorForegroundInverse">@color/foreground_device_default_dark</item> @@ -2285,6 +2402,9 @@ easier. <item name="textColorPrimary">@color/text_color_primary_device_default_dark</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item> + <item name="textColorPrimaryInverse">@color/text_color_primary_device_default_light</item> + <item name="textColorSecondaryInverse">@color/text_color_secondary_device_default_light</item> + <item name="textColorTertiaryInverse">@color/text_color_tertiary_device_default_light</item> <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item> <item name="colorForeground">@color/foreground_device_default_dark</item> <item name="colorForegroundInverse">@color/foreground_device_default_light</item> @@ -2330,6 +2450,9 @@ easier. <item name="textColorPrimary">@color/text_color_primary_device_default_light</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_light</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item> + <item name="textColorPrimaryInverse">@color/text_color_primary_device_default_dark</item> + <item name="textColorSecondaryInverse">@color/text_color_secondary_device_default_dark</item> + <item name="textColorTertiaryInverse">@color/text_color_tertiary_device_default_dark</item> <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item> <item name="colorForeground">@color/foreground_device_default_light</item> <item name="colorForegroundInverse">@color/foreground_device_default_dark</item> @@ -2385,6 +2508,9 @@ easier. <item name="textColorPrimary">@color/text_color_primary_device_default_light</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_light</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item> + <item name="textColorPrimaryInverse">@color/text_color_primary_device_default_dark</item> + <item name="textColorSecondaryInverse">@color/text_color_secondary_device_default_dark</item> + <item name="textColorTertiaryInverse">@color/text_color_tertiary_device_default_dark</item> <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item> <item name="colorForeground">@color/foreground_device_default_light</item> <item name="colorForegroundInverse">@color/foreground_device_default_dark</item> @@ -2433,6 +2559,9 @@ easier. <item name="textColorPrimary">@color/text_color_primary_device_default_light</item> <item name="textColorSecondary">@color/text_color_secondary_device_default_light</item> <item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item> + <item name="textColorPrimaryInverse">@color/text_color_primary_device_default_dark</item> + <item name="textColorSecondaryInverse">@color/text_color_secondary_device_default_dark</item> + <item name="textColorTertiaryInverse">@color/text_color_tertiary_device_default_dark</item> <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item> <item name="colorForeground">@color/foreground_device_default_light</item> <item name="colorForegroundInverse">@color/foreground_device_default_dark</item> diff --git a/core/tests/coretests/src/android/os/VibrationEffectTest.java b/core/tests/coretests/src/android/os/VibrationEffectTest.java index 009665fa1f53..6cbfffc96116 100644 --- a/core/tests/coretests/src/android/os/VibrationEffectTest.java +++ b/core/tests/coretests/src/android/os/VibrationEffectTest.java @@ -102,7 +102,9 @@ public class VibrationEffectTest { assertThrows(IllegalArgumentException.class, () -> VibrationEffect.createOneShot(1, -2).validate()); assertThrows(IllegalArgumentException.class, - () -> VibrationEffect.createOneShot(1, 256).validate()); + () -> VibrationEffect.createOneShot(1, 0).validate()); + assertThrows(IllegalArgumentException.class, + () -> VibrationEffect.createOneShot(-1, 255).validate()); } @Test @@ -117,6 +119,7 @@ public class VibrationEffectTest { @Test public void testValidateWaveform() { VibrationEffect.createWaveform(TEST_TIMINGS, TEST_AMPLITUDES, -1).validate(); + VibrationEffect.createWaveform(new long[]{10, 10}, new int[] {0, 0}, -1).validate(); VibrationEffect.createWaveform(TEST_TIMINGS, TEST_AMPLITUDES, 0).validate(); VibrationEffect.startWaveform() .addStep(/* amplitude= */ 1, /* duration= */ 10) diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java index 19c27639a00d..6e34a3322e35 100644 --- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java +++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java @@ -1857,6 +1857,57 @@ public class ChooserActivityTest { } @Test + public void testEmptyDirectRowLogging() throws InterruptedException { + Intent sendIntent = createSendTextIntent(); + // We need app targets for direct targets to get displayed + List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); + when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(), + Mockito.anyBoolean(), + Mockito.isA(List.class))).thenReturn(resolvedComponentInfos); + + // Start activity + final ChooserWrapperActivity activity = mActivityRule + .launchActivity(Intent.createChooser(sendIntent, null)); + + // Thread.sleep shouldn't be a thing in an integration test but it's + // necessary here because of the way the code is structured + Thread.sleep(3000); + + assertThat("Chooser should have 2 app targets", + activity.getAdapter().getCount(), is(2)); + assertThat("Chooser should have no direct targets", + activity.getAdapter().getSelectableServiceTargetCount(), is(0)); + + ChooserActivityLoggerFake logger = + (ChooserActivityLoggerFake) activity.getChooserActivityLogger(); + assertThat(logger.numCalls(), is(6)); + // first one should be SHARESHEET_TRIGGERED uievent + assertThat(logger.get(0).atomId, is(FrameworkStatsLog.UI_EVENT_REPORTED)); + assertThat(logger.get(0).event.getId(), + is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_TRIGGERED.getId())); + // second one should be SHARESHEET_STARTED event + assertThat(logger.get(1).atomId, is(FrameworkStatsLog.SHARESHEET_STARTED)); + assertThat(logger.get(1).intent, is(Intent.ACTION_SEND)); + assertThat(logger.get(1).mimeType, is("text/plain")); + assertThat(logger.get(1).packageName, is("com.android.frameworks.coretests")); + assertThat(logger.get(1).appProvidedApp, is(0)); + assertThat(logger.get(1).appProvidedDirect, is(0)); + assertThat(logger.get(1).isWorkprofile, is(false)); + assertThat(logger.get(1).previewType, is(3)); + // third one should be SHARESHEET_APP_LOAD_COMPLETE uievent + assertThat(logger.get(2).atomId, is(FrameworkStatsLog.UI_EVENT_REPORTED)); + assertThat(logger.get(2).event.getId(), + is(ChooserActivityLogger + .SharesheetStandardEvent.SHARESHEET_APP_LOAD_COMPLETE.getId())); + // fourth and fifth are just artifacts of test set-up + // sixth one should be ranking atom with SHARESHEET_EMPTY_DIRECT_SHARE_ROW event + assertThat(logger.get(5).atomId, is(FrameworkStatsLog.UI_EVENT_REPORTED)); + assertThat(logger.get(5).event.getId(), + is(ChooserActivityLogger + .SharesheetStandardEvent.SHARESHEET_EMPTY_DIRECT_SHARE_ROW.getId())); + } + + @Test public void testCopyTextToClipboardLogging() throws Exception { Intent sendIntent = createSendTextIntent(); List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java index 16a2fbd6465e..9fcab0923f2d 100644 --- a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java +++ b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java @@ -68,7 +68,8 @@ public class ChooserWrapperActivity extends ChooserActivity { : sOverrides.packageManager; return new ChooserListAdapter(context, payloadIntents, initialIntents, rList, filterLastUsed, resolverListController, - this, this, packageManager); + this, this, packageManager, + getChooserActivityLogger()); } ChooserListAdapter getAdapter() { diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index 8d4739dbc255..99d71675ffa9 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -153,7 +153,6 @@ applications that come with the platform <permission name="android.permission.PACKAGE_USAGE_STATS" /> <permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" /> <permission name="android.permission.MODIFY_AUDIO_ROUTING" /> - <permission name="android.permission.GET_RUNTIME_PERMISSION_GROUP_MAPPING" /> </privapp-permissions> <privapp-permissions package="com.android.phone"> diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml index ce8ce51b1d5e..3caff35c8a9d 100644 --- a/libs/WindowManager/Shell/res/values/dimen.xml +++ b/libs/WindowManager/Shell/res/values/dimen.xml @@ -180,11 +180,6 @@ individual_bubble_size + some padding. --> <dimen name="bubble_stack_user_education_side_inset">72dp</dimen> - <!-- The width/height of the icon view on staring surface. --> - <dimen name="starting_surface_icon_size">160dp</dimen> - <!-- The default width/height of the icon on the spec of adaptive icon drawable. --> - <dimen name="default_icon_size">108dp</dimen> - <!-- The width/height of the size compat restart button. --> <dimen name="size_compat_button_size">48dp</dimen> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java index 94d13eab4299..a88be3198502 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java @@ -399,6 +399,19 @@ public class ShellTaskOrganizer extends TaskOrganizer { } } + /** Helper to set int metadata on the Surface corresponding to the task id. */ + public void setSurfaceMetadata(int taskId, int key, int value) { + synchronized (mLock) { + final TaskAppearedInfo info = mTasks.get(taskId); + if (info == null || info.getLeash() == null) { + return; + } + SurfaceControl.Transaction t = new SurfaceControl.Transaction(); + t.setMetadata(info.getLeash(), key, value); + t.apply(); + } + } + private boolean updateTaskListenerIfNeeded(RunningTaskInfo taskInfo, SurfaceControl leash, TaskListener oldListener, TaskListener newListener) { if (oldListener == newListener) return false; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java index 84a9ce52ffdc..1d37a128da0c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java @@ -124,9 +124,9 @@ public class SplashscreenContentDrawer { private void updateDensity() { mIconSize = mContext.getResources().getDimensionPixelSize( - com.android.wm.shell.R.dimen.starting_surface_icon_size); + com.android.internal.R.dimen.starting_surface_icon_size); mDefaultIconSize = mContext.getResources().getDimensionPixelSize( - com.android.wm.shell.R.dimen.default_icon_size); + com.android.internal.R.dimen.starting_surface_default_icon_size); mBrandingImageWidth = mContext.getResources().getDimensionPixelSize( com.android.wm.shell.R.dimen.starting_surface_brand_image_width); mBrandingImageHeight = mContext.getResources().getDimensionPixelSize( diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java index bdc8ff1f9882..ff91d827b280 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java @@ -29,6 +29,7 @@ import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; +import android.graphics.PixelFormat; import android.graphics.Rect; import android.hardware.display.DisplayManager; import android.os.IBinder; @@ -215,6 +216,7 @@ public class StartingSurfaceDrawer { WindowManager.LayoutParams.TYPE_APPLICATION_STARTING); params.setFitInsetsSides(0); params.setFitInsetsTypes(0); + params.format = PixelFormat.TRANSLUCENT; int windowFlags = WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN diff --git a/core/jni/permission_utils.h b/libs/WindowManager/Shell/src/com/android/wm/shell/tasksurfacehelper/TaskSurfaceHelper.java index d625bb6ba30a..fbbd09faee9b 100644 --- a/core/jni/permission_utils.h +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/tasksurfacehelper/TaskSurfaceHelper.java @@ -14,14 +14,13 @@ * limitations under the License. */ -#pragma once +package com.android.wm.shell.tasksurfacehelper; -#include <android/media/permission/Identity.h> -#include <jni.h> - -namespace android::media::permission { +/** + * Interface to communicate with a Task's SurfaceControl. + */ +public interface TaskSurfaceHelper { -Identity convertIdentity(JNIEnv* env, const jobject& jIdentity); + /** Sets the METADATA_GAME_MODE for the layer corresponding to the task **/ + default void setGameModeForTask(int taskId, int gameMode) {} } - -int register_android_media_permission_Identity(JNIEnv* env); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/tasksurfacehelper/TaskSurfaceHelperController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/tasksurfacehelper/TaskSurfaceHelperController.java new file mode 100644 index 000000000000..b459b9fcd0b2 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/tasksurfacehelper/TaskSurfaceHelperController.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.tasksurfacehelper; + +import android.view.SurfaceControl; + +import com.android.wm.shell.ShellTaskOrganizer; +import com.android.wm.shell.common.ShellExecutor; + +/** + * Intermediary controller that communicates with {@link ShellTaskOrganizer} to send commands + * to SurfaceControl. + */ +public class TaskSurfaceHelperController { + + private final ShellTaskOrganizer mTaskOrganizer; + private final ShellExecutor mMainExecutor; + private final TaskSurfaceHelperImpl mImpl = new TaskSurfaceHelperImpl(); + + public TaskSurfaceHelperController(ShellTaskOrganizer taskOrganizer, + ShellExecutor mainExecutor) { + mTaskOrganizer = taskOrganizer; + mMainExecutor = mainExecutor; + } + + public TaskSurfaceHelper asTaskSurfaceHelper() { + return mImpl; + } + + /** + * Sends a Transaction to set the game mode metadata on the + * corresponding SurfaceControl + */ + public void setGameModeForTask(int taskId, int gameMode) { + mTaskOrganizer.setSurfaceMetadata(taskId, SurfaceControl.METADATA_GAME_MODE, gameMode); + } + + private class TaskSurfaceHelperImpl implements TaskSurfaceHelper { + @Override + public void setGameModeForTask(int taskId, int gameMode) { + mMainExecutor.execute(() -> { + TaskSurfaceHelperController.this.setGameModeForTask(taskId, gameMode); + }); + } + } +} diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/tasksurfacehelper/TaskSurfaceHelperControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/tasksurfacehelper/TaskSurfaceHelperControllerTest.java new file mode 100644 index 000000000000..d6142753b48a --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/tasksurfacehelper/TaskSurfaceHelperControllerTest.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.tasksurfacehelper; + +import static org.mockito.Mockito.verify; + +import android.platform.test.annotations.Presubmit; +import android.testing.AndroidTestingRunner; +import android.view.SurfaceControl; + +import androidx.test.filters.SmallTest; + +import com.android.wm.shell.ShellTaskOrganizer; +import com.android.wm.shell.common.ShellExecutor; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@Presubmit +@RunWith(AndroidTestingRunner.class) +@SmallTest +public class TaskSurfaceHelperControllerTest { + private TaskSurfaceHelperController mTaskSurfaceHelperController; + @Mock + private ShellTaskOrganizer mMockTaskOrganizer; + @Mock + private ShellExecutor mMockShellExecutor; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + mTaskSurfaceHelperController = new TaskSurfaceHelperController( + mMockTaskOrganizer, mMockShellExecutor); + } + + @Test + public void testSetGameModeForTask() { + mTaskSurfaceHelperController.setGameModeForTask(/*taskId*/1, /*gameMode*/3); + verify(mMockTaskOrganizer).setSurfaceMetadata(1, SurfaceControl.METADATA_GAME_MODE, 3); + } +} diff --git a/libs/androidfw/TEST_MAPPING b/libs/androidfw/TEST_MAPPING index 8a5c06d1eef9..9ebc9969a730 100644 --- a/libs/androidfw/TEST_MAPPING +++ b/libs/androidfw/TEST_MAPPING @@ -2,9 +2,6 @@ "presubmit": [ { "name": "CtsResourcesLoaderTests" - }, - { - "name": "ResourcesHardeningTest" } ] -}
\ No newline at end of file +} diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java index 0d44a8580ef9..7c6ae28bdd30 100644 --- a/media/java/android/media/AudioRecord.java +++ b/media/java/android/media/AudioRecord.java @@ -16,8 +16,6 @@ package android.media; -import static android.media.permission.PermissionUtil.myIdentity; - import android.annotation.CallbackExecutor; import android.annotation.FloatRange; import android.annotation.IntDef; @@ -29,12 +27,13 @@ import android.annotation.SystemApi; import android.annotation.TestApi; import android.app.ActivityThread; import android.compat.annotation.UnsupportedAppUsage; +import android.content.AttributionSource; +import android.content.AttributionSource.ScopedParcelState; import android.content.Context; import android.media.MediaRecorder.Source; import android.media.audiopolicy.AudioMix; import android.media.audiopolicy.AudioPolicy; import android.media.metrics.LogSessionId; -import android.media.permission.Identity; import android.media.projection.MediaProjection; import android.os.Binder; import android.os.Build; @@ -42,6 +41,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Message; +import android.os.Parcel; import android.os.PersistableBundle; import android.os.RemoteException; import android.os.ServiceManager; @@ -381,7 +381,8 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection, * {@link AudioManager#AUDIO_SESSION_ID_GENERATE} if the session isn't known at construction * time. See also {@link AudioManager#generateAudioSessionId()} to obtain a session ID before * construction. - * @param context An optional context to pull an attribution tag from. + * @param context An optional context on whose behalf the recoding is performed. + * * @throws IllegalArgumentException */ private AudioRecord(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes, @@ -449,10 +450,11 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection, audioBuffSizeCheck(bufferSizeInBytes); - Identity identity = myIdentity(context); - if (identity.packageName == null) { + AttributionSource attributionSource = (context != null) + ? context.getAttributionSource() : AttributionSource.myAttributionSource(); + if (attributionSource.getPackageName() == null) { // Command line utility - identity.packageName = "uid:" + Binder.getCallingUid(); + attributionSource = attributionSource.withPackageName("uid:" + Binder.getCallingUid()); } int[] sampleRate = new int[] {mSampleRate}; @@ -461,14 +463,15 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection, //TODO: update native initialization when information about hardware init failure // due to capture device already open is available. - int initResult = native_setup(new WeakReference<AudioRecord>(this), - mAudioAttributes, sampleRate, mChannelMask, mChannelIndexMask, - mAudioFormat, mNativeBufferSizeInBytes, - session, identity, 0 /*nativeRecordInJavaObj*/, - maxSharedAudioHistoryMs); - if (initResult != SUCCESS) { - loge("Error code "+initResult+" when initializing native AudioRecord object."); - return; // with mState == STATE_UNINITIALIZED + try (ScopedParcelState attributionSourceState = attributionSource.asScopedParcelState()) { + int initResult = native_setup(new WeakReference<AudioRecord>(this), mAudioAttributes, + sampleRate, mChannelMask, mChannelIndexMask, mAudioFormat, + mNativeBufferSizeInBytes, session, attributionSourceState.getParcel(), + 0 /*nativeRecordInJavaObj*/, maxSharedAudioHistoryMs); + if (initResult != SUCCESS) { + loge("Error code " + initResult + " when initializing native AudioRecord object."); + return; // with mState == STATE_UNINITIALIZED + } } mSampleRate = sampleRate[0]; @@ -512,23 +515,27 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection, */ /* package */ void deferred_connect(long nativeRecordInJavaObj) { if (mState != STATE_INITIALIZED) { - int[] session = { 0 }; - int[] rates = { 0 }; + int[] session = {0}; + int[] rates = {0}; //TODO: update native initialization when information about hardware init failure // due to capture device already open is available. // Note that for this native_setup, we are providing an already created/initialized // *Native* AudioRecord, so the attributes parameters to native_setup() are ignored. - int initResult = native_setup(new WeakReference<AudioRecord>(this), - null /*mAudioAttributes*/, - rates /*mSampleRates*/, - 0 /*mChannelMask*/, - 0 /*mChannelIndexMask*/, - 0 /*mAudioFormat*/, - 0 /*mNativeBufferSizeInBytes*/, - session, - myIdentity(null), - nativeRecordInJavaObj, - 0); + final int initResult; + try (ScopedParcelState attributionSourceState = AttributionSource.myAttributionSource() + .asScopedParcelState()) { + initResult = native_setup(new WeakReference<>(this), + null /*mAudioAttributes*/, + rates /*mSampleRates*/, + 0 /*mChannelMask*/, + 0 /*mChannelIndexMask*/, + 0 /*mAudioFormat*/, + 0 /*mNativeBufferSizeInBytes*/, + session, + attributionSourceState.getParcel(), + nativeRecordInJavaObj, + 0); + } if (initResult != SUCCESS) { loge("Error code "+initResult+" when initializing native AudioRecord object."); return; // with mState == STATE_UNINITIALIZED @@ -620,8 +627,8 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection, /** * Sets the context the record belongs to. This context will be used to pull information, - * such as attribution tags, which will be associated with the AudioRecord. However, the - * context itself will not be retained by the AudioRecord. + * such as {@link android.content.AttributionSource}, which will be associated with + * the AudioRecord. However, the context itself will not be retained by the AudioRecord. * @param context a non-null {@link Context} instance * @return the same Builder instance. */ @@ -2216,7 +2223,7 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection, //-------------------- /** - * @deprecated Use native_setup that takes an Identity object + * @deprecated Use native_setup that takes an {@link AttributionSource} object * @return */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, @@ -2227,18 +2234,20 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection, int[] sampleRate, int channelMask, int channelIndexMask, int audioFormat, int buffSizeInBytes, int[] sessionId, String opPackageName, long nativeRecordInJavaObj) { - Identity identity = myIdentity(null); - identity.packageName = opPackageName; - - return native_setup(audiorecordThis, attributes, sampleRate, channelMask, channelIndexMask, - audioFormat, buffSizeInBytes, sessionId, identity, nativeRecordInJavaObj, 0); + AttributionSource attributionSource = AttributionSource.myAttributionSource() + .withPackageName(opPackageName); + try (ScopedParcelState attributionSourceState = attributionSource.asScopedParcelState()) { + return native_setup(audiorecordThis, attributes, sampleRate, channelMask, + channelIndexMask, audioFormat, buffSizeInBytes, sessionId, + attributionSourceState.getParcel(), nativeRecordInJavaObj, 0); + } } private native int native_setup(Object audiorecordThis, Object /*AudioAttributes*/ attributes, int[] sampleRate, int channelMask, int channelIndexMask, int audioFormat, - int buffSizeInBytes, int[] sessionId, Identity identity, long nativeRecordInJavaObj, - int maxSharedAudioHistoryMs); + int buffSizeInBytes, int[] sessionId, @NonNull Parcel attributionSource, + long nativeRecordInJavaObj, int maxSharedAudioHistoryMs); // TODO remove: implementation calls directly into implementation of native_release() private native void native_finalize(); diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index 2d8babdc9f94..4f761ba0bf6a 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -18,7 +18,6 @@ package android.media; import static android.Manifest.permission.BIND_IMS_SERVICE; import static android.content.pm.PackageManager.PERMISSION_GRANTED; -import static android.media.permission.PermissionUtil.myIdentity; import android.annotation.CallbackExecutor; import android.annotation.IntDef; @@ -28,6 +27,8 @@ import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.app.ActivityThread; import android.compat.annotation.UnsupportedAppUsage; +import android.content.AttributionSource; +import android.content.AttributionSource.ScopedParcelState; import android.content.ContentProvider; import android.content.ContentResolver; import android.content.Context; @@ -35,7 +36,6 @@ import android.content.res.AssetFileDescriptor; import android.graphics.SurfaceTexture; import android.media.SubtitleController.Anchor; import android.media.SubtitleTrack.RenderingWidget; -import android.media.permission.Identity; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -56,7 +56,6 @@ import android.provider.Settings; import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; -import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; import android.util.Pair; @@ -685,14 +684,18 @@ public class MediaPlayer extends PlayerBase mTimeProvider = new TimeProvider(this); mOpenSubtitleSources = new Vector<InputStream>(); - Identity identity = myIdentity(null); + AttributionSource attributionSource = AttributionSource.myAttributionSource(); // set the package name to empty if it was null - identity.packageName = TextUtils.emptyIfNull(identity.packageName); + if (attributionSource.getPackageName() == null) { + attributionSource = attributionSource.withPackageName(""); + } /* Native setup requires a weak reference to our object. * It's easier to create it here than in C++. */ - native_setup(new WeakReference<MediaPlayer>(this), identity); + try (ScopedParcelState attributionSourceState = attributionSource.asScopedParcelState()) { + native_setup(new WeakReference<MediaPlayer>(this), attributionSourceState.getParcel()); + } baseRegisterPlayer(sessionId); } @@ -2475,7 +2478,8 @@ public class MediaPlayer extends PlayerBase private native final int native_setMetadataFilter(Parcel request); private static native final void native_init(); - private native void native_setup(Object mediaplayerThis, @NonNull Identity identity); + private native void native_setup(Object mediaplayerThis, + @NonNull Parcel attributionSource); private native final void native_finalize(); /** diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java index 499034ea7c41..1efd4c6846e6 100644 --- a/media/java/android/media/MediaRecorder.java +++ b/media/java/android/media/MediaRecorder.java @@ -16,8 +16,6 @@ package android.media; -import static android.media.permission.PermissionUtil.myIdentity; - import android.annotation.CallbackExecutor; import android.annotation.FloatRange; import android.annotation.IntDef; @@ -27,14 +25,16 @@ import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.app.ActivityThread; import android.compat.annotation.UnsupportedAppUsage; +import android.content.AttributionSource; +import android.content.AttributionSource.ScopedParcelState; import android.content.Context; import android.hardware.Camera; import android.media.metrics.LogSessionId; -import android.media.permission.Identity; import android.os.Build; import android.os.Handler; import android.os.Looper; import android.os.Message; +import android.os.Parcel; import android.os.PersistableBundle; import android.util.ArrayMap; import android.util.Log; @@ -163,8 +163,11 @@ public class MediaRecorder implements AudioRouting, /* Native setup requires a weak reference to our object. * It's easier to create it here than in C++. */ - native_setup(new WeakReference<MediaRecorder>(this), - ActivityThread.currentPackageName(), myIdentity(context)); + try (ScopedParcelState attributionSourceState = context.getAttributionSource() + .asScopedParcelState()) { + native_setup(new WeakReference<>(this), ActivityThread.currentPackageName(), + attributionSourceState.getParcel()); + } } /** @@ -1894,14 +1897,15 @@ public class MediaRecorder implements AudioRouting, publicAlternatives = "{@link MediaRecorder}") private void native_setup(Object mediarecorderThis, String clientName, String opPackageName) throws IllegalStateException { - Identity identity = myIdentity(null); - identity.packageName = opPackageName; - - native_setup(mediarecorderThis, clientName, identity); + AttributionSource attributionSource = AttributionSource.myAttributionSource() + .withPackageName(opPackageName); + try (ScopedParcelState attributionSourceState = attributionSource.asScopedParcelState()) { + native_setup(mediarecorderThis, clientName, attributionSourceState.getParcel()); + } } private native void native_setup(Object mediarecorderThis, - String clientName, Identity identity) + String clientName, @NonNull Parcel attributionSource) throws IllegalStateException; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) diff --git a/media/java/android/media/audiofx/AudioEffect.java b/media/java/android/media/audiofx/AudioEffect.java index fd3c4057ad21..70bb9608f1c2 100644 --- a/media/java/android/media/audiofx/AudioEffect.java +++ b/media/java/android/media/audiofx/AudioEffect.java @@ -16,8 +16,6 @@ package android.media.audiofx; -import static android.media.permission.PermissionUtil.myIdentity; - import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -26,10 +24,11 @@ import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; +import android.content.AttributionSource; +import android.content.AttributionSource.ScopedParcelState; import android.media.AudioDeviceAttributes; import android.media.AudioDeviceInfo; import android.media.AudioSystem; -import android.media.permission.Identity; import android.os.Build; import android.os.Handler; import android.os.Looper; @@ -518,10 +517,13 @@ public class AudioEffect { // native initialization // TODO b/182469354: Make consistent with AudioRecord - int initResult = native_setup(new WeakReference<AudioEffect>(this), - type.toString(), uuid.toString(), priority, audioSession, - deviceType, deviceAddress, - id, desc, myIdentity(null), probe); + int initResult; + try (ScopedParcelState attributionSourceState = AttributionSource.myAttributionSource() + .asScopedParcelState()) { + initResult = native_setup(new WeakReference<>(this), type.toString(), uuid.toString(), + priority, audioSession, deviceType, deviceAddress, id, desc, + attributionSourceState.getParcel(), probe); + } if (initResult != SUCCESS && initResult != ALREADY_EXISTS) { Log.e(TAG, "Error code " + initResult + " when initializing AudioEffect."); @@ -1388,7 +1390,7 @@ public class AudioEffect { private native final int native_setup(Object audioeffect_this, String type, String uuid, int priority, int audioSession, int deviceType, String deviceAddress, int[] id, Object[] desc, - Identity identity, boolean probe); + @NonNull Parcel attributionSource, boolean probe); private native final void native_finalize(); diff --git a/media/java/android/media/audiofx/Visualizer.java b/media/java/android/media/audiofx/Visualizer.java index 58c9e650bb90..3349277ede3b 100644 --- a/media/java/android/media/audiofx/Visualizer.java +++ b/media/java/android/media/audiofx/Visualizer.java @@ -16,12 +16,13 @@ package android.media.audiofx; -import static android.media.permission.PermissionUtil.myIdentity; - +import android.annotation.NonNull; import android.compat.annotation.UnsupportedAppUsage; -import android.media.permission.Identity; +import android.content.AttributionSource; +import android.content.AttributionSource.ScopedParcelState; import android.os.Handler; import android.os.Looper; +import android.os.Parcel; import android.util.Log; import com.android.internal.annotations.GuardedBy; @@ -222,8 +223,12 @@ public class Visualizer { // native initialization // TODO b/182469354: make consistent with AudioRecord - int result = native_setup(new WeakReference<Visualizer>(this), audioSession, id, - myIdentity(null)); + int result; + try (ScopedParcelState attributionSourceState = AttributionSource.myAttributionSource() + .asScopedParcelState()) { + result = native_setup(new WeakReference<>(this), audioSession, id, + attributionSourceState.getParcel()); + } if (result != SUCCESS && result != ALREADY_EXISTS) { Log.e(TAG, "Error code "+result+" when initializing Visualizer."); switch (result) { @@ -690,7 +695,7 @@ public class Visualizer { private native final int native_setup(Object audioeffect_this, int audioSession, int[] id, - Identity identity); + @NonNull Parcel attributionSource); @GuardedBy("mStateLock") private native final void native_finalize(); diff --git a/media/java/android/media/permission/PermissionUtil.java b/media/java/android/media/permission/PermissionUtil.java index 92fe8820570c..b08d111db89c 100644 --- a/media/java/android/media/permission/PermissionUtil.java +++ b/media/java/android/media/permission/PermissionUtil.java @@ -51,24 +51,6 @@ import java.util.Objects; * @hide */ public class PermissionUtil { - /** - * Create an identity for the current process and the passed context. - * - * @param context The process the identity is for. If {@code null}, the process's default - * identity is chosen. - * @return The identity for the current process and context - */ - public static @NonNull Identity myIdentity(@Nullable Context context) { - Identity identity = new Identity(); - - identity.pid = Process.myPid(); - identity.uid = Process.myUid(); - identity.packageName = context != null ? context.getOpPackageName() - : ActivityThread.currentOpPackageName(); - identity.attributionTag = context != null ? context.getAttributionTag() : null; - - return identity; - } /** * Authenticate an originator, where the binder call is coming from a middleman. diff --git a/media/jni/Android.bp b/media/jni/Android.bp index d49790e3ecd3..bc73f6ad1ad2 100644 --- a/media/jni/Android.bp +++ b/media/jni/Android.bp @@ -51,6 +51,7 @@ cc_library_shared { shared_libs: [ "audioclient-types-aidl-cpp", "av-types-aidl-cpp", + "framework-permission-aidl-cpp", "libandroid_runtime", "libaudioclient", "libnativehelper", @@ -85,7 +86,6 @@ cc_library_shared { "android.hardware.drm@1.4", "android.hidl.memory@1.0", "android.hidl.token@1.0-utils", - "media_permission-aidl-cpp", ], header_libs: [ diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp index a3607597f05e..2636ab227646 100644 --- a/media/jni/android_media_MediaPlayer.cpp +++ b/media/jni/android_media_MediaPlayer.cpp @@ -17,7 +17,6 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "MediaPlayer-JNI" -#include "permission_utils.h" #include "utils/Log.h" #include <media/mediaplayer.h> @@ -80,8 +79,6 @@ static StateExceptionFields gStateExceptionFields; using namespace android; using media::VolumeShaper; -using media::permission::Identity; -using media::permission::convertIdentity; // ---------------------------------------------------------------------------- @@ -949,11 +946,14 @@ android_media_MediaPlayer_native_init(JNIEnv *env) static void android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this, - jobject jIdentity) + jobject jAttributionSource) { ALOGV("native_setup"); - sp<MediaPlayer> mp = new MediaPlayer(convertIdentity(env, jIdentity)); + Parcel* parcel = parcelForJavaObject(env, jAttributionSource); + android::content::AttributionSourceState attributionSource; + attributionSource.readFromParcel(parcel); + sp<MediaPlayer> mp = new MediaPlayer(attributionSource); if (mp == NULL) { jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); return; @@ -1409,7 +1409,7 @@ static const JNINativeMethod gMethods[] = { {"native_setMetadataFilter", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_setMetadataFilter}, {"native_getMetadata", "(ZZLandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer_getMetadata}, {"native_init", "()V", (void *)android_media_MediaPlayer_native_init}, - {"native_setup", "(Ljava/lang/Object;Landroid/media/permission/Identity;)V",(void *)android_media_MediaPlayer_native_setup}, + {"native_setup", "(Ljava/lang/Object;Landroid/os/Parcel;)V",(void *)android_media_MediaPlayer_native_setup}, {"native_finalize", "()V", (void *)android_media_MediaPlayer_native_finalize}, {"getAudioSessionId", "()I", (void *)android_media_MediaPlayer_get_audio_session_id}, {"native_setAudioSessionId", "(I)V", (void *)android_media_MediaPlayer_set_audio_session_id}, diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp index 66411233216f..7ef0f7709408 100644 --- a/media/jni/android_media_MediaRecorder.cpp +++ b/media/jni/android_media_MediaRecorder.cpp @@ -24,7 +24,6 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "MediaRecorderJNI" -#include "permission_utils.h" #include <utils/Log.h> #include <gui/Surface.h> @@ -46,13 +45,13 @@ #include <system/audio.h> #include <android_runtime/android_view_Surface.h> +#include <android/content/AttributionSourceState.h> +#include <android_os_Parcel.h> // ---------------------------------------------------------------------------- using namespace android; -using android::media::permission::convertIdentity; - // ---------------------------------------------------------------------------- // helper function to extract a native Camera object from a Camera Java object @@ -620,11 +619,14 @@ android_media_MediaRecorder_native_init(JNIEnv *env) static void android_media_MediaRecorder_native_setup(JNIEnv *env, jobject thiz, jobject weak_this, - jstring packageName, jobject jIdentity) + jstring packageName, jobject jAttributionSource) { ALOGV("setup"); - sp<MediaRecorder> mr = new MediaRecorder(convertIdentity(env, jIdentity)); + Parcel* parcel = parcelForJavaObject(env, jAttributionSource); + android::content::AttributionSourceState attributionSource; + attributionSource.readFromParcel(parcel); + sp<MediaRecorder> mr = new MediaRecorder(attributionSource); if (mr == NULL) { jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); @@ -871,7 +873,7 @@ static const JNINativeMethod gMethods[] = { {"native_reset", "()V", (void *)android_media_MediaRecorder_native_reset}, {"release", "()V", (void *)android_media_MediaRecorder_release}, {"native_init", "()V", (void *)android_media_MediaRecorder_native_init}, - {"native_setup", "(Ljava/lang/Object;Ljava/lang/String;Landroid/media/permission/Identity;)V", + {"native_setup", "(Ljava/lang/Object;Ljava/lang/String;Landroid/os/Parcel;)V", (void *)android_media_MediaRecorder_native_setup}, {"native_finalize", "()V", (void *)android_media_MediaRecorder_native_finalize}, {"native_setInputSurface", "(Landroid/view/Surface;)V", (void *)android_media_MediaRecorder_setInputSurface }, diff --git a/media/jni/audioeffect/Android.bp b/media/jni/audioeffect/Android.bp index bfed983c8bce..2ddfacf3884a 100644 --- a/media/jni/audioeffect/Android.bp +++ b/media/jni/audioeffect/Android.bp @@ -19,6 +19,7 @@ cc_library_shared { ], shared_libs: [ + "framework-permission-aidl-cpp", "liblog", "libcutils", "libutils", @@ -27,11 +28,11 @@ cc_library_shared { "libaudioclient", "libaudioutils", "libaudiofoundation", - "media_permission-aidl-cpp", + "libbinder" ], export_shared_lib_headers: [ - "media_permission-aidl-cpp", + "framework-permission-aidl-cpp", ], version_script: "exports.lds", diff --git a/media/jni/audioeffect/Visualizer.cpp b/media/jni/audioeffect/Visualizer.cpp index 8a52456849f0..84a8d5122470 100644 --- a/media/jni/audioeffect/Visualizer.cpp +++ b/media/jni/audioeffect/Visualizer.cpp @@ -28,14 +28,16 @@ #include <cutils/bitops.h> #include <utils/Thread.h> +#include <android/content/AttributionSourceState.h> + #include "Visualizer.h" namespace android { // --------------------------------------------------------------------------- -Visualizer::Visualizer (const Identity& identity) - : AudioEffect(identity) +Visualizer::Visualizer (const android::content::AttributionSourceState& attributionSource) + : AudioEffect(attributionSource) { } diff --git a/media/jni/audioeffect/Visualizer.h b/media/jni/audioeffect/Visualizer.h index 3ee91f0f8b1e..aa07ce8055ae 100644 --- a/media/jni/audioeffect/Visualizer.h +++ b/media/jni/audioeffect/Visualizer.h @@ -20,9 +20,7 @@ #include <media/AudioEffect.h> #include <system/audio_effects/effect_visualizer.h> #include <utils/Thread.h> -#include "android/media/permission/Identity.h" - -using namespace android::media::permission; +#include "android/content/AttributionSourceState.h" /** * The Visualizer class enables application to retrieve part of the currently playing audio for @@ -68,9 +66,9 @@ public: /* Constructor. * See AudioEffect constructor for details on parameters. */ - explicit Visualizer(const Identity& identity); + explicit Visualizer(const android::content::AttributionSourceState& attributionSource); - ~Visualizer(); + ~Visualizer(); /** * Initialize an uninitialized Visualizer. diff --git a/media/jni/audioeffect/android_media_AudioEffect.cpp b/media/jni/audioeffect/android_media_AudioEffect.cpp index 953b7e01c983..3a8decdad18f 100644 --- a/media/jni/audioeffect/android_media_AudioEffect.cpp +++ b/media/jni/audioeffect/android_media_AudioEffect.cpp @@ -25,7 +25,9 @@ #include <nativehelper/JNIHelp.h> #include <android_runtime/AndroidRuntime.h> #include "media/AudioEffect.h" -#include "permission_utils.h" + +#include <android/content/AttributionSourceState.h> +#include <android_os_Parcel.h> #include <nativehelper/ScopedUtfChars.h> @@ -35,8 +37,6 @@ using namespace android; -using media::permission::convertIdentity; - #define AUDIOEFFECT_SUCCESS 0 #define AUDIOEFFECT_ERROR (-1) #define AUDIOEFFECT_ERROR_ALREADY_EXISTS (-2) @@ -273,7 +273,7 @@ static jint android_media_AudioEffect_native_setup(JNIEnv *env, jobject thiz, jobject weak_this, jstring type, jstring uuid, jint priority, jint sessionId, jint deviceType, jstring deviceAddress, - jintArray jId, jobjectArray javadesc, jobject jIdentity, jboolean probe) + jintArray jId, jobjectArray javadesc, jobject jAttributionSource, jboolean probe) { ALOGV("android_media_AudioEffect_native_setup"); AudioEffectJniStorage* lpJniStorage = NULL; @@ -285,6 +285,8 @@ android_media_AudioEffect_native_setup(JNIEnv *env, jobject thiz, jobject weak_t effect_descriptor_t desc; jobject jdesc; AudioDeviceTypeAddr device; + AttributionSourceState attributionSource; + Parcel* parcel = NULL; setAudioEffect(env, thiz, 0); @@ -338,7 +340,9 @@ android_media_AudioEffect_native_setup(JNIEnv *env, jobject thiz, jobject weak_t } // create the native AudioEffect object - lpAudioEffect = new AudioEffect(convertIdentity(env, jIdentity)); + parcel = parcelForJavaObject(env, jAttributionSource); + attributionSource.readFromParcel(parcel); + lpAudioEffect = new AudioEffect(attributionSource); if (lpAudioEffect == 0) { ALOGE("Error creating AudioEffect"); goto setup_failure; @@ -774,7 +778,7 @@ android_media_AudioEffect_native_queryPreProcessings(JNIEnv *env, jclass clazz _ // Dalvik VM type signatures static const JNINativeMethod gMethods[] = { {"native_init", "()V", (void *)android_media_AudioEffect_native_init}, - {"native_setup", "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;IIILjava/lang/String;[I[Ljava/lang/Object;Landroid/media/permission/Identity;Z)I", + {"native_setup", "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;IIILjava/lang/String;[I[Ljava/lang/Object;Landroid/os/Parcel;Z)I", (void *)android_media_AudioEffect_native_setup}, {"native_finalize", "()V", (void *)android_media_AudioEffect_native_finalize}, {"native_release", "()V", (void *)android_media_AudioEffect_native_release}, diff --git a/media/jni/audioeffect/android_media_Visualizer.cpp b/media/jni/audioeffect/android_media_Visualizer.cpp index 439715cbb811..b30f00fdf7de 100644 --- a/media/jni/audioeffect/android_media_Visualizer.cpp +++ b/media/jni/audioeffect/android_media_Visualizer.cpp @@ -25,12 +25,16 @@ #include <android_runtime/AndroidRuntime.h> #include <utils/threads.h> #include "Visualizer.h" -#include "permission_utils.h" #include <nativehelper/ScopedUtfChars.h> +#include <android/content/AttributionSourceState.h> +#include <android_os_Parcel.h> + using namespace android; +using content::AttributionSourceState; + #define VISUALIZER_SUCCESS 0 #define VISUALIZER_ERROR (-1) #define VISUALIZER_ERROR_ALREADY_EXISTS (-2) @@ -348,13 +352,15 @@ static void android_media_visualizer_effect_callback(int32_t event, static jint android_media_visualizer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this, - jint sessionId, jintArray jId, jobject jIdentity) + jint sessionId, jintArray jId, jobject jAttributionSource) { ALOGV("android_media_visualizer_native_setup"); VisualizerJniStorage* lpJniStorage = NULL; int lStatus = VISUALIZER_ERROR_NO_MEMORY; sp<Visualizer> lpVisualizer; jint* nId = NULL; + AttributionSourceState attributionSource; + Parcel* parcel = nullptr; setVisualizer(env, thiz, 0); @@ -381,7 +387,9 @@ android_media_visualizer_native_setup(JNIEnv *env, jobject thiz, jobject weak_th } // create the native Visualizer object - lpVisualizer = new Visualizer(convertIdentity(env, jIdentity)); + parcel = parcelForJavaObject(env, jAttributionSource); + attributionSource.readFromParcel(parcel); + lpVisualizer = sp<Visualizer>::make(attributionSource); if (lpVisualizer == 0) { ALOGE("Error creating Visualizer"); goto setup_failure; @@ -678,7 +686,7 @@ android_media_setPeriodicCapture(JNIEnv *env, jobject thiz, jint rate, jboolean // Dalvik VM type signatures static const JNINativeMethod gMethods[] = { {"native_init", "()V", (void *)android_media_visualizer_native_init}, - {"native_setup", "(Ljava/lang/Object;I[ILandroid/media/permission/Identity;)I", + {"native_setup", "(Ljava/lang/Object;I[ILandroid/os/Parcel;)I", (void *)android_media_visualizer_native_setup}, {"native_finalize", "()V", (void *)android_media_visualizer_native_finalize}, {"native_release", "()V", (void *)android_media_visualizer_native_release}, diff --git a/media/jni/soundpool/Android.bp b/media/jni/soundpool/Android.bp index 4227cd8cbb29..ee473f5deb15 100644 --- a/media/jni/soundpool/Android.bp +++ b/media/jni/soundpool/Android.bp @@ -126,6 +126,7 @@ cc_library_shared { ], shared_libs: [ + "framework-permission-aidl-cpp", "libaudioutils", "liblog", "libcutils", @@ -135,7 +136,6 @@ cc_library_shared { "libaudioclient", "libmediandk", "libbinder", - "media_permission-aidl-cpp", ], cflags: [ diff --git a/media/jni/soundpool/Stream.cpp b/media/jni/soundpool/Stream.cpp index 95fe000bd2c2..bbbef3853b23 100644 --- a/media/jni/soundpool/Stream.cpp +++ b/media/jni/soundpool/Stream.cpp @@ -17,7 +17,7 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "SoundPool::Stream" #include <utils/Log.h> -#include<android/media/permission/Identity.h> +#include <android/content/AttributionSourceState.h> #include "Stream.h" @@ -25,8 +25,6 @@ namespace android::soundpool { -using media::permission::Identity; - Stream::~Stream() { ALOGV("%s(%p)", __func__, this); @@ -330,15 +328,16 @@ void Stream::play_l(const std::shared_ptr<Sound>& sound, int32_t nextStreamID, // do not create a new audio track if current track is compatible with sound parameters - Identity identity = Identity(); - identity.packageName = mStreamManager->getOpPackageName(); + android::content::AttributionSourceState attributionSource; + attributionSource.packageName = mStreamManager->getOpPackageName(); + attributionSource.token = sp<BBinder>::make(); // TODO b/182469354 make consistent with AudioRecord, add util for native source newTrack = new AudioTrack(streamType, sampleRate, sound->getFormat(), channelMask, sound->getIMemory(), AUDIO_OUTPUT_FLAG_FAST, staticCallback, userData, 0 /*default notification frames*/, AUDIO_SESSION_ALLOCATE, AudioTrack::TRANSFER_DEFAULT, - nullptr /*offloadInfo*/, identity, + nullptr /*offloadInfo*/, attributionSource, mStreamManager->getAttributes(), false /*doNotReconnect*/, 1.0f /*maxRequiredSpeed*/); // Set caller name so it can be logged in destructor. diff --git a/packages/CtsShim/apk/arm/CtsShim.apk b/packages/CtsShim/apk/arm/CtsShim.apk Binary files differindex ca69a28a04b4..bb6dfa3a4ede 100644 --- a/packages/CtsShim/apk/arm/CtsShim.apk +++ b/packages/CtsShim/apk/arm/CtsShim.apk diff --git a/packages/CtsShim/apk/arm/CtsShimPriv.apk b/packages/CtsShim/apk/arm/CtsShimPriv.apk Binary files differindex d7cfb969c728..2835d57474d9 100644 --- a/packages/CtsShim/apk/arm/CtsShimPriv.apk +++ b/packages/CtsShim/apk/arm/CtsShimPriv.apk diff --git a/packages/CtsShim/apk/x86/CtsShim.apk b/packages/CtsShim/apk/x86/CtsShim.apk Binary files differindex ca69a28a04b4..bb6dfa3a4ede 100644 --- a/packages/CtsShim/apk/x86/CtsShim.apk +++ b/packages/CtsShim/apk/x86/CtsShim.apk diff --git a/packages/CtsShim/apk/x86/CtsShimPriv.apk b/packages/CtsShim/apk/x86/CtsShimPriv.apk Binary files differindex 84c34010a212..2e1a78989b70 100644 --- a/packages/CtsShim/apk/x86/CtsShimPriv.apk +++ b/packages/CtsShim/apk/x86/CtsShimPriv.apk diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/dimens.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/dimens.xml index f0cdaf603ba1..626fd3aa49f5 100644 --- a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/dimens.xml +++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/dimens.xml @@ -16,10 +16,12 @@ --> <resources> <!-- Collapsing toolbar layout dimensions --> - <dimen name="toolbar_one_line_height">226dp</dimen> - <dimen name="toolbar_two_lines_height">270dp</dimen> - <dimen name="toolbar_three_lines_height">314dp</dimen> + <dimen name="toolbar_one_line_height">216dp</dimen> + <dimen name="toolbar_two_lines_height">260dp</dimen> + <dimen name="toolbar_three_lines_height">304dp</dimen> <dimen name="scrim_visible_height_trigger">174dp</dimen> + <dimen name="scrim_visible_height_trigger_two_lines">218dp</dimen> + <dimen name="scrim_visible_height_trigger_three_lines">262dp</dimen> <dimen name="expanded_title_margin_start">24dp</dimen> <dimen name="expanded_title_margin_end">24dp</dimen> </resources>
\ No newline at end of file diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/AdjustableToolbarLayout.java b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/AdjustableToolbarLayout.java index b3053ac76b55..0e7e595a3f04 100644 --- a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/AdjustableToolbarLayout.java +++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/AdjustableToolbarLayout.java @@ -26,12 +26,9 @@ import androidx.annotation.Nullable; import com.google.android.material.appbar.CollapsingToolbarLayout; -import java.lang.reflect.Field; -import java.lang.reflect.Method; - /** - * A customized version of CollapsingToolbarLayout that can apply different font size based on - * the line count of its title. + * A customized version of CollapsingToolbarLayout that can apply different font size based on the + * line count of its title. */ public class AdjustableToolbarLayout extends CollapsingToolbarLayout { @@ -59,43 +56,25 @@ public class AdjustableToolbarLayout extends CollapsingToolbarLayout { public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { v.removeOnLayoutChangeListener(this); - final int count = getLineCountWithReflection(); + final int count = getLineCount(); if (count > TOOLBAR_MAX_LINE_NUMBER) { final ViewGroup.LayoutParams lp = getLayoutParams(); lp.height = getResources() .getDimensionPixelSize(R.dimen.toolbar_three_lines_height); + setScrimVisibleHeightTrigger( + getResources().getDimensionPixelSize( + R.dimen.scrim_visible_height_trigger_three_lines)); setLayoutParams(lp); } else if (count == TOOLBAR_MAX_LINE_NUMBER) { final ViewGroup.LayoutParams lp = getLayoutParams(); lp.height = getResources() .getDimensionPixelSize(R.dimen.toolbar_two_lines_height); + setScrimVisibleHeightTrigger( + getResources().getDimensionPixelSize( + R.dimen.scrim_visible_height_trigger_two_lines)); setLayoutParams(lp); } } }); } - - /** - * Returns a number of title line count for CollapsingToolbarLayout so that facilitates the - * determination to apply what kind of font size. Since the title of CollapsingToolbarLayout is - * drawn in a canvas and the text process is wrapped in a CollapsingTextHelper, the way we used - * here is to get the line count from the CollapsingTextHelper via Java Reflection. - */ - private int getLineCountWithReflection() { - try { - final Field textHelperField = - this.getClass().getSuperclass().getDeclaredField("collapsingTextHelper"); - textHelperField.setAccessible(true); - final Object textHelperObj = textHelperField.get(this); - - final Field layoutField = textHelperObj.getClass().getDeclaredField("textLayout"); - layoutField.setAccessible(true); - final Object layoutObj = layoutField.get(textHelperObj); - - final Method method = layoutObj.getClass().getDeclaredMethod("getLineCount"); - return (int) method.invoke(layoutObj); - } catch (Exception e) { - return 0; - } - } } diff --git a/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml b/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml index 010b9ba4324b..2d214fe65c64 100644 --- a/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml +++ b/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml @@ -48,7 +48,6 @@ android:layout_width="@dimen/settingslib_restricted_icon_size" android:layout_height="@dimen/settingslib_restricted_icon_size" android:tint="?android:attr/colorAccent" - android:theme="@android:style/Theme.Material" android:layout_gravity="center_vertical" android:layout_marginEnd="@dimen/settingslib_restricted_icon_margin_end" android:src="@*android:drawable/ic_info" diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java index 2dbfef039197..83a6973ffec6 100644 --- a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java +++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java @@ -139,6 +139,17 @@ public class RestrictedPreferenceHelper { } /** + * @return EnforcedAdmin if we have been passed the restriction in the xml. + */ + public EnforcedAdmin checkRestrictionEnforced() { + if (mAttrUserRestriction == null) { + return null; + } + return RestrictedLockUtilsInternal.checkIfRestrictionEnforced(mContext, + mAttrUserRestriction, UserHandle.myUserId()); + } + + /** * Disable this preference based on the enforce admin. * * @param admin details of the admin who enforced the restriction. If it is diff --git a/packages/SystemUI/res/drawable/screenshot_edit_background.xml b/packages/SystemUI/res/drawable/screenshot_edit_background.xml new file mode 100644 index 000000000000..5c3c12c572f6 --- /dev/null +++ b/packages/SystemUI/res/drawable/screenshot_edit_background.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2021 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<!-- Long screenshot edit FAB background --> +<ripple xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" + android:color="?android:textColorPrimary"> + <item android:id="@android:id/background"> + <shape android:shape="rectangle"> + <solid android:color="?androidprv:attr/colorAccentSecondary"/> + <corners android:radius="16dp"/> + </shape> + </item> + <item android:id="@android:id/mask"> + <shape android:shape="rectangle"> + <solid android:color="?android:textColorPrimary"/> + <corners android:radius="16dp"/> + </shape> + </item> +</ripple>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/screenshot_save_background.xml b/packages/SystemUI/res/drawable/screenshot_save_background.xml new file mode 100644 index 000000000000..cfd2dc214477 --- /dev/null +++ b/packages/SystemUI/res/drawable/screenshot_save_background.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2021 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<!-- Long screenshot save button background --> +<ripple xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" + android:color="?android:textColorPrimary"> + <item android:id="@android:id/background"> + <shape android:shape="rectangle"> + <solid android:color="?androidprv:attr/colorAccentSecondary"/> + <corners android:radius="20dp"/> + </shape> + </item> + <item android:id="@android:id/mask"> + <shape android:shape="rectangle"> + <solid android:color="?android:textColorPrimary"/> + <corners android:radius="20dp"/> + </shape> + </item> +</ripple>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/long_screenshot.xml b/packages/SystemUI/res/layout/long_screenshot.xml index de3384657d9d..8e30aecd6a27 100644 --- a/packages/SystemUI/res/layout/long_screenshot.xml +++ b/packages/SystemUI/res/layout/long_screenshot.xml @@ -28,11 +28,11 @@ android:id="@+id/save" style="@android:style/Widget.DeviceDefault.Button.Colored" android:layout_width="wrap_content" - android:layout_height="wrap_content" + android:layout_height="40dp" android:text="@string/save" android:layout_marginStart="8dp" android:layout_marginTop="4dp" - android:backgroundTint="?androidprv:attr/colorAccentSecondary" + android:background="@drawable/screenshot_save_background" android:textColor="?android:textColorSecondary" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" @@ -114,7 +114,7 @@ android:layout_marginBottom="16dp" android:layout_marginEnd="16dp" style="@android:style/Widget.DeviceDefault.Button.Colored" - android:backgroundTint="?androidprv:attr/colorAccentSecondary" + android:background="@drawable/screenshot_edit_background" android:src="@drawable/ic_screenshot_edit" android:contentDescription="@string/screenshot_edit_label" android:tint="?android:textColorSecondary" diff --git a/packages/SystemUI/res/layout/qs_paged_page.xml b/packages/SystemUI/res/layout/qs_paged_page.xml index a4f0a0c85d41..98804fc80b50 100644 --- a/packages/SystemUI/res/layout/qs_paged_page.xml +++ b/packages/SystemUI/res/layout/qs_paged_page.xml @@ -18,4 +18,8 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/tile_page" android:layout_width="match_parent" - android:layout_height="match_parent"/> + android:layout_height="match_parent" + android:paddingStart="@dimen/notification_side_paddings" + android:paddingEnd="@dimen/notification_side_paddings" + android:clipChildren="false" + android:clipToPadding="false" /> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 6a848fbd2a26..46511682464b 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -642,7 +642,7 @@ <item name="android:tint">?android:attr/textColorPrimary</item> <item name="android:stateListAnimator">@anim/media_button_state_list_animator</item> <item name="android:padding">12dp</item> - <item name="android:scaleType">fitCenter</item> + <item name="android:scaleType">centerInside</item> </style> <style name="MediaPlayer.OutlineButton"> @@ -662,7 +662,8 @@ <style name="MediaPlayer.AppIcon"> <item name="android:background">@drawable/qs_media_icon_background</item> - <item name="android:backgroundTint">?android:attr/textColorPrimary</item> + <item name="android:backgroundTint">@color/media_player_solid_button_bg</item> + <item name="android:padding">4dp</item> </style> <style name="MediaPlayer.Album"> diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconView.java b/packages/SystemUI/src/com/android/keyguard/LockIconView.java index eff412e49836..423bd5626da9 100644 --- a/packages/SystemUI/src/com/android/keyguard/LockIconView.java +++ b/packages/SystemUI/src/com/android/keyguard/LockIconView.java @@ -21,7 +21,6 @@ import android.content.Context; import android.graphics.PointF; import android.graphics.RectF; import android.util.AttributeSet; -import android.view.Surface; import android.widget.FrameLayout; import android.widget.ImageView; @@ -30,44 +29,25 @@ import android.widget.ImageView; */ public class LockIconView extends ImageView { @NonNull private final RectF mSensorRect; - @NonNull private final Context mContext; - @NonNull private PointF mLockIconCenter = new PointF(0f, 0f); private int mRadius; public LockIconView(Context context, AttributeSet attrs) { super(context, attrs); - mContext = context; mSensorRect = new RectF(); } void setLocation(@NonNull PointF center, int radius) { mLockIconCenter = center; mRadius = radius; - } - // The "h" and "w" are the display's height and width relative to its current rotation. - private void updateSensorRect(int h, int w) { - // mSensorProps coordinates assume portrait mode. + // mSensorProps coordinates assume portrait mode which is OK b/c the keyguard is always in + // portrait. mSensorRect.set(mLockIconCenter.x - mRadius, mLockIconCenter.y - mRadius, mLockIconCenter.x + mRadius, mLockIconCenter.y + mRadius); - // Transform mSensorRect if the device is in landscape mode. - switch (mContext.getDisplay().getRotation()) { - case Surface.ROTATION_90: - mSensorRect.set(mSensorRect.top, h - mSensorRect.right, mSensorRect.bottom, - h - mSensorRect.left); - break; - case Surface.ROTATION_270: - mSensorRect.set(w - mSensorRect.bottom, mSensorRect.left, w - mSensorRect.top, - mSensorRect.right); - break; - default: - // Do nothing to stay in portrait mode. - } - setX(mSensorRect.left); setY(mSensorRect.top); setLayoutParams(new FrameLayout.LayoutParams( @@ -76,18 +56,6 @@ public class LockIconView extends ImageView { } @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - super.onLayout(changed, left, top, right, bottom); - // Always re-compute the layout regardless of whether "changed" is true. It is usually false - // when the device goes from landscape to seascape and vice versa, but mSensorRect and - // its dependencies need to be recalculated to stay at the same physical location on the - // screen. - final int w = getLayoutParams().width; - final int h = getLayoutParams().height; - updateSensorRect(h, w); - } - - @Override public boolean hasOverlappingRendering() { return false; } diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java index e6fe0600b9b8..a28223de2bf1 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java @@ -117,7 +117,8 @@ public class SystemUIFactory { .setAppPairs(mWMComponent.getAppPairs()) .setTaskViewFactory(mWMComponent.getTaskViewFactory()) .setTransitions(mWMComponent.getTransitions()) - .setStartingSurface(mWMComponent.getStartingSurface()); + .setStartingSurface(mWMComponent.getStartingSurface()) + .setTaskSurfaceHelper(mWMComponent.getTaskSurfaceHelper()); } else { // TODO: Call on prepareSysUIComponentBuilder but not with real components. Other option // is separating this logic into newly creating SystemUITestsFactory. @@ -132,8 +133,8 @@ public class SystemUIFactory { .setAppPairs(Optional.ofNullable(null)) .setTaskViewFactory(Optional.ofNullable(null)) .setTransitions(Transitions.createEmptyForTesting()) - .setStartingSurface(Optional.ofNullable(null)); - + .setStartingSurface(Optional.ofNullable(null)) + .setTaskSurfaceHelper(Optional.ofNullable(null)); } mSysUIComponent = builder.build(); if (mInitializeComponents) { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java index 146f430c88a1..f8e4bdc83fbb 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java @@ -693,7 +693,6 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); - // UdfpsController is not BiometricPrompt-specific. It can be active for keyguard or // enrollment. if (mUdfpsController != null) { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.java index 7fc67bcf79e0..a52296a71960 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.java @@ -26,9 +26,11 @@ import android.graphics.PixelFormat; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.ISidefpsController; +import android.util.DisplayMetrics; import android.util.Log; import android.view.Gravity; import android.view.LayoutInflater; +import android.view.Surface; import android.view.WindowManager; import com.android.internal.annotations.VisibleForTesting; @@ -45,20 +47,19 @@ import javax.inject.Inject; @SysUISingleton public class SidefpsController { private static final String TAG = "SidefpsController"; - // TODO (b/188690214): define and retrieve values from framework via SensorProps - static final int DISPLAY_HEIGHT = 1804; - static final int DISPLAY_WIDTH = 2208; - static final int SFPS_INDICATOR_HEIGHT = 225; - static final int SFPS_Y = 500; - static final int SFPS_INDICATOR_WIDTH = 50; - - @Nullable private SidefpsView mView; - private final FingerprintManager mFingerprintManager; - private final Context mContext; + @NonNull private final Context mContext; @NonNull private final LayoutInflater mInflater; + private final FingerprintManager mFingerprintManager; private final WindowManager mWindowManager; private final DelayableExecutor mFgExecutor; + // TODO: update mDisplayHeight and mDisplayWidth for multi-display devices + private final int mDisplayHeight; + private final int mDisplayWidth; + private boolean mIsVisible = false; + @Nullable private SidefpsView mView; + + static final int SFPS_AFFORDANCE_WIDTH = 50; // in default portrait mode @NonNull private final ISidefpsController mSidefpsControllerImpl = new ISidefpsController.Stub() { @@ -110,6 +111,11 @@ public class SidefpsController { WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; mCoreLayoutParams.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY; + DisplayMetrics displayMetrics = new DisplayMetrics(); + windowManager.getDefaultDisplay().getMetrics(displayMetrics); + mDisplayHeight = displayMetrics.heightPixels; + mDisplayWidth = displayMetrics.widthPixels; + mFingerprintManager.setSidefpsController(mSidefpsControllerImpl); } @@ -122,7 +128,6 @@ public class SidefpsController { void hide() { if (mView != null) { - Log.v(TAG, "hideUdfpsOverlay | removing window"); mWindowManager.removeView(mView); mView.setOnTouchListener(null); mView.setOnHoverListener(null); @@ -132,13 +137,14 @@ public class SidefpsController { } } + void onConfigurationChanged() { - // If overlay was hidden, it should remain hidden - if (!mIsVisible) { + // If mView is null or if view is hidden, then return. + if (mView == null || !mIsVisible) { return; } - // If the overlay needs to be shown, destroy the current overlay, and re-create and show - // the overlay with the updated LayoutParams. + // If the overlay needs to be displayed with a new configuration, destroy the current + // overlay, and re-create and show the overlay with the updated LayoutParams. hide(); show(); } @@ -148,6 +154,25 @@ public class SidefpsController { for (FingerprintSensorPropertiesInternal props : mFingerprintManager.getSensorPropertiesInternal()) { if (props.isAnySidefpsType()) { + // TODO(b/188690214): L155-L173 can be removed once sensorLocationX, + // sensorLocationY, and sensorRadius are defined in sensorProps by the HAL + int sensorLocationX = 25; + int sensorLocationY = 610; + int sensorRadius = 112; + + FingerprintSensorPropertiesInternal tempProps = + new FingerprintSensorPropertiesInternal( + props.sensorId, + props.sensorStrength, + props.maxEnrollmentsPerUser, + props.componentInfo, + props.sensorType, + props.resetLockoutRequiresHardwareAuthToken, + sensorLocationX, + sensorLocationY, + sensorRadius + ); + props = tempProps; return props; } } @@ -166,17 +191,30 @@ public class SidefpsController { */ private WindowManager.LayoutParams computeLayoutParams() { mCoreLayoutParams.flags = getCoreLayoutParamFlags(); - - // Default dimensions assume portrait mode. - mCoreLayoutParams.x = DISPLAY_WIDTH - SFPS_INDICATOR_WIDTH; - mCoreLayoutParams.y = SFPS_Y; - mCoreLayoutParams.height = SFPS_INDICATOR_HEIGHT; - mCoreLayoutParams.width = SFPS_INDICATOR_WIDTH; - - /* - TODO (b/188692405): recalculate coordinates for non-portrait configurations and folding - states - */ + // Y value of top of affordance in portrait mode, X value of left of affordance in landscape + int sfpsLocationY = mSensorProps.sensorLocationY - mSensorProps.sensorRadius; + int sfpsAffordanceHeight = mSensorProps.sensorRadius * 2; + + // Calculate coordinates of drawable area for the fps affordance, accounting for orientation + switch (mContext.getDisplay().getRotation()) { + case Surface.ROTATION_90: + mCoreLayoutParams.x = sfpsLocationY; + mCoreLayoutParams.y = 0; + mCoreLayoutParams.height = SFPS_AFFORDANCE_WIDTH; + mCoreLayoutParams.width = sfpsAffordanceHeight; + break; + case Surface.ROTATION_270: + mCoreLayoutParams.x = mDisplayHeight - sfpsLocationY - sfpsAffordanceHeight; + mCoreLayoutParams.y = mDisplayWidth - SFPS_AFFORDANCE_WIDTH; + mCoreLayoutParams.height = SFPS_AFFORDANCE_WIDTH; + mCoreLayoutParams.width = sfpsAffordanceHeight; + break; + default: // Portrait + mCoreLayoutParams.x = mDisplayWidth - SFPS_AFFORDANCE_WIDTH; + mCoreLayoutParams.y = sfpsLocationY; + mCoreLayoutParams.height = sfpsAffordanceHeight; + mCoreLayoutParams.width = SFPS_AFFORDANCE_WIDTH; + } return mCoreLayoutParams; } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsView.java b/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsView.java index b9e9b596f54a..4fc59d60ff62 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsView.java @@ -16,8 +16,7 @@ package com.android.systemui.biometrics; -import static com.android.systemui.biometrics.SidefpsController.SFPS_INDICATOR_HEIGHT; -import static com.android.systemui.biometrics.SidefpsController.SFPS_INDICATOR_WIDTH; +import static com.android.systemui.biometrics.SidefpsController.SFPS_AFFORDANCE_WIDTH; import android.annotation.NonNull; import android.content.Context; @@ -27,6 +26,7 @@ import android.graphics.Paint; import android.graphics.RectF; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.util.AttributeSet; +import android.view.Surface; import android.widget.FrameLayout; /** @@ -34,18 +34,22 @@ import android.widget.FrameLayout; */ public class SidefpsView extends FrameLayout { private static final String TAG = "SidefpsView"; + private static final int POINTER_SIZE_PX = 50; + private static final int ROUND_RADIUS = 15; + @NonNull private final RectF mSensorRect; @NonNull private final Paint mSensorRectPaint; @NonNull private final Paint mPointerText; - private static final int POINTER_SIZE_PX = 50; + @NonNull private final Context mContext; // Used to obtain the sensor location. @NonNull private FingerprintSensorPropertiesInternal mSensorProps; + @Surface.Rotation private int mOrientation; public SidefpsView(Context context, AttributeSet attrs) { super(context, attrs); super.setWillNotDraw(false); - + mContext = context; mPointerText = new Paint(0 /* flags */); mPointerText.setAntiAlias(true); mPointerText.setColor(Color.WHITE); @@ -54,7 +58,7 @@ public class SidefpsView extends FrameLayout { mSensorRect = new RectF(); mSensorRectPaint = new Paint(0 /* flags */); mSensorRectPaint.setAntiAlias(true); - mSensorRectPaint.setColor(Color.BLUE); + mSensorRectPaint.setColor(Color.BLUE); // TODO: Fix Color mSensorRectPaint.setStyle(Paint.Style.FILL); } @@ -65,11 +69,19 @@ public class SidefpsView extends FrameLayout { @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); - canvas.drawRect(mSensorRect, mSensorRectPaint); + canvas.drawRoundRect(mSensorRect, ROUND_RADIUS, ROUND_RADIUS, mSensorRectPaint); + int x, y; + if (mOrientation == Surface.ROTATION_90 || mOrientation == Surface.ROTATION_270) { + x = mSensorProps.sensorRadius + 10; + y = SFPS_AFFORDANCE_WIDTH / 2 + 15; + } else { + x = SFPS_AFFORDANCE_WIDTH / 2 - 10; + y = mSensorProps.sensorRadius + 30; + } canvas.drawText( ">", - SFPS_INDICATOR_WIDTH / 2 - 10, // TODO(b/188690214): retrieve from sensorProps - SFPS_INDICATOR_HEIGHT / 2 + 30, //TODO(b/188690214): retrieve from sensorProps + x, + y, mPointerText ); } @@ -77,11 +89,19 @@ public class SidefpsView extends FrameLayout { @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); + mOrientation = mContext.getDisplay().getRotation(); + if (mOrientation == Surface.ROTATION_90 || mOrientation == Surface.ROTATION_270) { + right = mSensorProps.sensorRadius * 2; + bottom = SFPS_AFFORDANCE_WIDTH; + } else { + right = SFPS_AFFORDANCE_WIDTH; + bottom = mSensorProps.sensorRadius * 2; + } mSensorRect.set( 0, 0, - SFPS_INDICATOR_WIDTH, //TODO(b/188690214): retrieve from sensorProps - SFPS_INDICATOR_HEIGHT); //TODO(b/188690214): retrieve from sensorProps + right, + bottom); } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java index 5c360a649af0..3726ae132b64 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java @@ -123,6 +123,11 @@ public class UdfpsController implements DozeReceiver { private int mActivePointerId = -1; // The timestamp of the most recent touch log. private long mTouchLogTime; + // Sensor has a good capture for this touch. Do not need to illuminate for this particular + // touch event anymore. In other words, do not illuminate until user lifts and touches the + // sensor area again. + // TODO: We should probably try to make touch/illumination things more of a FSM + private boolean mGoodCaptureReceived; @Nullable private UdfpsView mView; // The current request from FingerprintService. Null if no current request. @@ -225,48 +230,69 @@ public class UdfpsController implements DozeReceiver { @Override public void showUdfpsOverlay(int sensorId, int reason, @NonNull IUdfpsOverlayControllerCallback callback) { - final UdfpsEnrollHelper enrollHelper; - if (reason == IUdfpsOverlayController.REASON_ENROLL_FIND_SENSOR - || reason == IUdfpsOverlayController.REASON_ENROLL_ENROLLING) { - enrollHelper = new UdfpsEnrollHelper(mContext, reason); - } else { - enrollHelper = null; - } - - mServerRequest = new ServerRequest(reason, callback, enrollHelper); - updateOverlay(); + mFgExecutor.execute(() -> { + final UdfpsEnrollHelper enrollHelper; + if (reason == IUdfpsOverlayController.REASON_ENROLL_FIND_SENSOR + || reason == IUdfpsOverlayController.REASON_ENROLL_ENROLLING) { + enrollHelper = new UdfpsEnrollHelper(mContext, reason); + } else { + enrollHelper = null; + } + mServerRequest = new ServerRequest(reason, callback, enrollHelper); + updateOverlay(); + }); } @Override public void hideUdfpsOverlay(int sensorId) { - mServerRequest = null; - updateOverlay(); + mFgExecutor.execute(() -> { + mServerRequest = null; + updateOverlay(); + }); + } + + @Override + public void onAcquiredGood(int sensorId) { + mFgExecutor.execute(() -> { + if (mView == null) { + Log.e(TAG, "Null view when onAcquiredGood for sensorId: " + sensorId); + return; + } + mGoodCaptureReceived = true; + mView.stopIllumination(); + }); } @Override public void onEnrollmentProgress(int sensorId, int remaining) { - if (mServerRequest == null) { - Log.e(TAG, "onEnrollProgress received but serverRequest is null"); - return; - } - mServerRequest.onEnrollmentProgress(remaining); + mFgExecutor.execute(() -> { + if (mServerRequest == null) { + Log.e(TAG, "onEnrollProgress received but serverRequest is null"); + return; + } + mServerRequest.onEnrollmentProgress(remaining); + }); } @Override public void onEnrollmentHelp(int sensorId) { - if (mServerRequest == null) { - Log.e(TAG, "onEnrollmentHelp received but serverRequest is null"); - return; - } - mServerRequest.onEnrollmentHelp(); + mFgExecutor.execute(() -> { + if (mServerRequest == null) { + Log.e(TAG, "onEnrollmentHelp received but serverRequest is null"); + return; + } + mServerRequest.onEnrollmentHelp(); + }); } @Override public void setDebugMessage(int sensorId, String message) { - if (mView == null) { - return; - } - mView.setDebugMessage(message); + mFgExecutor.execute(() -> { + if (mView == null) { + return; + } + mView.setDebugMessage(message); + }); } } @@ -333,7 +359,7 @@ public class UdfpsController implements DozeReceiver { private boolean onTouch(View view, MotionEvent event, boolean fromUdfpsView) { UdfpsView udfpsView = (UdfpsView) view; - final boolean isFingerDown = udfpsView.isIlluminationRequested(); + final boolean isIlluminationRequested = udfpsView.isIlluminationRequested(); boolean handled = false; switch (event.getActionMasked()) { case MotionEvent.ACTION_OUTSIDE: @@ -388,7 +414,8 @@ public class UdfpsController implements DozeReceiver { "minor: %.1f, major: %.1f, v: %.1f, exceedsVelocityThreshold: %b", minor, major, v, exceedsVelocityThreshold); final long sinceLastLog = SystemClock.elapsedRealtime() - mTouchLogTime; - if (!isFingerDown && !exceedsVelocityThreshold) { + if (!isIlluminationRequested && !mGoodCaptureReceived && + !exceedsVelocityThreshold) { onFingerDown((int) x, (int) y, minor, major); Log.v(TAG, "onTouch | finger down: " + touchInfo); mTouchLogTime = SystemClock.elapsedRealtime(); @@ -423,7 +450,7 @@ public class UdfpsController implements DozeReceiver { Log.v(TAG, "onTouch | finger move: " + touchInfo); mTouchLogTime = SystemClock.elapsedRealtime(); } - } else if (isFingerDown) { + } else { Log.v(TAG, "onTouch | finger outside"); onFingerUp(); } @@ -438,10 +465,8 @@ public class UdfpsController implements DozeReceiver { mVelocityTracker.recycle(); mVelocityTracker = null; } - if (isFingerDown) { - Log.v(TAG, "onTouch | finger up"); - onFingerUp(); - } + Log.v(TAG, "onTouch | finger up"); + onFingerUp(); mFalsingManager.isFalseTouch(UDFPS_AUTHENTICATION); break; @@ -795,13 +820,16 @@ public class UdfpsController implements DozeReceiver { // This method can be called from the UI thread. private void onFingerUp() { mActivePointerId = -1; + mGoodCaptureReceived = false; mMainHandler.removeCallbacks(mAcquiredVibration); if (mView == null) { Log.w(TAG, "Null view in onFingerUp"); return; } mFingerprintManager.onPointerUp(mSensorProps.sensorId); - mView.stopIllumination(); + if (mView.isIlluminationRequested()) { + mView.stopIllumination(); + } } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java index c04201caa182..0fdc4d8e86a7 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java @@ -36,6 +36,7 @@ import com.android.wm.shell.onehanded.OneHanded; import com.android.wm.shell.pip.Pip; import com.android.wm.shell.splitscreen.SplitScreen; import com.android.wm.shell.startingsurface.StartingSurface; +import com.android.wm.shell.tasksurfacehelper.TaskSurfaceHelper; import com.android.wm.shell.transition.ShellTransitions; import java.util.Optional; @@ -94,6 +95,9 @@ public interface SysUIComponent { @BindsInstance Builder setStartingSurface(Optional<StartingSurface> s); + @BindsInstance + Builder setTaskSurfaceHelper(Optional<TaskSurfaceHelper> t); + SysUIComponent build(); } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java index bbd95b4d0c90..442d351729d7 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java @@ -33,6 +33,7 @@ import com.android.wm.shell.onehanded.OneHanded; import com.android.wm.shell.pip.Pip; import com.android.wm.shell.splitscreen.SplitScreen; import com.android.wm.shell.startingsurface.StartingSurface; +import com.android.wm.shell.tasksurfacehelper.TaskSurfaceHelper; import com.android.wm.shell.transition.ShellTransitions; import java.util.Optional; @@ -102,4 +103,7 @@ public interface WMComponent { @WMSingleton Optional<StartingSurface> getStartingSurface(); + + @WMSingleton + Optional<TaskSurfaceHelper> getTaskSurfaceHelper(); } diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java index 55feea970e84..d698142674ce 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java +++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java @@ -315,8 +315,7 @@ public class MediaControlPanel { appIconView.clearColorFilter(); if (data.getAppIcon() != null && !data.getResumption()) { appIconView.setImageIcon(data.getAppIcon()); - int color = Utils.getColorAttrDefaultColor(mContext, - com.android.internal.R.attr.colorAccentTertiary); + int color = mContext.getColor(android.R.color.system_accent2_900); appIconView.setColorFilter(color); } else { appIconView.setColorFilter(getGrayscaleFilter()); diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java index e0c8af6b8977..ce1066ee41c2 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java +++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java @@ -80,8 +80,22 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout { @Override public void setPageMargin(int marginPixels) { - if (marginPixels != getPageMargin()) { - super.setPageMargin(marginPixels); + // Using page margins creates some rounding issues that interfere with the correct position + // in the onPageChangedListener and therefore present bad positions to the PageIndicator. + // Instead, we use negative margins in the container and positive padding in the pages, + // matching the margin set from QSContainerImpl (note that new pages will always be inflated + // with the correct value. + // QSContainerImpl resources are set onAttachedView, so this view will always have the right + // values when attached. + MarginLayoutParams lp = (MarginLayoutParams) getLayoutParams(); + lp.setMarginStart(-marginPixels); + lp.setMarginEnd(-marginPixels); + setLayoutParams(lp); + + int nPages = mPages.size(); + for (int i = 0; i < nPages; i++) { + View v = mPages.get(i); + v.setPadding(marginPixels, v.getPaddingTop(), marginPixels, v.getPaddingBottom()); } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java index cd97f976540d..edfbed04f70d 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java @@ -295,7 +295,7 @@ public class QSContainerImpl extends FrameLayout { qsPanelController.setContentMargins(mContentPadding, mContentPadding); // Set it as double the side margin (to simulate end margin of current page + // start margin of next page). - qsPanelController.setPageMargin(2 * mSideMargins); + qsPanelController.setPageMargin(mSideMargins); } else if (view == mHeader) { // No content padding for the header. } else { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java index 86465b6f6b1a..b60ef1d62ef5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java @@ -382,13 +382,15 @@ public class StackScrollAlgorithm { final boolean isHunGoingToShade = ambientState.isShadeExpanded() && view == ambientState.getTrackedHeadsUpRow(); - if (!isHunGoingToShade) { - if (ambientState.isExpansionChanging() && !ambientState.isOnKeyguard()) { - viewState.alpha = Interpolators.getNotificationScrimAlpha( - ambientState.getExpansionFraction(), true /* notification */); - } else { - viewState.alpha = 1f - ambientState.getHideAmount(); - } + if (isHunGoingToShade) { + // Keep 100% opacity for heads up notification going to shade. + } else if (ambientState.isOnKeyguard()) { + // Adjust alpha for wakeup to lockscreen. + viewState.alpha = 1f - ambientState.getHideAmount(); + } else if (ambientState.isExpansionChanging()) { + // Adjust alpha for shade open & close. + viewState.alpha = Interpolators.getNotificationScrimAlpha( + ambientState.getExpansionFraction(), true /* notification */); } if (view.mustStayOnScreen() && viewState.yTranslation >= 0) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java index eb46fe3c6177..a7b802ac4afc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -75,6 +75,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.jank.InteractionJankMonitor; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.internal.policy.ScreenDecorationsUtils; import com.android.internal.util.LatencyTracker; import com.android.keyguard.KeyguardStatusView; import com.android.keyguard.KeyguardStatusViewController; @@ -906,8 +907,7 @@ public class NotificationPanelViewController extends PanelViewController { R.dimen.pulse_expansion_max_top_overshoot); mScrimCornerRadius = mResources.getDimensionPixelSize( R.dimen.notification_scrim_corner_radius); - mScreenCornerRadius = mResources.getDimensionPixelSize( - com.android.internal.R.dimen.rounded_corner_radius); + mScreenCornerRadius = (int) ScreenDecorationsUtils.getWindowCornerRadius(mResources); mNotificationScrimPadding = mResources.getDimensionPixelSize( R.dimen.notification_side_paddings); mLockscreenNotificationQSPadding = mResources.getDimensionPixelSize( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt index 7dccf01dcbc6..ef7fac311799 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt @@ -53,8 +53,8 @@ class OngoingCallController @Inject constructor( private val logger: OngoingCallLogger ) : CallbackController<OngoingCallListener> { - /** Null if there's no ongoing call. */ - private var ongoingCallInfo: OngoingCallInfo? = null + /** Non-null if there's an active call notification. */ + private var callNotificationInfo: CallNotificationInfo? = null /** True if the application managing the call is visible to the user. */ private var isCallAppVisible: Boolean = true private var chipView: View? = null @@ -76,19 +76,34 @@ class OngoingCallController @Inject constructor( } override fun onEntryUpdated(entry: NotificationEntry) { - if (isOngoingCallNotification(entry)) { - ongoingCallInfo = OngoingCallInfo( - entry.sbn.notification.`when`, - entry.sbn.notification.contentIntent.intent, - entry.sbn.uid) - updateChip() - } else if (isCallNotification(entry)) { - removeChip() + // We have a new call notification or our existing call notification has been updated. + // TODO(b/183229367): This likely won't work if you take a call from one app then + // switch to a call from another app. + if (callNotificationInfo == null && isCallNotification(entry) || + (entry.sbn.key == callNotificationInfo?.key)) { + val newOngoingCallInfo = CallNotificationInfo( + entry.sbn.key, + entry.sbn.notification.`when`, + entry.sbn.notification.contentIntent.intent, + entry.sbn.uid, + entry.sbn.notification.extras.getInt( + Notification.EXTRA_CALL_TYPE, -1) == CALL_TYPE_ONGOING + ) + if (newOngoingCallInfo == callNotificationInfo) { + return + } + + callNotificationInfo = newOngoingCallInfo + if (newOngoingCallInfo.isOngoing) { + updateChip() + } else { + removeChip() + } } } override fun onEntryRemoved(entry: NotificationEntry, reason: Int) { - if (isOngoingCallNotification(entry)) { + if (entry.sbn.key == callNotificationInfo?.key) { removeChip() } } @@ -126,7 +141,7 @@ class OngoingCallController @Inject constructor( * Returns true if there's an active ongoing call that should be displayed in a status bar chip. */ fun hasOngoingCall(): Boolean { - return ongoingCallInfo != null && + return callNotificationInfo?.isOngoing == true && // When the user is in the phone app, don't show the chip. !isCallAppVisible } @@ -146,7 +161,7 @@ class OngoingCallController @Inject constructor( } private fun updateChip() { - val currentOngoingCallInfo = ongoingCallInfo ?: return + val currentCallNotificationInfo = callNotificationInfo ?: return val currentChipView = chipView val timeView = @@ -155,7 +170,7 @@ class OngoingCallController @Inject constructor( currentChipView?.findViewById<View>(R.id.ongoing_call_chip_background) if (currentChipView != null && timeView != null && backgroundView != null) { - timeView.base = currentOngoingCallInfo.callStartTime - + timeView.base = currentCallNotificationInfo.callStartTime - System.currentTimeMillis() + systemClock.elapsedRealtime() timeView.start() @@ -163,17 +178,17 @@ class OngoingCallController @Inject constructor( currentChipView.setOnClickListener { logger.logChipClicked() activityStarter.postStartActivityDismissingKeyguard( - currentOngoingCallInfo.intent, 0, + currentCallNotificationInfo.intent, 0, ActivityLaunchAnimator.Controller.fromView(backgroundView)) } - setUpUidObserver(currentOngoingCallInfo) + setUpUidObserver(currentCallNotificationInfo) mListeners.forEach { l -> l.onOngoingCallStateChanged(animate = true) } } else { - // If we failed to update the chip, don't store the ongoing call info. Then - // [hasOngoingCall] will return false and we fall back to typical notification handling. - ongoingCallInfo = null + // If we failed to update the chip, don't store the call info. Then [hasOngoingCall] + // will return false and we fall back to typical notification handling. + callNotificationInfo = null if (DEBUG) { Log.w(TAG, "Ongoing call chip view could not be found; " + @@ -185,14 +200,14 @@ class OngoingCallController @Inject constructor( /** * Sets up an [IUidObserver] to monitor the status of the application managing the ongoing call. */ - private fun setUpUidObserver(currentOngoingCallInfo: OngoingCallInfo) { + private fun setUpUidObserver(currentCallNotificationInfo: CallNotificationInfo) { isCallAppVisible = isProcessVisibleToUser( - iActivityManager.getUidProcessState(currentOngoingCallInfo.uid, null)) + iActivityManager.getUidProcessState(currentCallNotificationInfo.uid, null)) uidObserver = object : IUidObserver.Stub() { override fun onUidStateChanged( uid: Int, procState: Int, procStateSeq: Long, capability: Int) { - if (uid == currentOngoingCallInfo.uid) { + if (uid == currentCallNotificationInfo.uid) { val oldIsCallAppVisible = isCallAppVisible isCallAppVisible = isProcessVisibleToUser(procState) if (oldIsCallAppVisible != isCallAppVisible) { @@ -225,26 +240,23 @@ class OngoingCallController @Inject constructor( } private fun removeChip() { - ongoingCallInfo = null + callNotificationInfo = null mListeners.forEach { l -> l.onOngoingCallStateChanged(animate = true) } if (uidObserver != null) { iActivityManager.unregisterUidObserver(uidObserver) } } - private class OngoingCallInfo( + private data class CallNotificationInfo( + val key: String, val callStartTime: Long, val intent: Intent, - val uid: Int + val uid: Int, + /** True if the call is currently ongoing (as opposed to incoming, screening, etc.). */ + val isOngoing: Boolean ) } -private fun isOngoingCallNotification(entry: NotificationEntry): Boolean { - val extras = entry.sbn.notification.extras - return isCallNotification(entry) && - extras.getInt(Notification.EXTRA_CALL_TYPE, -1) == CALL_TYPE_ONGOING -} - private fun isCallNotification(entry: NotificationEntry): Boolean { return entry.sbn.notification.isStyle(Notification.CallStyle::class.java) } diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java index 6c306743e4ce..6ef74505a681 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java @@ -73,6 +73,8 @@ import com.android.wm.shell.splitscreen.SplitScreenController; import com.android.wm.shell.startingsurface.StartingSurface; import com.android.wm.shell.startingsurface.StartingWindowController; import com.android.wm.shell.startingsurface.StartingWindowTypeAlgorithm; +import com.android.wm.shell.tasksurfacehelper.TaskSurfaceHelper; +import com.android.wm.shell.tasksurfacehelper.TaskSurfaceHelperController; import com.android.wm.shell.transition.ShellTransitions; import com.android.wm.shell.transition.Transitions; @@ -253,6 +255,24 @@ public abstract class WMShellBaseModule { } // + // Task to Surface communication + // + + @WMSingleton + @Provides + static Optional<TaskSurfaceHelper> provideTaskSurfaceHelper( + Optional<TaskSurfaceHelperController> taskSurfaceController) { + return taskSurfaceController.map((controller) -> controller.asTaskSurfaceHelper()); + } + + @WMSingleton + @Provides + static Optional<TaskSurfaceHelperController> provideTaskSurfaceHelperController( + ShellTaskOrganizer taskOrganizer, @ShellMainThread ShellExecutor mainExecutor) { + return Optional.ofNullable(new TaskSurfaceHelperController(taskOrganizer, mainExecutor)); + } + + // // Pip (optional feature) // diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java index 46c18480c77b..9322aa9b0ea8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java @@ -275,6 +275,7 @@ public class UdfpsControllerTest extends SysuiTestCase { mScreenObserver.onScreenTurnedOn(); mFgExecutor.runAllReady(); mUdfpsController.onAodInterrupt(0, 0, 0f, 0f); + when(mUdfpsView.isIlluminationRequested()).thenReturn(true); // WHEN it is cancelled mUdfpsController.onCancelUdfps(); // THEN the illumination is hidden @@ -289,6 +290,7 @@ public class UdfpsControllerTest extends SysuiTestCase { mScreenObserver.onScreenTurnedOn(); mFgExecutor.runAllReady(); mUdfpsController.onAodInterrupt(0, 0, 0f, 0f); + when(mUdfpsView.isIlluminationRequested()).thenReturn(true); // WHEN it times out mFgExecutor.advanceClockToNext(); mFgExecutor.runAllReady(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt index 3a71ecf42699..ca3cff98b78c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt @@ -55,6 +55,8 @@ import org.mockito.Mockito.mock import org.mockito.Mockito.never import org.mockito.Mockito.times import org.mockito.Mockito.verify +import org.mockito.Mockito.reset + import org.mockito.MockitoAnnotations private const val CALL_UID = 900 @@ -138,15 +140,51 @@ class OngoingCallControllerTest : SysuiTestCase() { .onOngoingCallStateChanged(anyBoolean()) } + /** + * If a call notification is never added before #onEntryRemoved is called, then the listener + * should never be notified. + */ @Test - fun onEntryRemoved_ongoingCallNotif_listenerNotified() { + fun onEntryRemoved_callNotifNeverAddedBeforehand_listenerNotNotified() { notifCollectionListener.onEntryRemoved(createOngoingCallNotifEntry(), REASON_USER_STOPPED) + verify(mockOngoingCallListener, never()).onOngoingCallStateChanged(anyBoolean()) + } + + @Test + fun onEntryRemoved_callNotifAddedThenRemoved_listenerNotified() { + val ongoingCallNotifEntry = createOngoingCallNotifEntry() + notifCollectionListener.onEntryAdded(ongoingCallNotifEntry) + reset(mockOngoingCallListener) + + notifCollectionListener.onEntryRemoved(ongoingCallNotifEntry, REASON_USER_STOPPED) + verify(mockOngoingCallListener).onOngoingCallStateChanged(anyBoolean()) } + /** Regression test for b/188491504. */ @Test - fun onEntryRemoved_notOngoingCallNotif_listenerNotNotified() { + fun onEntryRemoved_removedNotifHasSameKeyAsAddedNotif_listenerNotified() { + val ongoingCallNotifEntry = createOngoingCallNotifEntry() + notifCollectionListener.onEntryAdded(ongoingCallNotifEntry) + reset(mockOngoingCallListener) + + // Create another notification based on the ongoing call one, but remove the features that + // made it a call notification. + val removedEntryBuilder = NotificationEntryBuilder(ongoingCallNotifEntry) + removedEntryBuilder.modifyNotification(context).style = null + + notifCollectionListener.onEntryRemoved(removedEntryBuilder.build(), REASON_USER_STOPPED) + + verify(mockOngoingCallListener).onOngoingCallStateChanged(anyBoolean()) + } + + + @Test + fun onEntryRemoved_notifKeyDoesNotMatchOngoingCallNotif_listenerNotNotified() { + notifCollectionListener.onEntryAdded(createOngoingCallNotifEntry()) + reset(mockOngoingCallListener) + notifCollectionListener.onEntryRemoved(createNotCallNotifEntry(), REASON_USER_STOPPED) verify(mockOngoingCallListener, never()).onOngoingCallStateChanged(anyBoolean()) @@ -158,6 +196,20 @@ class OngoingCallControllerTest : SysuiTestCase() { } @Test + fun hasOngoingCall_unrelatedNotifSent_returnsFalse() { + notifCollectionListener.onEntryUpdated(createNotCallNotifEntry()) + + assertThat(controller.hasOngoingCall()).isFalse() + } + + @Test + fun hasOngoingCall_screeningCallNotifSent_returnsFalse() { + notifCollectionListener.onEntryUpdated(createScreeningCallNotifEntry()) + + assertThat(controller.hasOngoingCall()).isFalse() + } + + @Test fun hasOngoingCall_ongoingCallNotifSentAndCallAppNotVisible_returnsTrue() { `when`(mockIActivityManager.getUidProcessState(eq(CALL_UID), nullable(String::class.java))) .thenReturn(PROC_STATE_INVISIBLE) @@ -224,6 +276,7 @@ class OngoingCallControllerTest : SysuiTestCase() { fun setChipView_whenHasOngoingCallIsTrue_listenerNotifiedWithNewView() { // Start an ongoing call. notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry()) + reset(mockOngoingCallListener) lateinit var newChipView: View TestableLooper.get(this).runWithLooper { @@ -233,10 +286,7 @@ class OngoingCallControllerTest : SysuiTestCase() { // Change the chip view associated with the controller. controller.setChipView(newChipView) - // Verify the listener was notified once for the initial call and again when the new view - // was set. - verify(mockOngoingCallListener, times(2)) - .onOngoingCallStateChanged(anyBoolean()) + verify(mockOngoingCallListener).onOngoingCallStateChanged(anyBoolean()) } @Test @@ -245,6 +295,7 @@ class OngoingCallControllerTest : SysuiTestCase() { `when`(mockIActivityManager.getUidProcessState(eq(CALL_UID), nullable(String::class.java))) .thenReturn(PROC_STATE_INVISIBLE) notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry()) + reset(mockOngoingCallListener) val captor = ArgumentCaptor.forClass(IUidObserver.Stub::class.java) verify(mockIActivityManager).registerUidObserver( @@ -256,9 +307,7 @@ class OngoingCallControllerTest : SysuiTestCase() { mainExecutor.advanceClockToLast() mainExecutor.runAllReady(); - // Once for when the call was started, and another time when the process visibility changes. - verify(mockOngoingCallListener, times(2)) - .onOngoingCallStateChanged(anyBoolean()) + verify(mockOngoingCallListener).onOngoingCallStateChanged(anyBoolean()) } @Test @@ -267,6 +316,7 @@ class OngoingCallControllerTest : SysuiTestCase() { `when`(mockIActivityManager.getUidProcessState(eq(CALL_UID), nullable(String::class.java))) .thenReturn(PROC_STATE_VISIBLE) notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry()) + reset(mockOngoingCallListener) val captor = ArgumentCaptor.forClass(IUidObserver.Stub::class.java) verify(mockIActivityManager).registerUidObserver( @@ -278,9 +328,7 @@ class OngoingCallControllerTest : SysuiTestCase() { mainExecutor.advanceClockToLast() mainExecutor.runAllReady(); - // Once for when the call was started, and another time when the process visibility changes. - verify(mockOngoingCallListener, times(2)) - .onOngoingCallStateChanged(anyBoolean()) + verify(mockOngoingCallListener).onOngoingCallStateChanged(anyBoolean()) } @Test diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 8041ec4a9727..9e4290098843 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -811,7 +811,8 @@ public final class ActiveServices { } mAm.mAppOpsService.startOperation(AppOpsManager.getToken(mAm.mAppOpsService), AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, null, - true, false, null, false); + true, false, null, false, AppOpsManager.ATTRIBUTION_FLAGS_NONE, + AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE); } final ServiceMap smap = getServiceMapLocked(r.userId); @@ -1881,7 +1882,8 @@ public final class ActiveServices { mAm.mAppOpsService.startOperation( AppOpsManager.getToken(mAm.mAppOpsService), AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, - null, true, false, "", false); + null, true, false, "", false, AppOpsManager.ATTRIBUTION_FLAGS_NONE, + AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE); registerAppOpCallbackLocked(r); mAm.updateForegroundServiceUsageStats(r.name, r.userId, true); } @@ -6191,7 +6193,8 @@ public final class ActiveServices { r.mFgsNotificationDeferred, r.mFgsNotificationShown, durationMs, - r.mStartForegroundCount); + r.mStartForegroundCount, + ActivityManagerUtils.hashComponentNameForAtom(r.shortInstanceName)); } boolean canAllowWhileInUsePermissionInFgsLocked(int callingPid, int callingUid, diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 6e500e4ea5ea..294762139f50 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -156,6 +156,7 @@ import android.app.ActivityThread; import android.app.AnrController; import android.app.AppGlobals; import android.app.AppOpsManager; +import android.app.AppOpsManager.AttributionFlags; import android.app.AppOpsManagerInternal.CheckOpsDelegate; import android.app.ApplicationErrorReport; import android.app.ApplicationExitInfo; @@ -346,6 +347,7 @@ import com.android.internal.util.FastPrintWriter; import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.MemInfoReader; import com.android.internal.util.Preconditions; +import com.android.internal.util.function.DecFunction; import com.android.internal.util.function.HeptFunction; import com.android.internal.util.function.HexFunction; import com.android.internal.util.function.NonaFunction; @@ -353,6 +355,7 @@ import com.android.internal.util.function.OctFunction; import com.android.internal.util.function.QuadFunction; import com.android.internal.util.function.QuintFunction; import com.android.internal.util.function.TriFunction; +import com.android.internal.util.function.UndecFunction; import com.android.server.AlarmManagerInternal; import com.android.server.DeviceIdleInternal; import com.android.server.DisplayThread; @@ -1833,7 +1836,9 @@ public class ActivityManagerService extends IActivityManager.Stub final int[] cameraOp = {AppOpsManager.OP_CAMERA}; mAppOpsService.startWatchingActive(cameraOp, new IAppOpsActiveCallback.Stub() { @Override - public void opActiveChanged(int op, int uid, String packageName, boolean active) { + public void opActiveChanged(int op, int uid, String packageName, String attributionTag, + boolean active, @AttributionFlags int attributionFlags, + int attributionChainId) { cameraActiveChanged(uid, active); } }); @@ -6216,8 +6221,20 @@ public class ActivityManagerService extends IActivityManager.Stub // signature we just use the first package in the UID. For shared // UIDs we may blame the wrong app but that is Okay as they are // in the same security/privacy sandbox. - final AndroidPackage androidPackage = mPackageManagerInt - .getPackage(Binder.getCallingUid()); + final int uid = Binder.getCallingUid(); + // Here we handle some of the special UIDs (mediaserver, systemserver, etc) + final String packageName = AppOpsManager.resolvePackageName(uid, + /*packageName*/ null); + final AndroidPackage androidPackage; + if (packageName != null) { + androidPackage = mPackageManagerInt.getPackage(packageName); + } else { + androidPackage = mPackageManagerInt.getPackage(uid); + } + if (androidPackage == null) { + Log.e(TAG, "Cannot find package for uid: " + uid); + return null; + } final AttributionSource attributionSource = new AttributionSource( Binder.getCallingUid(), androidPackage.getPackageName(), null); pfd = cph.provider.openFile(attributionSource, uri, "r", null); @@ -16866,7 +16883,7 @@ public class ActivityManagerService extends IActivityManager.Stub try { return superImpl.apply(code, new AttributionSource(shellUid, "com.android.shell", attributionSource.getAttributionTag(), - attributionSource.getNext()), + attributionSource.getToken(), attributionSource.getNext()), shouldCollectAsyncNotedOp, message, shouldCollectMessage, skiProxyOperation); } finally { @@ -16882,8 +16899,9 @@ public class ActivityManagerService extends IActivityManager.Stub @Nullable String packageName, @Nullable String attributionTag, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, @Nullable String message, boolean shouldCollectMessage, - @NonNull NonaFunction<IBinder, Integer, Integer, String, String, Boolean, - Boolean, String, Boolean, SyncNotedAppOp> superImpl) { + @AttributionFlags int attributionFlags, int attributionChainId, + @NonNull UndecFunction<IBinder, Integer, Integer, String, String, Boolean, + Boolean, String, Boolean, Integer, Integer, SyncNotedAppOp> superImpl) { if (uid == mTargetUid && isTargetOp(code)) { final int shellUid = UserHandle.getUid(UserHandle.getUserId(uid), Process.SHELL_UID); @@ -16891,57 +16909,62 @@ public class ActivityManagerService extends IActivityManager.Stub try { return superImpl.apply(token, code, shellUid, "com.android.shell", attributionTag, startIfModeDefault, shouldCollectAsyncNotedOp, message, - shouldCollectMessage); + shouldCollectMessage, attributionFlags, attributionChainId); } finally { Binder.restoreCallingIdentity(identity); } } return superImpl.apply(token, code, uid, packageName, attributionTag, - startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage); + startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage, + attributionFlags, attributionChainId); } @Override - public SyncNotedAppOp startProxyOperation(IBinder token, int code, + public SyncNotedAppOp startProxyOperation(int code, @NonNull AttributionSource attributionSource, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage, - boolean skipProsyOperation, @NonNull OctFunction<IBinder, Integer, - AttributionSource, Boolean, Boolean, String, Boolean, Boolean, - SyncNotedAppOp> superImpl) { + boolean skipProxyOperation, @AttributionFlags int proxyAttributionFlags, + @AttributionFlags int proxiedAttributionFlags, int attributionChainId, + @NonNull DecFunction<Integer, AttributionSource, Boolean, Boolean, String, Boolean, + Boolean, Integer, Integer, Integer, SyncNotedAppOp> superImpl) { if (attributionSource.getUid() == mTargetUid && isTargetOp(code)) { final int shellUid = UserHandle.getUid(UserHandle.getUserId( attributionSource.getUid()), Process.SHELL_UID); final long identity = Binder.clearCallingIdentity(); try { - return superImpl.apply(token, code, new AttributionSource(shellUid, - "com.android.shell", attributionSource.getAttributionTag(), - attributionSource.getNext()), startIfModeDefault, - shouldCollectAsyncNotedOp, message, shouldCollectMessage, - skipProsyOperation); + return superImpl.apply(code, new AttributionSource(shellUid, + "com.android.shell", attributionSource.getAttributionTag(), + attributionSource.getToken(), attributionSource.getNext()), + startIfModeDefault, shouldCollectAsyncNotedOp, message, + shouldCollectMessage, skipProxyOperation, proxyAttributionFlags, + proxiedAttributionFlags, attributionChainId); } finally { Binder.restoreCallingIdentity(identity); } } - return superImpl.apply(token, code, attributionSource, startIfModeDefault, - shouldCollectAsyncNotedOp, message, shouldCollectMessage, skipProsyOperation); + return superImpl.apply(code, attributionSource, startIfModeDefault, + shouldCollectAsyncNotedOp, message, shouldCollectMessage, skipProxyOperation, + proxyAttributionFlags, proxiedAttributionFlags, attributionChainId); } @Override - public void finishProxyOperation(IBinder clientId, int code, - @NonNull AttributionSource attributionSource, - @NonNull TriFunction<IBinder, Integer, AttributionSource, Void> superImpl) { + public void finishProxyOperation(int code, @NonNull AttributionSource attributionSource, + boolean skipProxyOperation, @NonNull TriFunction<Integer, AttributionSource, + Boolean, Void> superImpl) { if (attributionSource.getUid() == mTargetUid && isTargetOp(code)) { final int shellUid = UserHandle.getUid(UserHandle.getUserId( attributionSource.getUid()), Process.SHELL_UID); final long identity = Binder.clearCallingIdentity(); try { - superImpl.apply(clientId, code, new AttributionSource(shellUid, + superImpl.apply(code, new AttributionSource(shellUid, "com.android.shell", attributionSource.getAttributionTag(), - attributionSource.getNext())); + attributionSource.getToken(), attributionSource.getNext()), + skipProxyOperation); } finally { Binder.restoreCallingIdentity(identity); } } - superImpl.apply(clientId, code, attributionSource); + superImpl.apply(code, attributionSource, skipProxyOperation); } private boolean isTargetOp(int code) { diff --git a/services/core/java/com/android/server/am/ActivityManagerUtils.java b/services/core/java/com/android/server/am/ActivityManagerUtils.java index dd2414866542..5506ad1b245b 100644 --- a/services/core/java/com/android/server/am/ActivityManagerUtils.java +++ b/services/core/java/com/android/server/am/ActivityManagerUtils.java @@ -121,4 +121,12 @@ public class ActivityManagerUtils { return (((double) hash) / Integer.MAX_VALUE) <= rate; } + + /** + * @param shortInstanceName {@link ServiceRecord#shortInstanceName}. + * @return hash of the ServiceRecord's shortInstanceName, combined with ANDROID_ID. + */ + public static int hashComponentNameForAtom(String shortInstanceName) { + return getUnsignedHashUnCached(shortInstanceName) ^ getAndroidIdHash(); + } } diff --git a/services/core/java/com/android/server/am/AssistDataRequester.java b/services/core/java/com/android/server/am/AssistDataRequester.java index 70a54cfdafa5..98ad81d7d9de 100644 --- a/services/core/java/com/android/server/am/AssistDataRequester.java +++ b/services/core/java/com/android/server/am/AssistDataRequester.java @@ -16,6 +16,7 @@ package com.android.server.am; +import static android.app.ActivityManager.ASSIST_CONTEXT_CONTENT; import static android.app.ActivityManager.ASSIST_CONTEXT_FULL; import static android.app.AppOpsManager.MODE_ALLOWED; import static android.app.AppOpsManager.OP_NONE; @@ -143,45 +144,47 @@ public class AssistDataRequester extends IAssistDataReceiver.Stub { * Request that autofill data be loaded asynchronously. The resulting data will be provided * through the {@link AssistDataRequesterCallbacks}. * - * See {@link #requestData(List, boolean, boolean, boolean, boolean, boolean, int, String, - * boolean)}. + * See {@link #requestData(List, boolean, boolean, boolean, boolean, boolean, boolean, int, + * String, boolean)}. */ public void requestAutofillData(List<IBinder> activityTokens, int callingUid, String callingPackage) { requestData(activityTokens, true /* requestAutofillData */, true /* fetchData */, false /* fetchScreenshot */, - true /* allowFetchData */, false /* allowFetchScreenshot */, - false /* ignoreTopActivityCheck */, callingUid, callingPackage); + true /* fetchStructure */, true /* allowFetchData */, + false /* allowFetchScreenshot */, false /* ignoreTopActivityCheck */, callingUid, + callingPackage); } /** * Request that assist data be loaded asynchronously. The resulting data will be provided * through the {@link AssistDataRequesterCallbacks}. * - * See {@link #requestData(List, boolean, boolean, boolean, boolean, boolean, int, String, - * boolean)}. + * See {@link #requestData(List, boolean, boolean, boolean, boolean, boolean, boolean, int, + * String, boolean)}. */ public void requestAssistData(List<IBinder> activityTokens, final boolean fetchData, final boolean fetchScreenshot, boolean allowFetchData, boolean allowFetchScreenshot, int callingUid, String callingPackage) { - requestAssistData(activityTokens, fetchData, fetchScreenshot, allowFetchData, - allowFetchScreenshot, false /* ignoreTopActivityCheck */, callingUid, - callingPackage); + requestAssistData(activityTokens, fetchData, fetchScreenshot, true /* fetchStructure */, + allowFetchData, allowFetchScreenshot, false /* ignoreTopActivityCheck */, + callingUid, callingPackage); } /** * Request that assist data be loaded asynchronously. The resulting data will be provided * through the {@link AssistDataRequesterCallbacks}. * - * See {@link #requestData(List, boolean, boolean, boolean, boolean, boolean, int, String, - * boolean)}. + * See {@link #requestData(List, boolean, boolean, boolean, boolean, boolean, boolean, int, + * String, boolean)}. */ public void requestAssistData(List<IBinder> activityTokens, final boolean fetchData, - final boolean fetchScreenshot, boolean allowFetchData, boolean allowFetchScreenshot, - boolean ignoreTopActivityCheck, int callingUid, String callingPackage) { + final boolean fetchScreenshot, final boolean fetchStructure, boolean allowFetchData, + boolean allowFetchScreenshot, boolean ignoreTopActivityCheck, int callingUid, + String callingPackage) { requestData(activityTokens, false /* requestAutofillData */, fetchData, fetchScreenshot, - allowFetchData, allowFetchScreenshot, ignoreTopActivityCheck, callingUid, - callingPackage); + fetchStructure, allowFetchData, allowFetchScreenshot, ignoreTopActivityCheck, + callingUid, callingPackage); } /** @@ -197,6 +200,8 @@ public class AssistDataRequester extends IAssistDataReceiver.Stub { * @param fetchScreenshot whether or not to fetch the screenshot, only applies if fetchData is * true, the caller is allowed to fetch the assist data, and the current activity allows * assist data to be fetched from it + * @param fetchStructure whether or not to fetch the AssistStructure along with the + * AssistContent * @param allowFetchData to be joined with other checks, determines whether or not the requester * is allowed to fetch the assist data * @param allowFetchScreenshot to be joined with other checks, determines whether or not the @@ -205,9 +210,9 @@ public class AssistDataRequester extends IAssistDataReceiver.Stub { * making the request. Used when passing an activity from Recents. */ private void requestData(List<IBinder> activityTokens, final boolean requestAutofillData, - final boolean fetchData, final boolean fetchScreenshot, boolean allowFetchData, - boolean allowFetchScreenshot, boolean ignoreTopActivityCheck, int callingUid, - String callingPackage) { + final boolean fetchData, final boolean fetchScreenshot, final boolean fetchStructure, + boolean allowFetchData, boolean allowFetchScreenshot, boolean ignoreTopActivityCheck, + int callingUid, String callingPackage) { // TODO(b/34090158): Known issue, if the assist data is not allowed on the current activity, // then no assist data is requested for any of the other activities @@ -246,13 +251,18 @@ public class AssistDataRequester extends IAssistDataReceiver.Stub { Bundle receiverExtras = new Bundle(); receiverExtras.putInt(KEY_RECEIVER_EXTRA_INDEX, i); receiverExtras.putInt(KEY_RECEIVER_EXTRA_COUNT, numActivities); - boolean result = requestAutofillData - ? mActivityTaskManager.requestAutofillData(this, - receiverExtras, topActivity, 0 /* flags */) - : mActivityTaskManager.requestAssistContextExtras( - ASSIST_CONTEXT_FULL, this, receiverExtras, topActivity, + boolean result; + if (requestAutofillData) { + result = mActivityTaskManager.requestAutofillData(this, receiverExtras, + topActivity, 0 /* flags */); + } else { + int requestType = fetchStructure ? ASSIST_CONTEXT_FULL : + ASSIST_CONTEXT_CONTENT; + result = mActivityTaskManager.requestAssistContextExtras( + requestType, this, receiverExtras, topActivity, /* checkActivityIsTop= */ (i == 0) && !ignoreTopActivityCheck, /* newSessionId= */ i == 0); + } if (result) { mPendingDataCount++; } else if (i == 0) { diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java index f70b0fb1d207..96db1adcfddb 100644 --- a/services/core/java/com/android/server/app/GameManagerService.java +++ b/services/core/java/com/android/server/app/GameManagerService.java @@ -267,7 +267,8 @@ public final class GameManagerService extends IGameManagerService.Stub { mAllowDownscale = true; } } catch (PackageManager.NameNotFoundException e) { - Slog.e(TAG, "Failed to get package metadata", e); + // Not all packages are installed, hence ignore those that are not installed yet. + Slog.v(TAG, "Failed to get package metadata"); } final String configString = DeviceConfig.getProperty( DeviceConfig.NAMESPACE_GAME_OVERLAY, packageName); @@ -531,9 +532,8 @@ public final class GameManagerService extends IGameManagerService.Stub { final ApplicationInfo applicationInfo = mPackageManager .getApplicationInfoAsUser(packageName, PackageManager.MATCH_ALL, userId); if (applicationInfo.category != ApplicationInfo.CATEGORY_GAME) { - Slog.e(TAG, "Ignoring attempt to get the Game Mode for '" + packageName - + "' which is not categorized as a game: applicationInfo.flags = " - + applicationInfo.flags + ", category = " + applicationInfo.category); + // The game mode for applications that are not identified as game is always + // UNSUPPORTED. See {@link PackageManager#setApplicationCategoryHint(String, int)} return GameManager.GAME_MODE_UNSUPPORTED; } } catch (PackageManager.NameNotFoundException e) { @@ -571,9 +571,8 @@ public final class GameManagerService extends IGameManagerService.Stub { final ApplicationInfo applicationInfo = mPackageManager .getApplicationInfoAsUser(packageName, PackageManager.MATCH_ALL, userId); if (applicationInfo.category != ApplicationInfo.CATEGORY_GAME) { - Slog.e(TAG, "Ignoring attempt to set the Game Mode for '" + packageName - + "' which is not categorized as a game: applicationInfo.flags = " - + applicationInfo.flags + ", category = " + applicationInfo.category); + // Ignore attempt to set the game mode for applications that are not identified + // as game. See {@link PackageManager#setApplicationCategoryHint(String, int)} return; } } catch (PackageManager.NameNotFoundException e) { diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index 541dcdc94a51..fdb3d8ca371c 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -84,6 +84,7 @@ import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.AppGlobals; import android.app.AppOpsManager; +import android.app.AppOpsManager.AttributionFlags; import android.app.AppOpsManager.AttributedOpEntry; import android.app.AppOpsManager.HistoricalOps; import android.app.AppOpsManager.Mode; @@ -200,6 +201,7 @@ import java.util.Map; import java.util.Objects; import java.util.Scanner; import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; public class AppOpsService extends IAppOpsService.Stub { @@ -257,11 +259,6 @@ public class AppOpsService extends IAppOpsService.Stub { private static final int MAX_UNUSED_POOLED_OBJECTS = 3; private static final int RARELY_USED_PACKAGES_INITIALIZATION_DELAY_MILLIS = 300000; - //TODO: remove this when development is done. - private static final int DEBUG_FGS_ALLOW_WHILE_IN_USE = 0; - private static final int DEBUG_FGS_ENFORCE_TYPE = 1; - - final Context mContext; final AtomicFile mFile; private final @Nullable File mNoteOpCallerStacktracesFile; @@ -414,9 +411,10 @@ public class AppOpsService extends IAppOpsService.Stub { } InProgressStartOpEvent acquire(long startTime, long elapsedTime, @NonNull IBinder clientId, - @NonNull Runnable onDeath, int proxyUid, @Nullable String proxyPackageName, - @Nullable String proxyAttributionTag, @AppOpsManager.UidState int uidState, - @OpFlags int flags) throws RemoteException { + @Nullable String attributionTag, @NonNull Runnable onDeath, int proxyUid, + @Nullable String proxyPackageName, @Nullable String proxyAttributionTag, + @AppOpsManager.UidState int uidState, @OpFlags int flags, @AttributionFlags + int attributionFlags, int attributionChainId) throws RemoteException { InProgressStartOpEvent recycled = acquire(); @@ -427,13 +425,14 @@ public class AppOpsService extends IAppOpsService.Stub { } if (recycled != null) { - recycled.reinit(startTime, elapsedTime, clientId, onDeath, uidState, flags, - proxyInfo, mOpEventProxyInfoPool); + recycled.reinit(startTime, elapsedTime, clientId, attributionTag, onDeath, + uidState, flags, proxyInfo, attributionFlags, attributionChainId, + mOpEventProxyInfoPool); return recycled; } - return new InProgressStartOpEvent(startTime, elapsedTime, clientId, onDeath, uidState, - proxyInfo, flags); + return new InProgressStartOpEvent(startTime, elapsedTime, clientId, attributionTag, + onDeath, uidState, proxyInfo, flags, attributionFlags, attributionChainId); } } @@ -685,6 +684,9 @@ public class AppOpsService extends IAppOpsService.Stub { /** Id of the client that started the event */ private @NonNull IBinder mClientId; + /** The attribution tag for this operation */ + private @Nullable String mAttributionTag; + /** To call when client dies */ private @NonNull Runnable mOnDeath; @@ -700,30 +702,44 @@ public class AppOpsService extends IAppOpsService.Stub { /** How many times the op was started but not finished yet */ int numUnfinishedStarts; + /** The attribution flags related to this event */ + private @AttributionFlags int mAttributionFlags; + + /** The id of the attribution chain this even is a part of */ + private int mAttributionChainId; + /** * Create a new {@link InProgressStartOpEvent}. * * @param startTime The time {@link #startOperation} was called * @param startElapsedTime The elapsed time when {@link #startOperation} was called * @param clientId The client id of the caller of {@link #startOperation} + * @param attributionTag The attribution tag for the operation. * @param onDeath The code to execute on client death * @param uidState The uidstate of the app {@link #startOperation} was called for + * @param attributionFlags the attribution flags for this operation. + * @param attributionChainId the unique id of the attribution chain this op is a part of. * @param proxy The proxy information, if {@link #startProxyOperation} was called * @param flags The trusted/nontrusted/self flags. * * @throws RemoteException If the client is dying */ private InProgressStartOpEvent(long startTime, long startElapsedTime, - @NonNull IBinder clientId, @NonNull Runnable onDeath, - @AppOpsManager.UidState int uidState, @Nullable OpEventProxyInfo proxy, - @OpFlags int flags) throws RemoteException { + @NonNull IBinder clientId, @Nullable String attributionTag, + @NonNull Runnable onDeath, @AppOpsManager.UidState int uidState, + @Nullable OpEventProxyInfo proxy, @OpFlags int flags, + @AttributionFlags int attributionFlags, int attributionChainId) + throws RemoteException { mStartTime = startTime; mStartElapsedTime = startElapsedTime; mClientId = clientId; + mAttributionTag = attributionTag; mOnDeath = onDeath; mUidState = uidState; mProxy = proxy; mFlags = flags; + mAttributionFlags = attributionFlags; + mAttributionChainId = attributionChainId; clientId.linkToDeath(this, 0); } @@ -744,21 +760,27 @@ public class AppOpsService extends IAppOpsService.Stub { * @param startTime The time {@link #startOperation} was called * @param startElapsedTime The elapsed time when {@link #startOperation} was called * @param clientId The client id of the caller of {@link #startOperation} + * @param attributionTag The attribution tag for this operation. * @param onDeath The code to execute on client death * @param uidState The uidstate of the app {@link #startOperation} was called for * @param flags The flags relating to the proxy * @param proxy The proxy information, if {@link #startProxyOperation} was called + * @param attributionFlags the attribution flags for this operation. + * @param attributionChainId the unique id of the attribution chain this op is a part of. * @param proxyPool The pool to release previous {@link OpEventProxyInfo} to * * @throws RemoteException If the client is dying */ public void reinit(long startTime, long startElapsedTime, @NonNull IBinder clientId, - @NonNull Runnable onDeath, @AppOpsManager.UidState int uidState, @OpFlags int flags, - @Nullable OpEventProxyInfo proxy, @NonNull Pools.Pool<OpEventProxyInfo> proxyPool + @Nullable String attributionTag, @NonNull Runnable onDeath, + @AppOpsManager.UidState int uidState, @OpFlags int flags, + @Nullable OpEventProxyInfo proxy, @AttributionFlags int attributionFlags, + int attributionChainId, @NonNull Pools.Pool<OpEventProxyInfo> proxyPool ) throws RemoteException { mStartTime = startTime; mStartElapsedTime = startElapsedTime; mClientId = clientId; + mAttributionTag = attributionTag; mOnDeath = onDeath; mUidState = uidState; mFlags = flags; @@ -767,6 +789,8 @@ public class AppOpsService extends IAppOpsService.Stub { proxyPool.release(mProxy); } mProxy = proxy; + mAttributionFlags = attributionFlags; + mAttributionChainId = attributionChainId; clientId.linkToDeath(this, 0); } @@ -791,7 +815,7 @@ public class AppOpsService extends IAppOpsService.Stub { return mUidState; } - /** @return proxy info for the access */ + /** @return proxy tag for the access */ public @Nullable OpEventProxyInfo getProxy() { return mProxy; } @@ -800,6 +824,16 @@ public class AppOpsService extends IAppOpsService.Stub { public @OpFlags int getFlags() { return mFlags; } + + /** @return attributoin flags used for the access */ + public @AttributionFlags int getAttributionFlags() { + return mAttributionFlags; + } + + /** @return attributoin chiang id for the access */ + public int getAttributionChainId() { + return mAttributionChainId; + } } private final class AttributedOp { @@ -943,32 +977,38 @@ public class AppOpsService extends IAppOpsService.Stub { * @param proxyAttributionTag The attribution tag of the proxy app * @param uidState UID state of the app startOp is called for * @param flags The proxy flags + * @param attributionFlags The attribution flags associated with this operation. + * @param attributionChainId The if of the attribution chain this operations is a part of. */ public void started(@NonNull IBinder clientId, int proxyUid, @Nullable String proxyPackageName, @Nullable String proxyAttributionTag, - @AppOpsManager.UidState int uidState, @OpFlags int flags) throws RemoteException { - started(clientId, proxyUid, proxyPackageName, proxyAttributionTag, uidState, flags, - true); + @AppOpsManager.UidState int uidState, @OpFlags int flags, @AttributionFlags + int attributionFlags, int attributionChainId) throws RemoteException { + started(clientId, proxyUid, proxyPackageName, proxyAttributionTag, + uidState, flags,/*triggerCallbackIfNeeded*/ true, attributionFlags, + attributionChainId); } private void started(@NonNull IBinder clientId, int proxyUid, @Nullable String proxyPackageName, @Nullable String proxyAttributionTag, @AppOpsManager.UidState int uidState, @OpFlags int flags, - boolean triggerCallbackIfNeeded) throws RemoteException { - startedOrPaused(clientId, proxyUid, proxyPackageName, proxyAttributionTag, - uidState, flags, triggerCallbackIfNeeded, true); + boolean triggerCallbackIfNeeded, @AttributionFlags int attributionFlags, + int attributionChainId) throws RemoteException { + startedOrPaused(clientId, proxyUid, proxyPackageName, + proxyAttributionTag, uidState, flags, triggerCallbackIfNeeded, + /*triggerCallbackIfNeeded*/ true, attributionFlags, attributionChainId); } private void startedOrPaused(@NonNull IBinder clientId, int proxyUid, @Nullable String proxyPackageName, @Nullable String proxyAttributionTag, @AppOpsManager.UidState int uidState, @OpFlags int flags, - boolean triggerCallbackIfNeeded, boolean isStarted) throws RemoteException { + boolean triggerCallbackIfNeeded, boolean isStarted, @AttributionFlags + int attributionFlags, int attributionChainId) throws RemoteException { if (triggerCallbackIfNeeded && !parent.isRunning() && isStarted) { - scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid, - parent.packageName, true); + scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid, parent.packageName, + tag, true, attributionFlags, attributionChainId); } - if (isStarted && mInProgressEvents == null) { mInProgressEvents = new ArrayMap<>(1); } else if (mPausedInProgressEvents == null) { @@ -981,9 +1021,10 @@ public class AppOpsService extends IAppOpsService.Stub { InProgressStartOpEvent event = events.get(clientId); if (event == null) { event = mInProgressStartOpEventPool.acquire(startTime, - SystemClock.elapsedRealtime(), clientId, + SystemClock.elapsedRealtime(), clientId, tag, PooledLambda.obtainRunnable(AppOpsService::onClientDeath, this, clientId), - proxyUid, proxyPackageName, proxyAttributionTag, uidState, flags); + proxyUid, proxyPackageName, proxyAttributionTag, uidState, flags, + attributionFlags, attributionChainId); events.put(clientId, event); } else { if (uidState != event.mUidState) { @@ -994,10 +1035,10 @@ public class AppOpsService extends IAppOpsService.Stub { event.numUnfinishedStarts++; if (isStarted) { + // TODO: Consider storing the attribution chain flags and id mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid, parent.packageName, tag, uidState, flags, startTime); } - } /** @@ -1063,7 +1104,8 @@ public class AppOpsService extends IAppOpsService.Stub { // TODO ntmyren: Also callback for single attribution tag activity changes if (triggerCallbackIfNeeded && !parent.isRunning()) { scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid, - parent.packageName, false); + parent.packageName, tag, false, event.getAttributionFlags(), + event.getAttributionChainId()); } } } @@ -1103,9 +1145,10 @@ public class AppOpsService extends IAppOpsService.Stub { */ public void createPaused(@NonNull IBinder clientId, int proxyUid, @Nullable String proxyPackageName, @Nullable String proxyAttributionTag, - @AppOpsManager.UidState int uidState, @OpFlags int flags) throws RemoteException { + @AppOpsManager.UidState int uidState, @OpFlags int flags, @AttributionFlags + int attributionFlags, int attributionChainId) throws RemoteException { startedOrPaused(clientId, proxyUid, proxyPackageName, proxyAttributionTag, - uidState, flags, true, false); + uidState, flags, true, false, attributionFlags, attributionChainId); } /** @@ -1124,9 +1167,11 @@ public class AppOpsService extends IAppOpsService.Stub { InProgressStartOpEvent event = mInProgressEvents.valueAt(i); mPausedInProgressEvents.put(event.mClientId, event); finishOrPause(event.mClientId, true, true); + + scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid, + parent.packageName, tag, false, + event.getAttributionFlags(), event.getAttributionChainId()); } - scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid, - parent.packageName, false); mInProgressEvents = null; } @@ -1153,10 +1198,10 @@ public class AppOpsService extends IAppOpsService.Stub { event.mStartTime = startTime; mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid, parent.packageName, tag, event.mUidState, event.mFlags, startTime); - } - if (shouldSendActive) { - scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid, - parent.packageName, true); + if (shouldSendActive) { + scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid, parent.packageName, + tag, true, event.getAttributionFlags(), event.getAttributionChainId()); + } } mPausedInProgressEvents = null; } @@ -1210,10 +1255,12 @@ public class AppOpsService extends IAppOpsService.Stub { // previously removed unfinished start counts back if (proxy != null) { started(event.getClientId(), proxy.getUid(), proxy.getPackageName(), - proxy.getAttributionTag(), newState, event.getFlags(), false); + proxy.getAttributionTag(), newState, event.getFlags(), false, + event.getAttributionFlags(), event.getAttributionChainId()); } else { started(event.getClientId(), Process.INVALID_UID, null, null, newState, - OP_FLAG_SELF, false); + OP_FLAG_SELF, false, event.getAttributionFlags(), + event.getAttributionChainId()); } InProgressStartOpEvent newEvent = mInProgressEvents.get(binders.get(i)); @@ -3321,9 +3368,10 @@ public class AppOpsService extends IAppOpsService.Stub { scheduleOpNotedIfNeededLocked(code, uid, packageName, attributionTag, flags, AppOpsManager.MODE_IGNORED); if (DEBUG) Slog.d(TAG, "noteOperation: no op for code " + code + " uid " + uid - + " package " + packageName); + + " package " + packageName + "flags: " + + AppOpsManager.flagsToString(flags)); return new SyncNotedAppOp(AppOpsManager.MODE_ERRORED, code, attributionTag, - packageName); + packageName + " flags: " + AppOpsManager.flagsToString(flags)); } final Op op = getOpLocked(ops, code, uid, true); final AttributedOp attributedOp = op.getOrCreateAttribution(op, attributionTag); @@ -3349,7 +3397,7 @@ public class AppOpsService extends IAppOpsService.Stub { if (uidMode != AppOpsManager.MODE_ALLOWED) { if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code " + switchCode + " (" + code + ") uid " + uid + " package " - + packageName); + + packageName + " flags: " + AppOpsManager.flagsToString(flags)); attributedOp.rejected(uidState.state, flags); scheduleOpNotedIfNeededLocked(code, uid, packageName, attributionTag, flags, uidMode); @@ -3362,7 +3410,7 @@ public class AppOpsService extends IAppOpsService.Stub { if (mode != AppOpsManager.MODE_ALLOWED) { if (DEBUG) Slog.d(TAG, "noteOperation: reject #" + mode + " for code " + switchCode + " (" + code + ") uid " + uid + " package " - + packageName); + + packageName + " flags: " + AppOpsManager.flagsToString(flags)); attributedOp.rejected(uidState.state, flags); scheduleOpNotedIfNeededLocked(code, uid, packageName, attributionTag, flags, mode); @@ -3373,7 +3421,8 @@ public class AppOpsService extends IAppOpsService.Stub { Slog.d(TAG, "noteOperation: allowing code " + code + " uid " + uid + " package " + packageName + (attributionTag == null ? "" - : "." + attributionTag)); + : "." + attributionTag) + " flags: " + + AppOpsManager.flagsToString(flags)); } scheduleOpNotedIfNeededLocked(code, uid, packageName, attributionTag, flags, AppOpsManager.MODE_ALLOWED); @@ -3674,16 +3723,18 @@ public class AppOpsService extends IAppOpsService.Stub { public SyncNotedAppOp startOperation(IBinder token, int code, int uid, @Nullable String packageName, @Nullable String attributionTag, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, - String message, boolean shouldCollectMessage) { + String message, boolean shouldCollectMessage, @AttributionFlags int attributionFlags, + int attributionChainId) { return mCheckOpsDelegateDispatcher.startOperation(token, code, uid, packageName, attributionTag, startIfModeDefault, shouldCollectAsyncNotedOp, message, - shouldCollectMessage); + shouldCollectMessage, attributionFlags, attributionChainId); } private SyncNotedAppOp startOperationImpl(@NonNull IBinder clientId, int code, int uid, @Nullable String packageName, @Nullable String attributionTag, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, @NonNull String message, - boolean shouldCollectMessage) { + boolean shouldCollectMessage, @AttributionFlags int attributionFlags, + int attributionChainId) { verifyIncomingUid(uid); verifyIncomingOp(code); verifyIncomingPackage(packageName, UserHandle.getUserId(uid)); @@ -3707,29 +3758,36 @@ public class AppOpsService extends IAppOpsService.Stub { } return startOperationUnchecked(clientId, code, uid, packageName, attributionTag, Process.INVALID_UID, null, null, OP_FLAG_SELF, startIfModeDefault, - shouldCollectAsyncNotedOp, message, shouldCollectMessage, false); + shouldCollectAsyncNotedOp, message, shouldCollectMessage, attributionFlags, + attributionChainId, /*dryRun*/ false); } @Override - public SyncNotedAppOp startProxyOperation(IBinder clientId, int code, + public SyncNotedAppOp startProxyOperation(int code, @NonNull AttributionSource attributionSource, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage, - boolean skipProxyOperation) { - return mCheckOpsDelegateDispatcher.startProxyOperation(clientId, code, attributionSource, + boolean skipProxyOperation, @AttributionFlags int proxyAttributionFlags, + @AttributionFlags int proxiedAttributionFlags, int attributionChainId) { + return mCheckOpsDelegateDispatcher.startProxyOperation(code, attributionSource, startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage, - skipProxyOperation); + skipProxyOperation, proxyAttributionFlags, proxiedAttributionFlags, + attributionChainId); } - private SyncNotedAppOp startProxyOperationImpl(IBinder clientId, int code, + private SyncNotedAppOp startProxyOperationImpl(int code, @NonNull AttributionSource attributionSource, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, String message, - boolean shouldCollectMessage, boolean skipProxyOperation) { + boolean shouldCollectMessage, boolean skipProxyOperation, @AttributionFlags + int proxyAttributionFlags, @AttributionFlags int proxiedAttributionFlags, + int attributionChainId) { final int proxyUid = attributionSource.getUid(); final String proxyPackageName = attributionSource.getPackageName(); final String proxyAttributionTag = attributionSource.getAttributionTag(); + final IBinder proxyToken = attributionSource.getToken(); final int proxiedUid = attributionSource.getNextUid(); final String proxiedPackageName = attributionSource.getNextPackageName(); final String proxiedAttributionTag = attributionSource.getNextAttributionTag(); + final IBinder proxiedToken = attributionSource.getNextToken(); verifyIncomingProxyUid(attributionSource); verifyIncomingOp(code); @@ -3762,10 +3820,11 @@ public class AppOpsService extends IAppOpsService.Stub { if (!skipProxyOperation) { // Test if the proxied operation will succeed before starting the proxy operation - final SyncNotedAppOp testProxiedOp = startOperationUnchecked(clientId, code, proxiedUid, - resolvedProxiedPackageName, proxiedAttributionTag, proxyUid, + final SyncNotedAppOp testProxiedOp = startOperationUnchecked(proxiedToken, code, + proxiedUid, resolvedProxiedPackageName, proxiedAttributionTag, proxyUid, resolvedProxyPackageName, proxyAttributionTag, proxiedFlags, startIfModeDefault, - shouldCollectAsyncNotedOp, message, shouldCollectMessage, true); + shouldCollectAsyncNotedOp, message, shouldCollectMessage, + proxiedAttributionFlags, attributionChainId, /*dryRun*/ true); if (!shouldStartForMode(testProxiedOp.getOpMode(), startIfModeDefault)) { return testProxiedOp; } @@ -3773,19 +3832,21 @@ public class AppOpsService extends IAppOpsService.Stub { final int proxyFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXY : AppOpsManager.OP_FLAG_UNTRUSTED_PROXY; - final SyncNotedAppOp proxyAppOp = startOperationUnchecked(clientId, code, proxyUid, + final SyncNotedAppOp proxyAppOp = startOperationUnchecked(proxyToken, code, proxyUid, resolvedProxyPackageName, proxyAttributionTag, Process.INVALID_UID, null, null, proxyFlags, startIfModeDefault, !isProxyTrusted, "proxy " + message, - shouldCollectMessage, false); + shouldCollectMessage, proxyAttributionFlags, attributionChainId, + /*dryRun*/ false); if (!shouldStartForMode(proxyAppOp.getOpMode(), startIfModeDefault)) { return proxyAppOp; } } - return startOperationUnchecked(clientId, code, proxiedUid, resolvedProxiedPackageName, + return startOperationUnchecked(proxiedToken, code, proxiedUid, resolvedProxiedPackageName, proxiedAttributionTag, proxyUid, resolvedProxyPackageName, proxyAttributionTag, proxiedFlags, startIfModeDefault, shouldCollectAsyncNotedOp, message, - shouldCollectMessage, false); + shouldCollectMessage, proxiedAttributionFlags, attributionChainId, + /*dryRun*/ false); } private boolean shouldStartForMode(int mode, boolean startIfModeDefault) { @@ -3796,7 +3857,8 @@ public class AppOpsService extends IAppOpsService.Stub { @NonNull String packageName, @Nullable String attributionTag, int proxyUid, String proxyPackageName, @Nullable String proxyAttributionTag, @OpFlags int flags, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, @Nullable String message, - boolean shouldCollectMessage, boolean dryRun) { + boolean shouldCollectMessage, @AttributionFlags int attributionFlags, + int attributionChainId, boolean dryRun) { RestrictionBypass bypass; try { bypass = verifyAndGetBypass(uid, packageName, attributionTag, proxyPackageName); @@ -3818,7 +3880,8 @@ public class AppOpsService extends IAppOpsService.Stub { flags, AppOpsManager.MODE_IGNORED); } if (DEBUG) Slog.d(TAG, "startOperation: no op for code " + code + " uid " + uid - + " package " + packageName); + + " package " + packageName + " flags: " + + AppOpsManager.flagsToString(flags)); return new SyncNotedAppOp(AppOpsManager.MODE_ERRORED, code, attributionTag, packageName); } @@ -3835,7 +3898,7 @@ public class AppOpsService extends IAppOpsService.Stub { if (DEBUG) { Slog.d(TAG, "startOperation: uid reject #" + uidMode + " for code " + switchCode + " (" + code + ") uid " + uid + " package " - + packageName); + + packageName + " flags: " + AppOpsManager.flagsToString(flags)); } if (!dryRun) { attributedOp.rejected(uidState.state, flags); @@ -3852,7 +3915,7 @@ public class AppOpsService extends IAppOpsService.Stub { && (!startIfModeDefault || mode != MODE_DEFAULT)) { if (DEBUG) Slog.d(TAG, "startOperation: reject #" + mode + " for code " + switchCode + " (" + code + ") uid " + uid + " package " - + packageName); + + packageName + " flags: " + AppOpsManager.flagsToString(flags)); if (!dryRun) { attributedOp.rejected(uidState.state, flags); scheduleOpStartedIfNeededLocked(code, uid, packageName, attributionTag, @@ -3862,15 +3925,18 @@ public class AppOpsService extends IAppOpsService.Stub { } } if (DEBUG) Slog.d(TAG, "startOperation: allowing code " + code + " uid " + uid - + " package " + packageName + " restricted: " + isRestricted); + + " package " + packageName + " restricted: " + isRestricted + + " flags: " + AppOpsManager.flagsToString(flags)); if (!dryRun) { try { if (isRestricted) { attributedOp.createPaused(clientId, proxyUid, proxyPackageName, - proxyAttributionTag, uidState.state, flags); + proxyAttributionTag, uidState.state, flags, attributionFlags, + attributionChainId); } else { attributedOp.started(clientId, proxyUid, proxyPackageName, - proxyAttributionTag, uidState.state, flags); + proxyAttributionTag, uidState.state, flags, attributionFlags, + attributionChainId); } } catch (RemoteException e) { throw new RuntimeException(e); @@ -3905,21 +3971,26 @@ public class AppOpsService extends IAppOpsService.Stub { } @Override - public void finishProxyOperation(IBinder clientId, int code, - @NonNull AttributionSource attributionSource) { - mCheckOpsDelegateDispatcher.finishProxyOperation(clientId, code, attributionSource); + public void finishProxyOperation(int code, @NonNull AttributionSource attributionSource, + boolean skipProxyOperation) { + mCheckOpsDelegateDispatcher.finishProxyOperation(code, attributionSource, + skipProxyOperation); } - private Void finishProxyOperationImpl(IBinder clientId, int code, - @NonNull AttributionSource attributionSource) { + private Void finishProxyOperationImpl(int code, @NonNull AttributionSource attributionSource, + boolean skipProxyOperation) { final int proxyUid = attributionSource.getUid(); final String proxyPackageName = attributionSource.getPackageName(); final String proxyAttributionTag = attributionSource.getAttributionTag(); + final IBinder proxyToken = attributionSource.getToken(); final int proxiedUid = attributionSource.getNextUid(); final String proxiedPackageName = attributionSource.getNextPackageName(); final String proxiedAttributionTag = attributionSource.getNextAttributionTag(); + final IBinder proxiedToken = attributionSource.getNextToken(); - verifyIncomingUid(proxyUid); + skipProxyOperation = resolveSkipProxyOperation(skipProxyOperation, attributionSource); + + verifyIncomingProxyUid(attributionSource); verifyIncomingOp(code); verifyIncomingPackage(proxyPackageName, UserHandle.getUserId(proxyUid)); verifyIncomingPackage(proxiedPackageName, UserHandle.getUserId(proxiedUid)); @@ -3930,8 +4001,10 @@ public class AppOpsService extends IAppOpsService.Stub { return null; } - finishOperationUnchecked(clientId, code, proxyUid, resolvedProxyPackageName, - proxyAttributionTag); + if (!skipProxyOperation) { + finishOperationUnchecked(proxyToken, code, proxyUid, resolvedProxyPackageName, + proxyAttributionTag); + } String resolvedProxiedPackageName = AppOpsManager.resolvePackageName(proxiedUid, proxiedPackageName); @@ -3939,7 +4012,7 @@ public class AppOpsService extends IAppOpsService.Stub { return null; } - finishOperationUnchecked(clientId, code, proxiedUid, resolvedProxiedPackageName, + finishOperationUnchecked(proxiedToken, code, proxiedUid, resolvedProxiedPackageName, proxiedAttributionTag); return null; @@ -3981,8 +4054,9 @@ public class AppOpsService extends IAppOpsService.Stub { } } - private void scheduleOpActiveChangedIfNeededLocked(int code, int uid, String packageName, - boolean active) { + private void scheduleOpActiveChangedIfNeededLocked(int code, int uid, @NonNull + String packageName, @Nullable String attributionTag, boolean active, @AttributionFlags + int attributionFlags, int attributionChainId) { ArraySet<ActiveCallback> dispatchedCallbacks = null; final int callbackListCount = mActiveWatchers.size(); for (int i = 0; i < callbackListCount; i++) { @@ -4003,11 +4077,13 @@ public class AppOpsService extends IAppOpsService.Stub { } mHandler.sendMessage(PooledLambda.obtainMessage( AppOpsService::notifyOpActiveChanged, - this, dispatchedCallbacks, code, uid, packageName, active)); + this, dispatchedCallbacks, code, uid, packageName, attributionTag, active, + attributionFlags, attributionChainId)); } private void notifyOpActiveChanged(ArraySet<ActiveCallback> callbacks, - int code, int uid, String packageName, boolean active) { + int code, int uid, @NonNull String packageName, @Nullable String attributionTag, + boolean active, @AttributionFlags int attributionFlags, int attributionChainId) { // There are features watching for mode changes such as window manager // and location manager which are in our process. The callbacks in these // features may require permissions our remote caller does not have. @@ -4017,7 +4093,8 @@ public class AppOpsService extends IAppOpsService.Stub { for (int i = 0; i < callbackCount; i++) { final ActiveCallback callback = callbacks.valueAt(i); try { - callback.mCallback.opActiveChanged(code, uid, packageName, active); + callback.mCallback.opActiveChanged(code, uid, packageName, attributionTag, + active, attributionFlags, attributionChainId); } catch (RemoteException e) { /* do nothing */ } @@ -5023,6 +5100,8 @@ public class AppOpsService extends IAppOpsService.Stub { } static class Shell extends ShellCommand { + static final AtomicInteger sAttributionChainIds = new AtomicInteger(0); + final IAppOpsService mInterface; final AppOpsService mInternal; @@ -5491,7 +5570,9 @@ public class AppOpsService extends IAppOpsService.Stub { if (shell.packageName != null) { shell.mInterface.startOperation(shell.mToken, shell.op, shell.packageUid, shell.packageName, shell.attributionTag, true, true, - "appops start shell command", true); + "appops start shell command", true, + AppOpsManager.ATTRIBUTION_FLAG_ACCESSOR, + shell.sAttributionChainIds.incrementAndGet()); } else { return -1; } @@ -6421,7 +6502,9 @@ public class AppOpsService extends IAppOpsService.Stub { @NonNull String proxiedPackageName) { Objects.requireNonNull(proxyPackageName); Objects.requireNonNull(proxiedPackageName); - Binder.withCleanCallingIdentity(() -> { + final long callingUid = Binder.getCallingUid(); + final long identity = Binder.clearCallingIdentity(); + try { final List<AppOpsManager.PackageOps> packageOps = getOpsForPackage(proxiedUid, proxiedPackageName, new int[] {op}); if (packageOps == null || packageOps.isEmpty()) { @@ -6436,13 +6519,13 @@ public class AppOpsService extends IAppOpsService.Stub { return false; } final OpEventProxyInfo proxyInfo = opEntry.getLastProxyInfo( - AppOpsManager.OP_FLAG_TRUSTED_PROXY - | AppOpsManager.OP_FLAG_UNTRUSTED_PROXY); - return proxyInfo != null && Binder.getCallingUid() == proxyInfo.getUid() + OP_FLAG_TRUSTED_PROXIED | AppOpsManager.OP_FLAG_UNTRUSTED_PROXIED); + return proxyInfo != null && callingUid == proxyInfo.getUid() && proxyPackageName.equals(proxyInfo.getPackageName()) && Objects.equals(proxyAttributionTag, proxyInfo.getAttributionTag()); - }); - return false; + } finally { + Binder.restoreCallingIdentity(identity); + } } @Override @@ -7275,89 +7358,101 @@ public class AppOpsService extends IAppOpsService.Stub { public SyncNotedAppOp startOperation(IBinder token, int code, int uid, @Nullable String packageName, @NonNull String attributionTag, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, - @Nullable String message, boolean shouldCollectMessage) { + @Nullable String message, boolean shouldCollectMessage, + @AttributionFlags int attributionFlags, int attributionChainId) { if (mPolicy != null) { if (mCheckOpsDelegate != null) { return mPolicy.startOperation(token, code, uid, packageName, attributionTag, startIfModeDefault, shouldCollectAsyncNotedOp, message, - shouldCollectMessage, this::startDelegateOperationImpl); + shouldCollectMessage, attributionFlags, attributionChainId, + this::startDelegateOperationImpl); } else { return mPolicy.startOperation(token, code, uid, packageName, attributionTag, startIfModeDefault, shouldCollectAsyncNotedOp, message, - shouldCollectMessage, AppOpsService.this::startOperationImpl); + shouldCollectMessage, attributionFlags, attributionChainId, + AppOpsService.this::startOperationImpl); } } else if (mCheckOpsDelegate != null) { return startDelegateOperationImpl(token, code, uid, packageName, attributionTag, startIfModeDefault, shouldCollectAsyncNotedOp, message, - shouldCollectMessage); + shouldCollectMessage, attributionFlags, attributionChainId); } return startOperationImpl(token, code, uid, packageName, attributionTag, - startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage); + startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage, + attributionFlags, attributionChainId); } private SyncNotedAppOp startDelegateOperationImpl(IBinder token, int code, int uid, @Nullable String packageName, @Nullable String attributionTag, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, String message, - boolean shouldCollectMessage) { + boolean shouldCollectMessage, @AttributionFlags int attributionFlags, + int attributionChainId) { return mCheckOpsDelegate.startOperation(token, code, uid, packageName, attributionTag, startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage, - AppOpsService.this::startOperationImpl); + attributionFlags, attributionChainId, AppOpsService.this::startOperationImpl); } - public SyncNotedAppOp startProxyOperation(IBinder clientId, int code, + public SyncNotedAppOp startProxyOperation(int code, @NonNull AttributionSource attributionSource, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage, - boolean skipProxyOperation) { + boolean skipProxyOperation, @AttributionFlags int proxyAttributionFlags, + @AttributionFlags int proxiedAttributionFlags, int attributionChainId) { if (mPolicy != null) { if (mCheckOpsDelegate != null) { - return mPolicy.startProxyOperation(clientId, code, attributionSource, + return mPolicy.startProxyOperation(code, attributionSource, startIfModeDefault, shouldCollectAsyncNotedOp, message, - shouldCollectMessage, skipProxyOperation, + shouldCollectMessage, skipProxyOperation, proxyAttributionFlags, + proxiedAttributionFlags, attributionChainId, this::startDelegateProxyOperationImpl); } else { - return mPolicy.startProxyOperation(clientId, code, attributionSource, + return mPolicy.startProxyOperation(code, attributionSource, startIfModeDefault, shouldCollectAsyncNotedOp, message, - shouldCollectMessage, skipProxyOperation, + shouldCollectMessage, skipProxyOperation, proxyAttributionFlags, + proxiedAttributionFlags, attributionChainId, AppOpsService.this::startProxyOperationImpl); } } else if (mCheckOpsDelegate != null) { - return startDelegateProxyOperationImpl(clientId, code, - attributionSource, startIfModeDefault, shouldCollectAsyncNotedOp, message, - shouldCollectMessage, skipProxyOperation); + return startDelegateProxyOperationImpl(code, attributionSource, + startIfModeDefault, shouldCollectAsyncNotedOp, message, + shouldCollectMessage, skipProxyOperation, proxyAttributionFlags, + proxiedAttributionFlags, attributionChainId); } - return startProxyOperationImpl(clientId, code, attributionSource, startIfModeDefault, - shouldCollectAsyncNotedOp, message, shouldCollectMessage, skipProxyOperation); + return startProxyOperationImpl(code, attributionSource, startIfModeDefault, + shouldCollectAsyncNotedOp, message, shouldCollectMessage, skipProxyOperation, + proxyAttributionFlags, proxiedAttributionFlags, attributionChainId); } - - private SyncNotedAppOp startDelegateProxyOperationImpl(IBinder token, int code, + private SyncNotedAppOp startDelegateProxyOperationImpl(int code, @NonNull AttributionSource attributionSource, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage, - boolean skipProxyOperation) { - return mCheckOpsDelegate.startProxyOperation(token, code, attributionSource, + boolean skipProxyOperation, @AttributionFlags int proxyAttributionFlags, + @AttributionFlags int proxiedAttributionFlsgs, int attributionChainId) { + return mCheckOpsDelegate.startProxyOperation(code, attributionSource, startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage, - skipProxyOperation, AppOpsService.this::startProxyOperationImpl); + skipProxyOperation, proxyAttributionFlags, proxiedAttributionFlsgs, + attributionChainId, AppOpsService.this::startProxyOperationImpl); } - public void finishProxyOperation(IBinder clientId, int code, - @NonNull AttributionSource attributionSource) { + public void finishProxyOperation(int code, + @NonNull AttributionSource attributionSource, boolean skipProxyOperation) { if (mPolicy != null) { if (mCheckOpsDelegate != null) { - mPolicy.finishProxyOperation(clientId, code, attributionSource, - this::finishDelegateProxyOperationImpl); + mPolicy.finishProxyOperation(code, attributionSource, + skipProxyOperation, this::finishDelegateProxyOperationImpl); } else { - mPolicy.finishProxyOperation(clientId, code, attributionSource, - AppOpsService.this::finishProxyOperationImpl); + mPolicy.finishProxyOperation(code, attributionSource, + skipProxyOperation, AppOpsService.this::finishProxyOperationImpl); } } else if (mCheckOpsDelegate != null) { - finishDelegateProxyOperationImpl(clientId, code, attributionSource); + finishDelegateProxyOperationImpl(code, attributionSource, skipProxyOperation); + } else { + finishProxyOperationImpl(code, attributionSource, skipProxyOperation); } - finishProxyOperationImpl(clientId, code, attributionSource); } - private Void finishDelegateProxyOperationImpl(IBinder clientId, int code, - @NonNull AttributionSource attributionSource) { - mCheckOpsDelegate.finishProxyOperation(clientId, code, attributionSource, + private Void finishDelegateProxyOperationImpl(int code, + @NonNull AttributionSource attributionSource, boolean skipProxyOperation) { + mCheckOpsDelegate.finishProxyOperation(code, attributionSource, skipProxyOperation, AppOpsService.this::finishProxyOperationImpl); return null; } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/UdfpsHelper.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/UdfpsHelper.java index f0e45978c365..879c8a0317d7 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/UdfpsHelper.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/UdfpsHelper.java @@ -113,6 +113,19 @@ public class UdfpsHelper { } } + public static void onAcquiredGood(int sensorId, + @Nullable IUdfpsOverlayController udfpsOverlayController) { + if (udfpsOverlayController == null) { + return; + } + + try { + udfpsOverlayController.onAcquiredGood(sensorId); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception when sending onAcquiredGood", e); + } + } + public static void onEnrollmentProgress(int sensorId, int remaining, @Nullable IUdfpsOverlayController udfpsOverlayController) { if (udfpsOverlayController == null) { diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java index 45842677609c..a5326b352264 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java @@ -22,6 +22,7 @@ import android.app.TaskStackListener; import android.content.Context; import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricFingerprintConstants; +import android.hardware.biometrics.BiometricFingerprintConstants.FingerprintAcquired; import android.hardware.biometrics.BiometricsProtoEnums; import android.hardware.biometrics.common.ICancellationSignal; import android.hardware.biometrics.fingerprint.ISession; @@ -81,6 +82,17 @@ class FingerprintAuthenticationClient extends AuthenticationClient<ISession> imp } @Override + public void onAcquired(@FingerprintAcquired int acquiredInfo, int vendorCode) { + // For UDFPS, notify SysUI that the illumination can be turned off. + // See AcquiredInfo#GOOD and AcquiredInfo#RETRYING_CAPTURE + if (acquiredInfo == BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_GOOD) { + UdfpsHelper.onAcquiredGood(getSensorId(), mUdfpsOverlayController); + } + + super.onAcquired(acquiredInfo, vendorCode); + } + + @Override public void onError(int errorCode, int vendorCode) { super.onError(errorCode, vendorCode); diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java index ed886fe166e0..125cfd2e134d 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java @@ -21,6 +21,7 @@ import android.annotation.Nullable; import android.content.Context; import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricFingerprintConstants; +import android.hardware.biometrics.BiometricFingerprintConstants.FingerprintAcquired; import android.hardware.biometrics.BiometricsProtoEnums; import android.hardware.biometrics.common.ICancellationSignal; import android.hardware.biometrics.fingerprint.ISession; @@ -85,14 +86,19 @@ class FingerprintEnrollClient extends EnrollClient<ISession> implements Udfps { } } - @Override - public void onAcquired(int acquiredInfo, int vendorCode) { - super.onAcquired(acquiredInfo, vendorCode); + public void onAcquired(@FingerprintAcquired int acquiredInfo, int vendorCode) { + // For UDFPS, notify SysUI that the illumination can be turned off. + // See AcquiredInfo#GOOD and AcquiredInfo#RETRYING_CAPTURE + if (acquiredInfo == BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_GOOD) { + UdfpsHelper.onAcquiredGood(getSensorId(), mUdfpsOverlayController); + } if (UdfpsHelper.isValidAcquisitionMessage(getContext(), acquiredInfo, vendorCode)) { UdfpsHelper.onEnrollmentHelp(getSensorId(), mUdfpsOverlayController); } + + super.onAcquired(acquiredInfo, vendorCode); } @Override diff --git a/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java b/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java index a34d7226136a..70a222fb09c5 100644 --- a/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java +++ b/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java @@ -35,17 +35,17 @@ public class SystemEmergencyHelper extends EmergencyHelper { private final Context mContext; - private TelephonyManager mTelephonyManager; + TelephonyManager mTelephonyManager; - private boolean mIsInEmergencyCall; - private long mEmergencyCallEndRealtimeMs = Long.MIN_VALUE; + boolean mIsInEmergencyCall; + long mEmergencyCallEndRealtimeMs = Long.MIN_VALUE; public SystemEmergencyHelper(Context context) { mContext = context; } /** Called when system is ready. */ - public void onSystemReady() { + public synchronized void onSystemReady() { if (mTelephonyManager != null) { return; } @@ -64,14 +64,20 @@ public class SystemEmergencyHelper extends EmergencyHelper { return; } - mIsInEmergencyCall = mTelephonyManager.isEmergencyNumber( - intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER)); + synchronized (SystemEmergencyHelper.this) { + mIsInEmergencyCall = mTelephonyManager.isEmergencyNumber( + intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER)); + } } }, new IntentFilter(Intent.ACTION_NEW_OUTGOING_CALL)); } @Override - public boolean isInEmergency(long extensionTimeMs) { + public synchronized boolean isInEmergency(long extensionTimeMs) { + if (mTelephonyManager == null) { + return false; + } + boolean isInExtensionTime = mEmergencyCallEndRealtimeMs != Long.MIN_VALUE && (SystemClock.elapsedRealtime() - mEmergencyCallEndRealtimeMs) < extensionTimeMs; @@ -84,12 +90,16 @@ public class SystemEmergencyHelper extends EmergencyHelper { private class EmergencyCallTelephonyCallback extends TelephonyCallback implements TelephonyCallback.CallStateListener{ + EmergencyCallTelephonyCallback() {} + @Override public void onCallStateChanged(int state) { if (state == TelephonyManager.CALL_STATE_IDLE) { - if (mIsInEmergencyCall) { - mEmergencyCallEndRealtimeMs = SystemClock.elapsedRealtime(); - mIsInEmergencyCall = false; + synchronized (SystemEmergencyHelper.this) { + if (mIsInEmergencyCall) { + mEmergencyCallEndRealtimeMs = SystemClock.elapsedRealtime(); + mIsInEmergencyCall = false; + } } } } diff --git a/services/core/java/com/android/server/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java index 6d7f79250715..4f8b87b51294 100644 --- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java +++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java @@ -1527,16 +1527,16 @@ public class LocationProviderManager extends throw new IllegalArgumentException(mName + " provider is not a test provider"); } + String locationProvider = location.getProvider(); + if (!TextUtils.isEmpty(locationProvider) && !mName.equals(locationProvider)) { + // The location has an explicit provider that is different from the mock + // provider name. The caller may be trying to fool us via b/33091107. + EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(), + mName + "!=" + locationProvider); + } + final long identity = Binder.clearCallingIdentity(); try { - String locationProvider = location.getProvider(); - if (!TextUtils.isEmpty(locationProvider) && !mName.equals(locationProvider)) { - // The location has an explicit provider that is different from the mock - // provider name. The caller may be trying to fool us via b/33091107. - EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(), - mName + "!=" + locationProvider); - } - mProvider.setMockProviderLocation(location); } finally { Binder.restoreCallingIdentity(identity); diff --git a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java index c1209d466d20..62db886b90e9 100644 --- a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java +++ b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java @@ -154,7 +154,7 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { // must have the required permission and the users must be in the same profile group // in order to launch any of its own activities. if (callerUserId != userId) { - final int permissionFlag = PermissionChecker.checkPermissionForPreflight( + final int permissionFlag = PermissionChecker.checkPermissionForPreflight( mContext, INTERACT_ACROSS_PROFILES, callingPid, diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 2f8ba6da89a3..6a399bdbb010 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -341,6 +341,7 @@ import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.ResolverActivity; +import com.android.internal.content.F2fsUtils; import com.android.internal.content.NativeLibraryHelper; import com.android.internal.content.PackageHelper; import com.android.internal.content.om.OverlayConfig; @@ -896,6 +897,20 @@ public class PackageManagerService extends IPackageManager.Stub * Only non-null during an OTA, and even then it is nulled again once systemReady(). */ private @Nullable ArraySet<String> mExistingPackages = null; + + /** + * List of code paths that need to be released when the system becomes ready. + * <p> + * NOTE: We have to delay releasing cblocks for no other reason than we cannot + * retrieve the setting {@link Secure#RELEASE_COMPRESS_BLOCKS_ON_INSTALL}. When + * we no longer need to read that setting, cblock release can occur in the + * constructor. + * + * @see Secure#RELEASE_COMPRESS_BLOCKS_ON_INSTALL + * @see #systemReady() + */ + private @Nullable List<File> mReleaseOnSystemReady; + /** * Whether or not system app permissions should be promoted from install to runtime. */ @@ -1413,8 +1428,8 @@ public class PackageManagerService extends IPackageManager.Stub mStaticLibsByDeclaringPackage = new WatchedArrayMap<>(); private final SnapshotCache<WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>> mStaticLibsByDeclaringPackageSnapshot = - new SnapshotCache.Auto<>(mSharedLibraries, mSharedLibraries, - "PackageManagerService.mSharedLibraries"); + new SnapshotCache.Auto<>(mStaticLibsByDeclaringPackage, mStaticLibsByDeclaringPackage, + "PackageManagerService.mStaticLibsByDeclaringPackage"); // Mapping from instrumentation class names to info about them. @Watched @@ -7907,6 +7922,21 @@ public class PackageManagerService extends IPackageManager.Stub IoUtils.closeQuietly(handle); } } + if (ret == PackageManager.INSTALL_SUCCEEDED) { + // NOTE: During boot, we have to delay releasing cblocks for no other reason than + // we cannot retrieve the setting {@link Secure#RELEASE_COMPRESS_BLOCKS_ON_INSTALL}. + // When we no longer need to read that setting, cblock release can occur always + // occur here directly + if (!mSystemReady) { + if (mReleaseOnSystemReady == null) { + mReleaseOnSystemReady = new ArrayList<>(); + } + mReleaseOnSystemReady.add(dstCodePath); + } else { + final ContentResolver resolver = mContext.getContentResolver(); + F2fsUtils.releaseCompressedBlocks(resolver, dstCodePath); + } + } if (ret != PackageManager.INSTALL_SUCCEEDED) { if (!dstCodePath.exists()) { return null; @@ -13224,9 +13254,8 @@ public class PackageManagerService extends IPackageManager.Stub if (!sharedLibraryInfo.isStatic()) { continue; } - final PackageSetting staticLibPkgSetting = getPackageSetting( - toStaticSharedLibraryPackageName(sharedLibraryInfo.getName(), - sharedLibraryInfo.getLongVersion())); + final PackageSetting staticLibPkgSetting = + getPackageSetting(sharedLibraryInfo.getPackageName()); if (staticLibPkgSetting == null) { Slog.wtf(TAG, "Shared lib without setting: " + sharedLibraryInfo); continue; @@ -17778,6 +17807,10 @@ public class PackageManagerService extends IPackageManager.Stub if (mRet == PackageManager.INSTALL_SUCCEEDED) { mRet = args.copyApk(); } + if (mRet == PackageManager.INSTALL_SUCCEEDED) { + F2fsUtils.releaseCompressedBlocks( + mContext.getContentResolver(), new File(args.getCodePath())); + } if (mParentInstallParams != null) { mParentInstallParams.tryProcessInstallRequest(args, mRet); } else { @@ -17785,7 +17818,6 @@ public class PackageManagerService extends IPackageManager.Stub processInstallRequestsAsync( res.returnCode == PackageManager.INSTALL_SUCCEEDED, Collections.singletonList(new InstallRequest(args, res))); - } } } @@ -22726,7 +22758,8 @@ public class PackageManagerService extends IPackageManager.Stub */ public int getPreferredActivitiesInternal(List<WatchedIntentFilter> outFilters, List<ComponentName> outActivities, String packageName) { - if (getInstantAppPackageName(Binder.getCallingUid()) != null) { + final int callingUid = Binder.getCallingUid(); + if (getInstantAppPackageName(callingUid) != null) { return 0; } int num = 0; @@ -22738,9 +22771,13 @@ public class PackageManagerService extends IPackageManager.Stub final Iterator<PreferredActivity> it = pir.filterIterator(); while (it.hasNext()) { final PreferredActivity pa = it.next(); + final String prefPackageName = pa.mPref.mComponent.getPackageName(); if (packageName == null - || (pa.mPref.mComponent.getPackageName().equals(packageName) - && pa.mPref.mAlways)) { + || (prefPackageName.equals(packageName) && pa.mPref.mAlways)) { + if (shouldFilterApplicationLocked( + mSettings.getPackageLPr(prefPackageName), callingUid, userId)) { + continue; + } if (outFilters != null) { outFilters.add(new WatchedIntentFilter(pa.getIntentFilter())); } @@ -24120,8 +24157,15 @@ public class PackageManagerService extends IPackageManager.Stub public void systemReady() { enforceSystemOrRoot("Only the system can claim the system is ready"); - mSystemReady = true; final ContentResolver resolver = mContext.getContentResolver(); + if (mReleaseOnSystemReady != null) { + for (int i = mReleaseOnSystemReady.size() - 1; i >= 0; --i) { + final File dstCodePath = mReleaseOnSystemReady.get(i); + F2fsUtils.releaseCompressedBlocks(resolver, dstCodePath); + } + mReleaseOnSystemReady = null; + } + mSystemReady = true; ContentObserver co = new ContentObserver(mHandler) { @Override public void onChange(boolean selfChange) { diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index 1bfa72f64d8e..b0f8ee1925c5 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -20,6 +20,7 @@ import static android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY; import static android.Manifest.permission.READ_EXTERNAL_STORAGE; import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE; import static android.app.AppOpsManager.MODE_ALLOWED; +import static android.app.AppOpsManager.MODE_ERRORED; import static android.app.AppOpsManager.MODE_IGNORED; import static android.content.pm.ApplicationInfo.AUTO_REVOKE_DISALLOWED; import static android.content.pm.ApplicationInfo.AUTO_REVOKE_DISCOURAGED; @@ -65,6 +66,7 @@ import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.AppOpsManager; +import android.app.AppOpsManager.AttributionFlags; import android.app.IActivityManager; import android.app.admin.DevicePolicyManagerInternal; import android.compat.annotation.ChangeId; @@ -108,6 +110,7 @@ import android.os.storage.StorageManager; import android.permission.IOnPermissionsChangeListener; import android.permission.IPermissionChecker; import android.permission.IPermissionManager; +import android.permission.PermissionCheckerManager; import android.permission.PermissionControllerManager; import android.permission.PermissionManager; import android.permission.PermissionManagerInternal; @@ -171,6 +174,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicInteger; import java.util.function.BiFunction; /** @@ -3320,8 +3324,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { } @Override - public @NonNull AttributionSource registerAttributionSource(@NonNull AttributionSource source) { - return mAttributionSourceRegistry.registerAttributionSource(source); + public void registerAttributionSource(@NonNull AttributionSource source) { + mAttributionSourceRegistry.registerAttributionSource(source); } @Override @@ -5295,8 +5299,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { * @param permissionName the name of the permission to be checked * @param userId the user ID * @param superImpl the original implementation that can be delegated to - * @return {@link android.content.pm.PackageManager.PERMISSION_GRANTED} if the package has - * the permission, or {@link android.content.pm.PackageManager.PERMISSION_DENITED} otherwise + * @return {@link android.content.pm.PackageManager#PERMISSION_GRANTED} if the package has + * the permission, or {@link android.content.pm.PackageManager#PERMISSION_DENIED} otherwise * * @see android.content.pm.PackageManager#checkPermission(String, String) */ @@ -5310,8 +5314,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { * @param uid the UID to be checked * @param permissionName the name of the permission to be checked * @param superImpl the original implementation that can be delegated to - * @return {@link android.content.pm.PackageManager.PERMISSION_GRANTED} if the package has - * the permission, or {@link android.content.pm.PackageManager.PERMISSION_DENITED} otherwise + * @return {@link android.content.pm.PackageManager#PERMISSION_GRANTED} if the package has + * the permission, or {@link android.content.pm.PackageManager#PERMISSION_DENIED} otherwise */ int checkUidPermission(int uid, @NonNull String permissionName, BiFunction<Integer, String, Integer> superImpl); @@ -5395,8 +5399,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { private final WeakHashMap<IBinder, AttributionSource> mAttributions = new WeakHashMap<>(); - public @NonNull AttributionSource registerAttributionSource( - @NonNull AttributionSource source) { + public void registerAttributionSource(@NonNull AttributionSource source) { // Here we keep track of attribution sources that were created by an app // from an attribution chain that called into the app and the apps's // own attribution source. An app can register an attribution chain up @@ -5443,10 +5446,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { } synchronized (mLock) { - final IBinder token = new Binder(); - final AttributionSource result = source.withToken(token); - mAttributions.put(token, result); - return result; + mAttributions.put(source.getToken(), source); } } @@ -5472,6 +5472,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { private static final ConcurrentHashMap<String, PermissionInfo> sPlatformPermissions = new ConcurrentHashMap<>(); + private static final AtomicInteger sAttributionChainIds = new AtomicInteger(0); + private final @NonNull Context mContext; private final @NonNull AppOpsManager mAppOpsManager; @@ -5481,53 +5483,108 @@ public class PermissionManagerService extends IPermissionManager.Stub { } @Override - @PermissionChecker.PermissionResult + @PermissionCheckerManager.PermissionResult public int checkPermission(@NonNull String permission, @NonNull AttributionSourceState attributionSourceState, @Nullable String message, - boolean forDataDelivery, boolean startDataDelivery, boolean fromDatasource) { + boolean forDataDelivery, boolean startDataDelivery, boolean fromDatasource, + int attributedOp) { Objects.requireNonNull(permission); Objects.requireNonNull(attributionSourceState); final AttributionSource attributionSource = new AttributionSource( attributionSourceState); final int result = checkPermission(mContext, permission, attributionSource, message, - forDataDelivery, startDataDelivery, fromDatasource); + forDataDelivery, startDataDelivery, fromDatasource, attributedOp); // Finish any started op if some step in the attribution chain failed. if (startDataDelivery && result != PermissionChecker.PERMISSION_GRANTED) { - finishDataDelivery(AppOpsManager.permissionToOp(permission), - attributionSource.asState()); + if (attributedOp == AppOpsManager.OP_NONE) { + finishDataDelivery(AppOpsManager.permissionToOpCode(permission), + attributionSource.asState(), fromDatasource); + } else { + finishDataDelivery(attributedOp, attributionSource.asState(), fromDatasource); + } } return result; } @Override - public void finishDataDelivery(@NonNull String op, - @NonNull AttributionSourceState attributionSourceState) { - if (op == null || attributionSourceState.packageName == null) { + public void finishDataDelivery(int op, + @NonNull AttributionSourceState attributionSourceState, boolean fromDatasource) { + Objects.requireNonNull(attributionSourceState); + + if (op == AppOpsManager.OP_NONE) { return; } - mAppOpsManager.finishProxyOp(op, new AttributionSource(attributionSourceState)); - if (attributionSourceState.next != null) { - finishDataDelivery(op, attributionSourceState.next[0]); + + AttributionSource current = new AttributionSource(attributionSourceState); + AttributionSource next = null; + + while (true) { + final boolean skipCurrentFinish = (fromDatasource || next != null); + + next = current.getNext(); + + // If the call is from a datasource we need to vet only the chain before it. This + // way we can avoid the datasource creating an attribution context for every call. + if (!(fromDatasource && current.asState() == attributionSourceState) + && next != null && !current.isTrusted(mContext)) { + return; + } + + // The access is for oneself if this is the single receiver of data + // after the data source or if this is the single attribution source + // in the chain if not from a datasource. + final boolean singleReceiverFromDatasource = (fromDatasource + && current.asState() == attributionSourceState && next != null + && next.getNext() == null); + final boolean selfAccess = singleReceiverFromDatasource || next == null; + + final AttributionSource accessorSource = (!singleReceiverFromDatasource) + ? current : next; + + if (selfAccess) { + final String resolvedPackageName = resolvePackageName(mContext, accessorSource); + if (resolvedPackageName == null) { + return; + } + mAppOpsManager.finishOp(accessorSource.getToken(), op, + accessorSource.getUid(), resolvedPackageName, + accessorSource.getAttributionTag()); + } else { + final AttributionSource resolvedAttributionSource = + resolveAttributionSource(mContext, accessorSource); + if (resolvedAttributionSource.getPackageName() == null) { + return; + } + mAppOpsManager.finishProxyOp(AppOpsManager.opToPublicName(op), + resolvedAttributionSource, skipCurrentFinish); + } + + if (next == null || next.getNext() == null) { + return; + } + + current = next; } } @Override - @PermissionChecker.PermissionResult + @PermissionCheckerManager.PermissionResult public int checkOp(int op, AttributionSourceState attributionSource, String message, boolean forDataDelivery, boolean startDataDelivery) { int result = checkOp(mContext, op, new AttributionSource(attributionSource), message, forDataDelivery, startDataDelivery); if (result != PermissionChecker.PERMISSION_GRANTED && startDataDelivery) { // Finish any started op if some step in the attribution chain failed. - finishDataDelivery(AppOpsManager.opToName(op), attributionSource); + finishDataDelivery(op, attributionSource, /*fromDatasource*/ false); } return result; } - @PermissionChecker.PermissionResult + @PermissionCheckerManager.PermissionResult private static int checkPermission(@NonNull Context context, @NonNull String permission, @NonNull AttributionSource attributionSource, @Nullable String message, - boolean forDataDelivery, boolean startDataDelivery, boolean fromDatasource) { + boolean forDataDelivery, boolean startDataDelivery, boolean fromDatasource, + int attributedOp) { PermissionInfo permissionInfo = sPlatformPermissions.get(permission); if (permissionInfo == null) { @@ -5549,7 +5606,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { } if (permissionInfo.isRuntime()) { return checkRuntimePermission(context, permission, attributionSource, message, - forDataDelivery, startDataDelivery, fromDatasource); + forDataDelivery, startDataDelivery, fromDatasource, attributedOp); } if (!fromDatasource && !checkPermission(context, permission, attributionSource.getUid(), @@ -5558,15 +5615,14 @@ public class PermissionManagerService extends IPermissionManager.Stub { } if (attributionSource.getNext() != null) { - return checkPermission(context, permission, - attributionSource.getNext(), message, forDataDelivery, - startDataDelivery, /*fromDatasource*/ false); + return checkPermission(context, permission, attributionSource.getNext(), message, + forDataDelivery, startDataDelivery, /*fromDatasource*/ false, attributedOp); } return PermissionChecker.PERMISSION_GRANTED; } - @PermissionChecker.PermissionResult + @PermissionCheckerManager.PermissionResult private static int checkAppOpPermission(@NonNull Context context, @NonNull String permission, @NonNull AttributionSource attributionSource, @Nullable String message, boolean forDataDelivery, boolean fromDatasource) { @@ -5586,7 +5642,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { // If the call is from a datasource we need to vet only the chain before it. This // way we can avoid the datasource creating an attribution context for every call. - if (!(fromDatasource && current == attributionSource) + if (!(fromDatasource && current.equals(attributionSource)) && next != null && !current.isTrusted(context)) { return PermissionChecker.PERMISSION_HARD_DENIED; } @@ -5595,12 +5651,15 @@ public class PermissionManagerService extends IPermissionManager.Stub { // after the data source or if this is the single attribution source // in the chain if not from a datasource. final boolean singleReceiverFromDatasource = (fromDatasource - && current == attributionSource && next != null && next.getNext() == null); + && current.equals(attributionSource) && next != null + && next.getNext() == null); final boolean selfAccess = singleReceiverFromDatasource || next == null; final int opMode = performOpTransaction(context, op, current, message, forDataDelivery, /*startDataDelivery*/ false, skipCurrentChecks, - selfAccess, singleReceiverFromDatasource); + selfAccess, singleReceiverFromDatasource, AppOpsManager.OP_NONE, + AppOpsManager.ATTRIBUTION_FLAGS_NONE, AppOpsManager.ATTRIBUTION_FLAGS_NONE, + AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE); switch (opMode) { case AppOpsManager.MODE_IGNORED: @@ -5631,9 +5690,12 @@ public class PermissionManagerService extends IPermissionManager.Stub { private static int checkRuntimePermission(@NonNull Context context, @NonNull String permission, @NonNull AttributionSource attributionSource, @Nullable String message, boolean forDataDelivery, boolean startDataDelivery, - boolean fromDatasource) { + boolean fromDatasource, int attributedOp) { // Now let's check the identity chain... final int op = AppOpsManager.permissionToOpCode(permission); + final int attributionChainId = (startDataDelivery) + ? sAttributionChainIds.incrementAndGet() + : AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE; AttributionSource current = attributionSource; AttributionSource next = null; @@ -5644,7 +5706,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { // If the call is from a datasource we need to vet only the chain before it. This // way we can avoid the datasource creating an attribution context for every call. - if (!(fromDatasource && current == attributionSource) + if (!(fromDatasource && current.equals(attributionSource)) && next != null && !current.isTrusted(context)) { return PermissionChecker.PERMISSION_HARD_DENIED; } @@ -5678,12 +5740,21 @@ public class PermissionManagerService extends IPermissionManager.Stub { // after the data source or if this is the single attribution source // in the chain if not from a datasource. final boolean singleReceiverFromDatasource = (fromDatasource - && current == attributionSource && next != null && next.getNext() == null); + && current.equals(attributionSource) + && next != null && next.getNext() == null); final boolean selfAccess = singleReceiverFromDatasource || next == null; + final int proxyAttributionFlags = (!skipCurrentChecks) + ? resolveProxyAttributionFlags(attributionSource, current, fromDatasource, + startDataDelivery, selfAccess) + : AppOpsManager.ATTRIBUTION_FLAGS_NONE; + final int proxiedAttributionFlags = resolveProxiedAttributionFlags( + attributionSource, next, fromDatasource, startDataDelivery, selfAccess); + final int opMode = performOpTransaction(context, op, current, message, forDataDelivery, startDataDelivery, skipCurrentChecks, selfAccess, - singleReceiverFromDatasource); + singleReceiverFromDatasource, attributedOp, proxyAttributionFlags, + proxiedAttributionFlags, attributionChainId); switch (opMode) { case AppOpsManager.MODE_ERRORED: { @@ -5714,6 +5785,50 @@ public class PermissionManagerService extends IPermissionManager.Stub { return permissionGranted; } + private static @AttributionFlags int resolveProxyAttributionFlags( + @NonNull AttributionSource attributionChain, + @NonNull AttributionSource current, boolean fromDatasource, + boolean startDataDelivery, boolean selfAccess) { + return resolveAttributionFlags(attributionChain, current, fromDatasource, + startDataDelivery, selfAccess, /*flagsForProxy*/ true); + } + + private static @AttributionFlags int resolveProxiedAttributionFlags( + @NonNull AttributionSource attributionChain, + @NonNull AttributionSource current, boolean fromDatasource, + boolean startDataDelivery, boolean selfAccess) { + return resolveAttributionFlags(attributionChain, current, fromDatasource, + startDataDelivery, selfAccess, /*flagsForProxy*/ false); + } + + private static @AttributionFlags int resolveAttributionFlags( + @NonNull AttributionSource attributionChain, + @NonNull AttributionSource current, boolean fromDatasource, + boolean startDataDelivery, boolean selfAccess, boolean flagsForProxy) { + if (current == null || !startDataDelivery) { + return AppOpsManager.ATTRIBUTION_FLAGS_NONE; + } + if (flagsForProxy) { + if (selfAccess) { + return AppOpsManager.ATTRIBUTION_FLAG_ACCESSOR; + } else if (!fromDatasource && current.equals(attributionChain)) { + return AppOpsManager.ATTRIBUTION_FLAG_ACCESSOR; + } + } else { + if (selfAccess) { + return AppOpsManager.ATTRIBUTION_FLAG_RECEIVER; + } else if (fromDatasource && current.equals(attributionChain.getNext())) { + return AppOpsManager.ATTRIBUTION_FLAG_ACCESSOR; + } else if (current.getNext() == null) { + return AppOpsManager.ATTRIBUTION_FLAG_RECEIVER; + } + } + if (fromDatasource && current.equals(attributionChain)) { + return AppOpsManager.ATTRIBUTION_FLAGS_NONE; + } + return AppOpsManager.ATTRIBUTION_FLAG_INTERMEDIARY; + } + private static int checkOp(@NonNull Context context, @NonNull int op, @NonNull AttributionSource attributionSource, @Nullable String message, boolean forDataDelivery, boolean startDataDelivery) { @@ -5721,6 +5836,10 @@ public class PermissionManagerService extends IPermissionManager.Stub { return PermissionChecker.PERMISSION_HARD_DENIED; } + final int attributionChainId = (startDataDelivery) + ? sAttributionChainIds.incrementAndGet() + : AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE; + AttributionSource current = attributionSource; AttributionSource next = null; @@ -5737,9 +5856,18 @@ public class PermissionManagerService extends IPermissionManager.Stub { // The access is for oneself if this is the single attribution source in the chain. final boolean selfAccess = (next == null); + final int proxyAttributionFlags = (!skipCurrentChecks) + ? resolveProxyAttributionFlags(attributionSource, current, + /*fromDatasource*/ false, startDataDelivery, selfAccess) + : AppOpsManager.ATTRIBUTION_FLAGS_NONE; + final int proxiedAttributionFlags = resolveProxiedAttributionFlags( + attributionSource, next, /*fromDatasource*/ false, startDataDelivery, + selfAccess); + final int opMode = performOpTransaction(context, op, current, message, forDataDelivery, startDataDelivery, skipCurrentChecks, selfAccess, - /*fromDatasource*/ false); + /*fromDatasource*/ false, AppOpsManager.OP_NONE, proxyAttributionFlags, + proxiedAttributionFlags, attributionChainId); switch (opMode) { case AppOpsManager.MODE_ERRORED: { @@ -5758,10 +5886,13 @@ public class PermissionManagerService extends IPermissionManager.Stub { } } + @SuppressWarnings("ConstantConditions") private static int performOpTransaction(@NonNull Context context, int op, @NonNull AttributionSource attributionSource, @Nullable String message, boolean forDataDelivery, boolean startDataDelivery, boolean skipProxyOperation, - boolean selfAccess, boolean singleReceiverFromDatasource) { + boolean selfAccess, boolean singleReceiverFromDatasource, int attributedOp, + @AttributionFlags int proxyAttributionFlags, + @AttributionFlags int proxiedAttributionFlags, int attributionChainId) { // We cannot perform app ops transactions without a package name. In all relevant // places we pass the package name but just in case there is a bug somewhere we // do a best effort to resolve the package from the UID (pick first without a loss @@ -5793,36 +5924,75 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (resolvedAttributionSource.getPackageName() == null) { return AppOpsManager.MODE_ERRORED; } + // If the datasource is not in a trusted platform component then in would not + // have UPDATE_APP_OPS_STATS and the call below would fail. The problem is that + // an app is exposing runtime permission protected data but cannot blame others + // in a trusted way which would not properly show in permission usage UIs. + // As a fallback we note a proxy op that blames the app and the datasource. + int startedOp = op; + int checkedOpResult = MODE_ALLOWED; + int startedOpResult; + + // If the datasource wants to attribute to another app op we need to + // make sure the op for the permission and the attributed ops allow + // the operation. We return the less permissive of the two and check + // the permission op while start the attributed op. + if (attributedOp != AppOpsManager.OP_NONE && attributedOp != op) { + checkedOpResult = appOpsManager.checkOpNoThrow(op, + resolvedAttributionSource.getUid(), resolvedAttributionSource + .getPackageName()); + if (checkedOpResult == MODE_ERRORED) { + return checkedOpResult; + } + startedOp = attributedOp; + } if (selfAccess) { - // If the datasource is not in a trusted platform component then in would not - // have UPDATE_APP_OPS_STATS and the call below would fail. The problem is that - // an app is exposing runtime permission protected data but cannot blame others - // in a trusted way which would not properly show in permission usage UIs. - // As a fallback we note a proxy op that blames the app and the datasource. try { - return appOpsManager.startOpNoThrow(op, resolvedAttributionSource.getUid(), + startedOpResult = appOpsManager.startOpNoThrow( + resolvedAttributionSource.getToken(), startedOp, + resolvedAttributionSource.getUid(), resolvedAttributionSource.getPackageName(), /*startIfModeDefault*/ false, resolvedAttributionSource.getAttributionTag(), - message); + message, proxyAttributionFlags, attributionChainId); } catch (SecurityException e) { Slog.w(LOG_TAG, "Datasource " + attributionSource + " protecting data with" + " platform defined runtime permission " + AppOpsManager.opToPermission(op) + " while not having " + Manifest.permission.UPDATE_APP_OPS_STATS); - return appOpsManager.startProxyOpNoThrow(op, attributionSource, message, - skipProxyOperation); + startedOpResult = appOpsManager.startProxyOpNoThrow(attributedOp, + attributionSource, message, skipProxyOperation, + proxyAttributionFlags, proxiedAttributionFlags, attributionChainId); } } else { - return appOpsManager.startProxyOpNoThrow(op, resolvedAttributionSource, message, - skipProxyOperation); + startedOpResult = appOpsManager.startProxyOpNoThrow(startedOp, + resolvedAttributionSource, message, skipProxyOperation, + proxyAttributionFlags, proxiedAttributionFlags, attributionChainId); } + return Math.max(checkedOpResult, startedOpResult); } else { final AttributionSource resolvedAttributionSource = resolveAttributionSource( context, accessorSource); if (resolvedAttributionSource.getPackageName() == null) { return AppOpsManager.MODE_ERRORED; } + int notedOp = op; + int checkedOpResult = MODE_ALLOWED; + int notedOpResult; + + // If the datasource wants to attribute to another app op we need to + // make sure the op for the permission and the attributed ops allow + // the operation. We return the less permissive of the two and check + // the permission op while start the attributed op. + if (attributedOp != AppOpsManager.OP_NONE && attributedOp != op) { + checkedOpResult = appOpsManager.checkOpNoThrow(op, + resolvedAttributionSource.getUid(), resolvedAttributionSource + .getPackageName()); + if (checkedOpResult == MODE_ERRORED) { + return checkedOpResult; + } + notedOp = attributedOp; + } if (selfAccess) { // If the datasource is not in a trusted platform component then in would not // have UPDATE_APP_OPS_STATS and the call below would fail. The problem is that @@ -5830,7 +6000,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { // in a trusted way which would not properly show in permission usage UIs. // As a fallback we note a proxy op that blames the app and the datasource. try { - return appOpsManager.noteOpNoThrow(op, resolvedAttributionSource.getUid(), + notedOpResult = appOpsManager.noteOpNoThrow(notedOp, + resolvedAttributionSource.getUid(), resolvedAttributionSource.getPackageName(), resolvedAttributionSource.getAttributionTag(), message); @@ -5839,13 +6010,14 @@ public class PermissionManagerService extends IPermissionManager.Stub { + " platform defined runtime permission " + AppOpsManager.opToPermission(op) + " while not having " + Manifest.permission.UPDATE_APP_OPS_STATS); - return appOpsManager.noteProxyOpNoThrow(op, attributionSource, message, - skipProxyOperation); + notedOpResult = appOpsManager.noteProxyOpNoThrow(notedOp, attributionSource, + message, skipProxyOperation); } } else { - return appOpsManager.noteProxyOpNoThrow(op, resolvedAttributionSource, message, - skipProxyOperation); + notedOpResult = appOpsManager.noteProxyOpNoThrow(notedOp, + resolvedAttributionSource, message, skipProxyOperation); } + return Math.max(checkedOpResult, notedOpResult); } } diff --git a/services/core/java/com/android/server/policy/AppOpsPolicy.java b/services/core/java/com/android/server/policy/AppOpsPolicy.java index 2cfbf26cf996..607bc569ad64 100644 --- a/services/core/java/com/android/server/policy/AppOpsPolicy.java +++ b/services/core/java/com/android/server/policy/AppOpsPolicy.java @@ -19,6 +19,7 @@ package com.android.server.policy; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.AppOpsManager; +import android.app.AppOpsManager.AttributionFlags; import android.app.AppOpsManagerInternal; import android.app.SyncNotedAppOp; import android.app.role.RoleManager; @@ -39,6 +40,7 @@ import android.util.ArraySet; import android.util.Log; import com.android.internal.annotations.GuardedBy; +import com.android.internal.util.function.DecFunction; import com.android.internal.util.function.HeptFunction; import com.android.internal.util.function.HexFunction; import com.android.internal.util.function.NonaFunction; @@ -46,6 +48,7 @@ import com.android.internal.util.function.OctFunction; import com.android.internal.util.function.QuadFunction; import com.android.internal.util.function.QuintFunction; import com.android.internal.util.function.TriFunction; +import com.android.internal.util.function.UndecFunction; import com.android.server.LocalServices; import java.util.List; @@ -179,32 +182,37 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat public SyncNotedAppOp startOperation(IBinder token, int code, int uid, @Nullable String packageName, @Nullable String attributionTag, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, String message, - boolean shouldCollectMessage, @NonNull NonaFunction<IBinder, Integer, Integer, String, - String, Boolean, Boolean, String, Boolean, SyncNotedAppOp> superImpl) { + boolean shouldCollectMessage, @AttributionFlags int attributionFlags, + int attributionChainId, @NonNull UndecFunction<IBinder, Integer, Integer, String, + String, Boolean, Boolean, String, Boolean, Integer, Integer, + SyncNotedAppOp> superImpl) { return superImpl.apply(token, resolveDatasourceOp(code, uid, packageName, attributionTag), uid, packageName, attributionTag, startIfModeDefault, shouldCollectAsyncNotedOp, - message, shouldCollectMessage); + message, shouldCollectMessage, attributionFlags, attributionChainId); } @Override - public SyncNotedAppOp startProxyOperation(IBinder token, int code, + public SyncNotedAppOp startProxyOperation(int code, @NonNull AttributionSource attributionSource, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage, - boolean skipProxyOperation, @NonNull OctFunction<IBinder, Integer, AttributionSource, - Boolean, Boolean, String, Boolean, Boolean, SyncNotedAppOp> superImpl) { - return superImpl.apply(token, resolveDatasourceOp(code, attributionSource.getUid(), + boolean skipProxyOperation, @AttributionFlags int proxyAttributionFlags, + @AttributionFlags int proxiedAttributionFlags, int attributionChainId, + @NonNull DecFunction<Integer, AttributionSource, Boolean, Boolean, String, Boolean, + Boolean, Integer, Integer, Integer, SyncNotedAppOp> superImpl) { + return superImpl.apply(resolveDatasourceOp(code, attributionSource.getUid(), attributionSource.getPackageName(), attributionSource.getAttributionTag()), attributionSource, startIfModeDefault, shouldCollectAsyncNotedOp, message, - shouldCollectMessage, skipProxyOperation); + shouldCollectMessage, skipProxyOperation, proxyAttributionFlags, + proxiedAttributionFlags, attributionChainId); } @Override - public void finishProxyOperation(IBinder clientId, int code, - @NonNull AttributionSource attributionSource, - @NonNull TriFunction<IBinder, Integer, AttributionSource, Void> superImpl) { - superImpl.apply(clientId, resolveDatasourceOp(code, attributionSource.getUid(), + public void finishProxyOperation(int code, @NonNull AttributionSource attributionSource, + boolean skipProxyOperation, @NonNull TriFunction<Integer, AttributionSource, + Boolean, Void> superImpl) { + superImpl.apply(resolveDatasourceOp(code, attributionSource.getUid(), attributionSource.getPackageName(), attributionSource.getAttributionTag()), - attributionSource); + attributionSource, skipProxyOperation); } private int resolveDatasourceOp(int code, int uid, @NonNull String packageName, diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java index 753b42b24556..0f37450c24c9 100644 --- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java +++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java @@ -25,6 +25,8 @@ import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; import android.graphics.drawable.Icon; import android.net.Uri; import android.os.Binder; @@ -59,6 +61,7 @@ import android.view.textclassifier.TextLinks; import android.view.textclassifier.TextSelection; import com.android.internal.annotations.GuardedBy; +import com.android.internal.content.PackageMonitor; import com.android.internal.util.DumpUtils; import com.android.internal.util.FunctionalUtils; import com.android.internal.util.FunctionalUtils.ThrowingConsumer; @@ -110,6 +113,7 @@ public final class TextClassificationManagerService extends ITextClassifierServi try { publishBinderService(Context.TEXT_CLASSIFICATION_SERVICE, mManagerService); mManagerService.startListenSettings(); + mManagerService.startTrackingPackageChanges(); } catch (Throwable t) { // Starting this service is not critical to the running of this device and should // therefore not crash the device. If it fails, log the error and continue. @@ -119,11 +123,14 @@ public final class TextClassificationManagerService extends ITextClassifierServi @Override public void onUserStarting(@NonNull TargetUser user) { + updatePackageStateForUser(user.getUserIdentifier()); processAnyPendingWork(user.getUserIdentifier()); } @Override public void onUserUnlocking(@NonNull TargetUser user) { + // refresh if we failed earlier due to locked encrypted user + updatePackageStateForUser(user.getUserIdentifier()); // Rebind if we failed earlier due to locked encrypted user processAnyPendingWork(user.getUserIdentifier()); } @@ -134,6 +141,14 @@ public final class TextClassificationManagerService extends ITextClassifierServi } } + private void updatePackageStateForUser(int userId) { + synchronized (mManagerService.mLock) { + // Update the cached disable status, the TextClassfier may not be direct boot aware, + // we should update the disable status after user unlock + mManagerService.getUserStateLocked(userId).updatePackageStateLocked(); + } + } + @Override public void onUserStopping(@NonNull TargetUser user) { int userId = user.getUserIdentifier(); @@ -160,6 +175,8 @@ public final class TextClassificationManagerService extends ITextClassifierServi private final String mDefaultTextClassifierPackage; @Nullable private final String mSystemTextClassifierPackage; + // TODO: consider using device config to control it. + private boolean DEBUG = false; private TextClassificationManagerService(Context context) { mContext = Objects.requireNonNull(context); @@ -176,6 +193,46 @@ public final class TextClassificationManagerService extends ITextClassifierServi mSettingsListener.registerObserver(); } + void startTrackingPackageChanges() { + final PackageMonitor monitor = new PackageMonitor() { + + @Override + public void onPackageAdded(String packageName, int uid) { + notifyPackageInstallStatusChange(packageName, /* installed*/ true); + } + + @Override + public void onPackageRemoved(String packageName, int uid) { + notifyPackageInstallStatusChange(packageName, /* installed= */ false); + } + + @Override + public void onPackageModified(String packageName) { + final int userId = getChangingUserId(); + synchronized (mLock) { + final UserState userState = getUserStateLocked(userId); + final ServiceState serviceState = userState.getServiceStateLocked(packageName); + if (serviceState != null) { + serviceState.onPackageModifiedLocked(); + } + } + } + + private void notifyPackageInstallStatusChange(String packageName, boolean installed) { + final int userId = getChangingUserId(); + synchronized (mLock) { + final UserState userState = getUserStateLocked(userId); + final ServiceState serviceState = userState.getServiceStateLocked(packageName); + if (serviceState != null) { + serviceState.onPackageInstallStatusChangeLocked(installed); + } + } + } + }; + + monitor.register(mContext, null, UserHandle.ALL, true); + } + @Override public void onConnectedStateChanged(@ConnectionState int connected) { } @@ -452,6 +509,14 @@ public final class TextClassificationManagerService extends ITextClassifierServi if (serviceState == null) { Slog.d(LOG_TAG, "No configured system TextClassifierService"); callback.onFailure(); + } else if (!serviceState.isInstalledLocked() || !serviceState.isEnabledLocked()) { + if (DEBUG) { + Slog.d(LOG_TAG, + serviceState.mPackageName + " is not available in user " + userId + + ". Installed: " + serviceState.isInstalledLocked() + + ", enabled:" + serviceState.isEnabledLocked()); + } + callback.onFailure(); } else if (attemptToBind && !serviceState.bindLocked()) { Slog.d(LOG_TAG, "Unable to bind TextClassifierService at " + methodName); callback.onFailure(); @@ -761,6 +826,24 @@ public final class TextClassificationManagerService extends ITextClassifierServi return serviceStates; } + @GuardedBy("mLock") + @Nullable + private ServiceState getServiceStateLocked(String packageName) { + for (ServiceState serviceState : getAllServiceStatesLocked()) { + if (serviceState.mPackageName.equals(packageName)) { + return serviceState; + } + } + return null; + } + + @GuardedBy("mLock") + private void updatePackageStateLocked() { + for (ServiceState serviceState : getAllServiceStatesLocked()) { + serviceState.updatePackageStateLocked(); + } + } + void dump(IndentingPrintWriter pw) { synchronized (mLock) { pw.increaseIndent(); @@ -814,6 +897,10 @@ public final class TextClassificationManagerService extends ITextClassifierServi ComponentName mBoundComponentName = null; @GuardedBy("mLock") int mBoundServiceUid = Process.INVALID_UID; + @GuardedBy("mLock") + boolean mInstalled; + @GuardedBy("mLock") + boolean mEnabled; private ServiceState( @UserIdInt int userId, @NonNull String packageName, boolean isTrusted) { @@ -822,6 +909,8 @@ public final class TextClassificationManagerService extends ITextClassifierServi mConnection = new TextClassifierServiceConnection(mUserId); mIsTrusted = isTrusted; mBindServiceFlags = createBindServiceFlags(packageName); + mInstalled = isPackageInstalledForUser(); + mEnabled = isServiceEnabledForUser(); } @Context.BindServiceFlags @@ -833,6 +922,54 @@ public final class TextClassificationManagerService extends ITextClassifierServi return flags; } + private boolean isPackageInstalledForUser() { + try { + PackageManager packageManager = mContext.getPackageManager(); + return packageManager.getPackageInfoAsUser(mPackageName, 0, mUserId) != null; + } catch (PackageManager.NameNotFoundException e) { + return false; + } + } + + private boolean isServiceEnabledForUser() { + PackageManager packageManager = mContext.getPackageManager(); + Intent intent = new Intent(TextClassifierService.SERVICE_INTERFACE); + intent.setPackage(mPackageName); + ResolveInfo resolveInfo = packageManager.resolveServiceAsUser(intent, + PackageManager.GET_SERVICES, mUserId); + ServiceInfo serviceInfo = resolveInfo == null ? null : resolveInfo.serviceInfo; + return serviceInfo != null; + } + + @GuardedBy("mLock") + @NonNull + private void onPackageInstallStatusChangeLocked(boolean installed) { + mInstalled = installed; + } + + @GuardedBy("mLock") + @NonNull + private void onPackageModifiedLocked() { + mEnabled = isServiceEnabledForUser(); + } + + @GuardedBy("mLock") + @NonNull + private void updatePackageStateLocked() { + mInstalled = isPackageInstalledForUser(); + mEnabled = isServiceEnabledForUser(); + } + + @GuardedBy("mLock") + boolean isInstalledLocked() { + return mInstalled; + } + + @GuardedBy("mLock") + boolean isEnabledLocked() { + return mEnabled; + } + @GuardedBy("mLock") boolean isBoundLocked() { return mService != null; @@ -923,6 +1060,8 @@ public final class TextClassificationManagerService extends ITextClassifierServi pw.printPair("userId", mUserId); synchronized (mLock) { pw.printPair("packageName", mPackageName); + pw.printPair("installed", mInstalled); + pw.printPair("enabled", mEnabled); pw.printPair("boundComponentName", mBoundComponentName); pw.printPair("isTrusted", mIsTrusted); pw.printPair("bindServiceFlags", mBindServiceFlags); diff --git a/services/core/java/com/android/server/vibrator/ClippingAmplitudeAndFrequencyAdapter.java b/services/core/java/com/android/server/vibrator/ClippingAmplitudeAndFrequencyAdapter.java new file mode 100644 index 000000000000..0690d3be3db1 --- /dev/null +++ b/services/core/java/com/android/server/vibrator/ClippingAmplitudeAndFrequencyAdapter.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.vibrator; + +import android.os.VibratorInfo; +import android.os.vibrator.RampSegment; +import android.os.vibrator.StepSegment; +import android.os.vibrator.VibrationEffectSegment; +import android.util.MathUtils; + +import java.util.List; + +/** + * Adapter that clips frequency values to {@link VibratorInfo#getFrequencyRange()} and + * amplitude values to respective {@link VibratorInfo#getMaxAmplitude}. + * + * <p>Devices with no frequency control will collapse all frequencies to zero and leave + * amplitudes unchanged. + * + * <p>The frequency value returned in segments will be absolute, converted with + * {@link VibratorInfo#getAbsoluteFrequency(float)}. + */ +final class ClippingAmplitudeAndFrequencyAdapter + implements VibrationEffectAdapters.SegmentsAdapter<VibratorInfo> { + + @Override + public int apply(List<VibrationEffectSegment> segments, int repeatIndex, VibratorInfo info) { + int segmentCount = segments.size(); + for (int i = 0; i < segmentCount; i++) { + VibrationEffectSegment segment = segments.get(i); + if (segment instanceof StepSegment) { + segments.set(i, apply((StepSegment) segment, info)); + } else if (segment instanceof RampSegment) { + segments.set(i, apply((RampSegment) segment, info)); + } + } + return repeatIndex; + } + + private StepSegment apply(StepSegment segment, VibratorInfo info) { + float clampedFrequency = clampFrequency(info, segment.getFrequency()); + return new StepSegment( + clampAmplitude(info, clampedFrequency, segment.getAmplitude()), + info.getAbsoluteFrequency(clampedFrequency), + (int) segment.getDuration()); + } + + private RampSegment apply(RampSegment segment, VibratorInfo info) { + float clampedStartFrequency = clampFrequency(info, segment.getStartFrequency()); + float clampedEndFrequency = clampFrequency(info, segment.getEndFrequency()); + return new RampSegment( + clampAmplitude(info, clampedStartFrequency, segment.getStartAmplitude()), + clampAmplitude(info, clampedEndFrequency, segment.getEndAmplitude()), + info.getAbsoluteFrequency(clampedStartFrequency), + info.getAbsoluteFrequency(clampedEndFrequency), + (int) segment.getDuration()); + } + + private float clampFrequency(VibratorInfo info, float frequency) { + return info.getFrequencyRange().clamp(frequency); + } + + private float clampAmplitude(VibratorInfo info, float frequency, float amplitude) { + return MathUtils.min(amplitude, info.getMaxAmplitude(frequency)); + } +} diff --git a/services/core/java/com/android/server/vibrator/DeviceVibrationEffectAdapter.java b/services/core/java/com/android/server/vibrator/DeviceVibrationEffectAdapter.java index 7f2b07b6f367..b695150d9ba3 100644 --- a/services/core/java/com/android/server/vibrator/DeviceVibrationEffectAdapter.java +++ b/services/core/java/com/android/server/vibrator/DeviceVibrationEffectAdapter.java @@ -16,159 +16,33 @@ package com.android.server.vibrator; -import android.hardware.vibrator.IVibrator; import android.os.VibrationEffect; import android.os.VibratorInfo; -import android.os.vibrator.RampSegment; -import android.os.vibrator.StepSegment; -import android.os.vibrator.VibrationEffectSegment; -import android.util.MathUtils; -import android.util.Range; -import java.util.ArrayList; +import java.util.Arrays; import java.util.List; /** Adapts a {@link VibrationEffect} to a specific device, taking into account its capabilities. */ -final class DeviceVibrationEffectAdapter implements VibrationEffectModifier<VibratorInfo> { +final class DeviceVibrationEffectAdapter + implements VibrationEffectAdapters.EffectAdapter<VibratorInfo> { - /** Adapts a sequence of {@link VibrationEffectSegment} to device's capabilities. */ - interface SegmentsAdapter { + /** Duration of each step created to simulate a ramp segment. */ + private static final int RAMP_STEP_DURATION_MILLIS = 5; - /** - * Modifies the given segments list by adding/removing segments to it based on the - * device capabilities specified by given {@link VibratorInfo}. - * - * @param segments List of {@link VibrationEffectSegment} to be adapter to the device. - * @param repeatIndex Repeat index on the current segment list. - * @param info The device vibrator info that the segments must be adapted to. - * @return The new repeat index on the modifies list. - */ - int apply(List<VibrationEffectSegment> segments, int repeatIndex, VibratorInfo info); - } - - private final SegmentsAdapter mAmplitudeFrequencyAdapter; - private final SegmentsAdapter mStepToRampAdapter; + private final List<VibrationEffectAdapters.SegmentsAdapter<VibratorInfo>> mSegmentAdapters; DeviceVibrationEffectAdapter() { - this(new ClippingAmplitudeFrequencyAdapter()); - } - - DeviceVibrationEffectAdapter(SegmentsAdapter amplitudeFrequencyAdapter) { - mAmplitudeFrequencyAdapter = amplitudeFrequencyAdapter; - mStepToRampAdapter = new StepToRampAdapter(); + mSegmentAdapters = Arrays.asList( + // TODO(b/167947076): add filter that removes unsupported primitives + // TODO(b/167947076): add filter that replaces unsupported prebaked with fallback + new RampToStepAdapter(RAMP_STEP_DURATION_MILLIS), + new StepToRampAdapter(), + new ClippingAmplitudeAndFrequencyAdapter() + ); } @Override public VibrationEffect apply(VibrationEffect effect, VibratorInfo info) { - if (!(effect instanceof VibrationEffect.Composed)) { - return effect; - } - - VibrationEffect.Composed composed = (VibrationEffect.Composed) effect; - List<VibrationEffectSegment> newSegments = new ArrayList<>(composed.getSegments()); - int newRepeatIndex = composed.getRepeatIndex(); - - // Maps steps that should be handled by PWLE to ramps. - // This should be done before frequency is converted from relative to absolute values. - newRepeatIndex = mStepToRampAdapter.apply(newSegments, newRepeatIndex, info); - - // Adapt amplitude and frequency values to device supported ones, converting frequency - // to absolute values in Hertz. - newRepeatIndex = mAmplitudeFrequencyAdapter.apply(newSegments, newRepeatIndex, info); - - // TODO(b/167947076): add ramp to step adapter - // TODO(b/167947076): add filter that removes unsupported primitives - // TODO(b/167947076): add filter that replaces unsupported prebaked with fallback - - return new VibrationEffect.Composed(newSegments, newRepeatIndex); - } - - /** - * Adapter that converts step segments that should be handled as PWLEs to ramp segments. - * - * <p>This leves the list unchanged if the device do not have compose PWLE capability. - */ - private static final class StepToRampAdapter implements SegmentsAdapter { - @Override - public int apply(List<VibrationEffectSegment> segments, int repeatIndex, - VibratorInfo info) { - if (!info.hasCapability(IVibrator.CAP_COMPOSE_PWLE_EFFECTS)) { - // The vibrator do not have PWLE capability, so keep the segments unchanged. - return repeatIndex; - } - int segmentCount = segments.size(); - // Convert steps that require frequency control to ramps. - for (int i = 0; i < segmentCount; i++) { - VibrationEffectSegment segment = segments.get(i); - if ((segment instanceof StepSegment) - && ((StepSegment) segment).getFrequency() != 0) { - segments.set(i, apply((StepSegment) segment)); - } - } - // Convert steps that are next to ramps to also become ramps, so they can be composed - // together in the same PWLE waveform. - for (int i = 1; i < segmentCount; i++) { - if (segments.get(i) instanceof RampSegment) { - for (int j = i - 1; j >= 0 && (segments.get(j) instanceof StepSegment); j--) { - segments.set(j, apply((StepSegment) segments.get(j))); - } - } - } - return repeatIndex; - } - - private RampSegment apply(StepSegment segment) { - return new RampSegment(segment.getAmplitude(), segment.getAmplitude(), - segment.getFrequency(), segment.getFrequency(), (int) segment.getDuration()); - } - } - - /** - * Adapter that clips frequency values to {@link VibratorInfo#getFrequencyRange()} and - * amplitude values to respective {@link VibratorInfo#getMaxAmplitude}. - * - * <p>Devices with no frequency control will collapse all frequencies to zero and leave - * amplitudes unchanged. - * - * <p>The frequency value returned in segments will be absolute, conveted with - * {@link VibratorInfo#getAbsoluteFrequency(float)}. - */ - private static final class ClippingAmplitudeFrequencyAdapter implements SegmentsAdapter { - @Override - public int apply(List<VibrationEffectSegment> segments, int repeatIndex, - VibratorInfo info) { - int segmentCount = segments.size(); - for (int i = 0; i < segmentCount; i++) { - VibrationEffectSegment segment = segments.get(i); - if (segment instanceof StepSegment) { - segments.set(i, apply((StepSegment) segment, info)); - } else if (segment instanceof RampSegment) { - segments.set(i, apply((RampSegment) segment, info)); - } - } - return repeatIndex; - } - - private StepSegment apply(StepSegment segment, VibratorInfo info) { - float clampedFrequency = info.getFrequencyRange().clamp(segment.getFrequency()); - return new StepSegment( - MathUtils.min(segment.getAmplitude(), info.getMaxAmplitude(clampedFrequency)), - info.getAbsoluteFrequency(clampedFrequency), - (int) segment.getDuration()); - } - - private RampSegment apply(RampSegment segment, VibratorInfo info) { - Range<Float> frequencyRange = info.getFrequencyRange(); - float clampedStartFrequency = frequencyRange.clamp(segment.getStartFrequency()); - float clampedEndFrequency = frequencyRange.clamp(segment.getEndFrequency()); - return new RampSegment( - MathUtils.min(segment.getStartAmplitude(), - info.getMaxAmplitude(clampedStartFrequency)), - MathUtils.min(segment.getEndAmplitude(), - info.getMaxAmplitude(clampedEndFrequency)), - info.getAbsoluteFrequency(clampedStartFrequency), - info.getAbsoluteFrequency(clampedEndFrequency), - (int) segment.getDuration()); - } + return VibrationEffectAdapters.apply(effect, mSegmentAdapters, info); } } diff --git a/services/core/java/com/android/server/vibrator/RampToStepAdapter.java b/services/core/java/com/android/server/vibrator/RampToStepAdapter.java new file mode 100644 index 000000000000..1e05bdbdf082 --- /dev/null +++ b/services/core/java/com/android/server/vibrator/RampToStepAdapter.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.vibrator; + +import android.hardware.vibrator.IVibrator; +import android.os.VibratorInfo; +import android.os.vibrator.RampSegment; +import android.os.vibrator.StepSegment; +import android.os.vibrator.VibrationEffectSegment; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Adapter that converts ramp segments that to a sequence of fixed step segments. + * + * <p>This leaves the list unchanged if the device have compose PWLE capability. + */ +final class RampToStepAdapter implements VibrationEffectAdapters.SegmentsAdapter<VibratorInfo> { + + private final int mStepDuration; + + RampToStepAdapter(int stepDuration) { + mStepDuration = stepDuration; + } + + @Override + public int apply(List<VibrationEffectSegment> segments, int repeatIndex, + VibratorInfo info) { + if (info.hasCapability(IVibrator.CAP_COMPOSE_PWLE_EFFECTS)) { + // The vibrator have PWLE capability, so keep the segments unchanged. + return repeatIndex; + } + int segmentCount = segments.size(); + for (int i = 0; i < segmentCount; i++) { + VibrationEffectSegment segment = segments.get(i); + if (!(segment instanceof RampSegment)) { + continue; + } + List<StepSegment> steps = apply((RampSegment) segment); + segments.remove(i); + segments.addAll(i, steps); + int addedSegments = steps.size() - 1; + if (repeatIndex > i) { + repeatIndex += addedSegments; + } + i += addedSegments; + segmentCount += addedSegments; + } + return repeatIndex; + } + + private List<StepSegment> apply(RampSegment ramp) { + if (Float.compare(ramp.getStartAmplitude(), ramp.getEndAmplitude()) == 0) { + // Amplitude is the same, so return a single step to simulate this ramp. + return Arrays.asList( + new StepSegment(ramp.getStartAmplitude(), ramp.getStartFrequency(), + (int) ramp.getDuration())); + } + + List<StepSegment> steps = new ArrayList<>(); + int stepCount = (int) (ramp.getDuration() + mStepDuration - 1) / mStepDuration; + for (int i = 0; i < stepCount - 1; i++) { + float pos = (float) i / stepCount; + steps.add(new StepSegment( + interpolate(ramp.getStartAmplitude(), ramp.getEndAmplitude(), pos), + interpolate(ramp.getStartFrequency(), ramp.getEndFrequency(), pos), + mStepDuration)); + } + int duration = (int) ramp.getDuration() - mStepDuration * (stepCount - 1); + steps.add(new StepSegment(ramp.getEndAmplitude(), ramp.getEndFrequency(), duration)); + return steps; + } + + private static float interpolate(float start, float end, float position) { + return start + position * (end - start); + } +} diff --git a/services/core/java/com/android/server/vibrator/StepToRampAdapter.java b/services/core/java/com/android/server/vibrator/StepToRampAdapter.java new file mode 100644 index 000000000000..f78df9208fbd --- /dev/null +++ b/services/core/java/com/android/server/vibrator/StepToRampAdapter.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.vibrator; + +import android.hardware.vibrator.IVibrator; +import android.os.VibratorInfo; +import android.os.vibrator.RampSegment; +import android.os.vibrator.StepSegment; +import android.os.vibrator.VibrationEffectSegment; + +import java.util.List; + +/** + * Adapter that converts step segments that should be handled as PWLEs to ramp segments. + * + * <p>This leaves the list unchanged if the device do not have compose PWLE capability. + */ +final class StepToRampAdapter implements VibrationEffectAdapters.SegmentsAdapter<VibratorInfo> { + @Override + public int apply(List<VibrationEffectSegment> segments, int repeatIndex, + VibratorInfo info) { + if (!info.hasCapability(IVibrator.CAP_COMPOSE_PWLE_EFFECTS)) { + // The vibrator do not have PWLE capability, so keep the segments unchanged. + return repeatIndex; + } + int segmentCount = segments.size(); + // Convert steps that require frequency control to ramps. + for (int i = 0; i < segmentCount; i++) { + VibrationEffectSegment segment = segments.get(i); + if ((segment instanceof StepSegment) + && ((StepSegment) segment).getFrequency() != 0) { + segments.set(i, apply((StepSegment) segment)); + } + } + // Convert steps that are next to ramps to also become ramps, so they can be composed + // together in the same PWLE waveform. + for (int i = 1; i < segmentCount; i++) { + if (segments.get(i) instanceof RampSegment) { + for (int j = i - 1; j >= 0 && (segments.get(j) instanceof StepSegment); j--) { + segments.set(j, apply((StepSegment) segments.get(j))); + } + } + } + return repeatIndex; + } + + private RampSegment apply(StepSegment segment) { + return new RampSegment(segment.getAmplitude(), segment.getAmplitude(), + segment.getFrequency(), segment.getFrequency(), (int) segment.getDuration()); + } +} diff --git a/services/core/java/com/android/server/vibrator/VibrationEffectAdapters.java b/services/core/java/com/android/server/vibrator/VibrationEffectAdapters.java new file mode 100644 index 000000000000..446d9810ff19 --- /dev/null +++ b/services/core/java/com/android/server/vibrator/VibrationEffectAdapters.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.vibrator; + +import android.os.VibrationEffect; +import android.os.vibrator.VibrationEffectSegment; + +import java.util.ArrayList; +import java.util.List; + +/** + * Helpers to adapt a {@link VibrationEffect} to generic modifiers (e.g. device capabilities, + * user settings, etc). + */ +public final class VibrationEffectAdapters { + + /** + * Function that applies a generic modifier to a sequence of {@link VibrationEffectSegment}. + * + * @param <T> The type of modifiers this adapter accepts. + */ + public interface SegmentsAdapter<T> { + + /** + * Add and/or remove segments to the given {@link VibrationEffectSegment} list based on the + * given modifier. + * + * <p>This returns the new {@code repeatIndex} to be used together with the updated list to + * specify an equivalent {@link VibrationEffect}. + * + * @param segments List of {@link VibrationEffectSegment} to be modified. + * @param repeatIndex Repeat index on the current segment list. + * @param modifier The modifier to be applied to the sequence of segments. + * @return The new repeat index on the modifies list. + */ + int apply(List<VibrationEffectSegment> segments, int repeatIndex, T modifier); + } + + /** + * Function that applies a generic modifier to a {@link VibrationEffect}. + * + * @param <T> The type of modifiers this adapter accepts. + */ + public interface EffectAdapter<T> { + + /** Applies the modifier to given {@link VibrationEffect}, returning the new effect. */ + VibrationEffect apply(VibrationEffect effect, T modifier); + } + + /** + * Applies a sequence of {@link SegmentsAdapter} to the segments of a given + * {@link VibrationEffect}, in order. + * + * @param effect The effect to be adapted to given modifier. + * @param adapters The sequence of adapters to be applied to given {@link VibrationEffect}. + * @param modifier The modifier to be passed to each adapter that describes the conditions the + * {@link VibrationEffect} needs to be adapted to (e.g. device capabilities, + * user settings, etc). + */ + public static <T> VibrationEffect apply(VibrationEffect effect, + List<SegmentsAdapter<T>> adapters, T modifier) { + if (!(effect instanceof VibrationEffect.Composed)) { + // Segments adapters can only be applied to Composed effects. + return effect; + } + + VibrationEffect.Composed composed = (VibrationEffect.Composed) effect; + List<VibrationEffectSegment> newSegments = new ArrayList<>(composed.getSegments()); + int newRepeatIndex = composed.getRepeatIndex(); + + int adapterCount = adapters.size(); + for (int i = 0; i < adapterCount; i++) { + newRepeatIndex = adapters.get(i).apply(newSegments, newRepeatIndex, modifier); + } + + return new VibrationEffect.Composed(newSegments, newRepeatIndex); + } +} diff --git a/services/core/java/com/android/server/vibrator/VibrationEffectModifier.java b/services/core/java/com/android/server/vibrator/VibrationEffectModifier.java deleted file mode 100644 index d287c8faa34d..000000000000 --- a/services/core/java/com/android/server/vibrator/VibrationEffectModifier.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.vibrator; - -import android.os.VibrationEffect; - -/** Function that applies a generic modifier to a {@link VibrationEffect}. */ -interface VibrationEffectModifier<T> { - - /** Applies the modifier to given {@link VibrationEffect}. */ - VibrationEffect apply(VibrationEffect effect, T modifier); -} diff --git a/services/core/java/com/android/server/vibrator/VibrationThread.java b/services/core/java/com/android/server/vibrator/VibrationThread.java index b3f1bcd444cc..e3672f4d497c 100644 --- a/services/core/java/com/android/server/vibrator/VibrationThread.java +++ b/services/core/java/com/android/server/vibrator/VibrationThread.java @@ -95,7 +95,7 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient { private final WorkSource mWorkSource = new WorkSource(); private final PowerManager.WakeLock mWakeLock; private final IBatteryStats mBatteryStatsService; - private final VibrationEffectModifier<VibratorInfo> mDeviceEffectAdapter = + private final DeviceVibrationEffectAdapter mDeviceEffectAdapter = new DeviceVibrationEffectAdapter(); private final Vibration mVibration; private final VibrationCallbacks mCallbacks; diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 3969a5f8d50c..d4df2f258a04 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -7013,7 +7013,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // TODO(b/181207944): Consider removing the if condition and always run // resolveFixedOrientationConfiguration() since this should be applied for all cases. if (isFixedOrientationLetterboxAllowed) { - resolveFixedOrientationConfiguration(newParentConfiguration); + resolveFixedOrientationConfiguration(newParentConfiguration, parentWindowingMode); } if (mCompatDisplayInsets != null) { @@ -7160,16 +7160,21 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A * change and the requested orientation is different from the parent. * * <p>If letterboxed due to fixed orientation then aspect ratio restrictions are also applied - * in this methiod. + * in this method. */ - private void resolveFixedOrientationConfiguration(@NonNull Configuration newParentConfig) { + private void resolveFixedOrientationConfiguration(@NonNull Configuration newParentConfig, + int windowingMode) { mLetterboxBoundsForFixedOrientationAndAspectRatio = null; if (handlesOrientationChangeFromDescendant()) { // No need to letterbox because of fixed orientation. Display will handle // fixed-orientation requests. return; } - if (newParentConfig.windowConfiguration.getWindowingMode() == WINDOWING_MODE_PINNED) { + if (WindowConfiguration.inMultiWindowMode(windowingMode) && isResizeable()) { + // Ignore orientation request for resizable apps in multi window. + return; + } + if (windowingMode == WINDOWING_MODE_PINNED) { // PiP bounds have higher priority than the requested orientation. Otherwise the // activity may be squeezed into a small piece. return; diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 29e55df32509..5e75cebc322d 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -2835,7 +2835,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { List<IBinder> topActivityToken = new ArrayList<>(); topActivityToken.add(tokens.getActivityToken()); requester.requestAssistData(topActivityToken, true /* fetchData */, - false /* fetchScreenshot */, true /* allowFetchData */, + false /* fetchScreenshot */, false /* fetchStructure */, true /* allowFetchData */, false /* allowFetchScreenshot*/, true /* ignoreFocusCheck */, Binder.getCallingUid(), callingPackageName); diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index b7ba8f8cf3c9..81992d8934ed 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -5013,28 +5013,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } /** - * Re-parent the DisplayContent's top surface, {@link #mSurfaceControl} to the specified - * SurfaceControl. - * - * @param win The window which owns the SurfaceControl. This indicates the z-order of the - * windows of this display against the windows on the parent display. - * @param sc The new SurfaceControl, where the DisplayContent's surfaces will be re-parented to. - */ - void reparentDisplayContent(WindowState win, SurfaceControl sc) { - if (mParentWindow != null) { - mParentWindow.removeEmbeddedDisplayContent(this); - } - mParentWindow = win; - mParentWindow.addEmbeddedDisplayContent(this); - mParentSurfaceControl = sc; - if (mPortalWindowHandle == null) { - mPortalWindowHandle = createPortalWindowHandle(sc.toString()); - } - getPendingTransaction().setInputWindowInfo(sc, mPortalWindowHandle) - .reparent(mSurfaceControl, sc); - } - - /** * Get the window which owns the surface that this DisplayContent is re-parented to. * * @return the parent window. diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 70f2d64e89aa..977df93412f8 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -1453,8 +1453,7 @@ public class DisplayPolicy { } void onDisplayInfoChanged(DisplayInfo info) { - mSystemGestures.screenWidth = info.logicalWidth; - mSystemGestures.screenHeight = info.logicalHeight; + mSystemGestures.onDisplayInfoChanged(info); } private void layoutStatusBar(DisplayFrames displayFrames, Rect contentFrame) { diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java index c6cd5606770e..e28201245d9b 100644 --- a/services/core/java/com/android/server/wm/Session.java +++ b/services/core/java/com/android/server/wm/Session.java @@ -609,11 +609,6 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { } @Override - public void reparentDisplayContent(IWindow window, SurfaceControl sc, int displayId) { - mService.reparentDisplayContent(window, sc, displayId); - } - - @Override public void updateDisplayContentLocation(IWindow window, int x, int y, int displayId) { mService.updateDisplayContentLocation(window, x, y, displayId); } diff --git a/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java b/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java index f3859b41b6fd..513b1b715a27 100644 --- a/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java +++ b/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java @@ -17,6 +17,7 @@ package com.android.server.wm; import android.content.Context; +import android.content.res.Resources; import android.graphics.Rect; import android.graphics.Region; import android.hardware.display.DisplayManagerGlobal; @@ -65,6 +66,7 @@ class SystemGesturesPointerEventListener implements PointerEventListener { int screenHeight; int screenWidth; + private DisplayInfo mTmpDisplayInfo = new DisplayInfo(); private int mDownPointers; private boolean mSwipeFireable; private boolean mDebugFireable; @@ -75,23 +77,31 @@ class SystemGesturesPointerEventListener implements PointerEventListener { mContext = checkNull("context", context); mHandler = handler; mCallbacks = checkNull("callbacks", callbacks); + onConfigurationChanged(); + } + void onDisplayInfoChanged(DisplayInfo info) { + screenWidth = info.logicalWidth; + screenHeight = info.logicalHeight; onConfigurationChanged(); } void onConfigurationChanged() { - mSwipeStartThreshold = mContext.getResources() - .getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height); - + final Resources r = mContext.getResources(); final Display display = DisplayManagerGlobal.getInstance() .getRealDisplay(Display.DEFAULT_DISPLAY); + display.getDisplayInfo(mTmpDisplayInfo); + mSwipeStartThreshold = mTmpDisplayInfo.logicalWidth > mTmpDisplayInfo.logicalHeight + ? r.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height_landscape) + : r.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height_portrait); + final DisplayCutout displayCutout = display.getCutout(); if (displayCutout != null) { final Rect bounds = displayCutout.getBoundingRectTop(); if (!bounds.isEmpty()) { // Expand swipe start threshold such that we can catch touches that just start below // the notch area - mDisplayCutoutTouchableRegionSize = mContext.getResources().getDimensionPixelSize( + mDisplayCutoutTouchableRegionSize = r.getDimensionPixelSize( com.android.internal.R.dimen.display_cutout_touchable_region_size); mSwipeStartThreshold += mDisplayCutoutTouchableRegionSize; } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 7df5744cdf15..1042a0b13e1c 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2329,6 +2329,17 @@ public class WindowManagerService extends IWindowManager.Stub } result |= RELAYOUT_RES_SURFACE_CHANGED; if (!win.mWillReplaceWindow) { + // When FLAG_SHOW_WALLPAPER flag is removed from a window, we usually set a flag + // in DC#pendingLayoutChanges and update the wallpaper target later. + // However it's possible that FLAG_SHOW_WALLPAPER flag is removed from a window + // when the window is about to exit, so we update the wallpaper target + // immediately here. Otherwise this window will be stuck in exiting and its + // surface remains on the screen. + // TODO(b/189856716): Allow destroying surface even if it belongs to the + // keyguard target. + if (wallpaperMayMove) { + displayContent.mWallpaperController.adjustWallpaperWindows(); + } focusMayChange = tryStartExitingAnimation(win, winAnimator, focusMayChange); } } @@ -6960,32 +6971,6 @@ public class WindowManagerService extends IWindowManager.Stub } } - /** @see Session#reparentDisplayContent(IWindow, SurfaceControl, int) */ - void reparentDisplayContent(IWindow client, SurfaceControl sc, int displayId) { - checkCallerOwnsDisplay(displayId); - - synchronized (mGlobalLock) { - int uid = Binder.getCallingUid(); - final long token = Binder.clearCallingIdentity(); - try { - final WindowState win = windowForClientLocked(null, client, false); - if (win == null) { - ProtoLog.w(WM_ERROR, "Bad requesting window %s", client); - return; - } - getDisplayContentOrCreate(displayId, null).reparentDisplayContent(win, sc); - // Notifies AccessibilityController to re-compute the window observer of - // this embedded display - if (mAccessibilityController != null) { - mAccessibilityController.handleWindowObserverOfEmbeddedDisplay( - displayId, win, uid); - } - } finally { - Binder.restoreCallingIdentity(token); - } - } - } - /** @see Session#updateDisplayContentLocation(IWindow, int, int, int) */ void updateDisplayContentLocation(IWindow client, int x, int y, int displayId) { checkCallerOwnsDisplay(displayId); diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 5f4798650184..20a992d244c5 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -1500,7 +1500,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } boolean didFrameInsetsChange = setReportResizeHints(); - boolean configChanged = !isLastConfigReportedToClient(); + // The latest configuration will be returned by the out parameter of relayout, so it is + // unnecessary to report resize if this window is running relayout. + final boolean configChanged = !mInRelayout && !isLastConfigReportedToClient(); if (DEBUG_CONFIGURATION && configChanged) { Slog.v(TAG_WM, "Win " + this + " config changed: " + getConfiguration()); } diff --git a/services/tests/mockingservicestests/Android.bp b/services/tests/mockingservicestests/Android.bp index 64b9a63991b4..24e11af23798 100644 --- a/services/tests/mockingservicestests/Android.bp +++ b/services/tests/mockingservicestests/Android.bp @@ -31,7 +31,10 @@ android_test { name: "FrameworksMockingServicesTests", defaults: ["FrameworkMockingServicesTests-jni-defaults"], - srcs: ["src/**/*.java", "src/**/*.kt"], + srcs: [ + "src/**/*.java", + "src/**/*.kt", + ], static_libs: [ "services.core", @@ -41,6 +44,7 @@ android_test { "service-jobscheduler", "service-permission.impl", "service-blobstore", + "service-appsearch", "androidx.test.runner", "androidx.test.ext.truth", "mockito-target-extended-minus-junit4", diff --git a/services/tests/mockingservicestests/src/com/android/server/appsearch/AppSearchConfigTest.java b/services/tests/mockingservicestests/src/com/android/server/appsearch/AppSearchConfigTest.java new file mode 100644 index 000000000000..c4860287c567 --- /dev/null +++ b/services/tests/mockingservicestests/src/com/android/server/appsearch/AppSearchConfigTest.java @@ -0,0 +1,286 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.appsearch; + +import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR; + +import static com.google.common.truth.Truth.assertThat; + +import android.provider.DeviceConfig; + +import com.android.server.testables.TestableDeviceConfig; + +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +/** + * Tests for {@link AppSearchConfig}. + * + * <p>Build/Install/Run: atest FrameworksMockingServicesTests:AppSearchConfigTest + */ +public class AppSearchConfigTest { + @Rule + public final TestableDeviceConfig.TestableDeviceConfigRule + mDeviceConfigRule = new TestableDeviceConfig.TestableDeviceConfigRule(); + + @Test + public void testDefaultValues_allCachedValue() { + AppSearchConfig appSearchConfig = AppSearchConfig.create(DIRECT_EXECUTOR); + + assertThat(appSearchConfig.getCachedMinTimeIntervalBetweenSamplesMillis()).isEqualTo( + AppSearchConfig.DEFAULT_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS); + assertThat(appSearchConfig.getCachedSamplingIntervalDefault()).isEqualTo( + AppSearchConfig.DEFAULT_SAMPLING_INTERVAL); + assertThat(appSearchConfig.getCachedSamplingIntervalForBatchCallStats()).isEqualTo( + AppSearchConfig.DEFAULT_SAMPLING_INTERVAL); + assertThat(appSearchConfig.getCachedSamplingIntervalForPutDocumentStats()).isEqualTo( + AppSearchConfig.DEFAULT_SAMPLING_INTERVAL); + } + + @Test + public void testCustomizedValue_minTimeIntervalBetweenSamplesMillis() { + final long minTimeIntervalBetweenSamplesMillis = -1; + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, + AppSearchConfig.KEY_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS, + Long.toString(minTimeIntervalBetweenSamplesMillis), + false); + + AppSearchConfig appSearchConfig = AppSearchConfig.create(DIRECT_EXECUTOR); + + assertThat(appSearchConfig.getCachedMinTimeIntervalBetweenSamplesMillis()).isEqualTo( + minTimeIntervalBetweenSamplesMillis); + } + + @Test + public void testCustomizedValueOverride_minTimeIntervalBetweenSamplesMillis() { + long minTimeIntervalBetweenSamplesMillis = -1; + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, + AppSearchConfig.KEY_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS, + Long.toString(minTimeIntervalBetweenSamplesMillis), + false); + AppSearchConfig appSearchConfig = AppSearchConfig.create(DIRECT_EXECUTOR); + + minTimeIntervalBetweenSamplesMillis = -2; + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, + AppSearchConfig.KEY_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS, + Long.toString(minTimeIntervalBetweenSamplesMillis), + false); + + assertThat(appSearchConfig.getCachedMinTimeIntervalBetweenSamplesMillis()).isEqualTo( + minTimeIntervalBetweenSamplesMillis); + } + + @Test + public void testCustomizedValue_allSamplingIntervals() { + final int samplingIntervalDefault = -1; + final int samplingIntervalPutDocumentStats = -2; + final int samplingIntervalBatchCallStats = -3; + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, + AppSearchConfig.KEY_SAMPLING_INTERVAL_DEFAULT, + Integer.toString(samplingIntervalDefault), + false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, + AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_PUT_DOCUMENT_STATS, + Integer.toString(samplingIntervalPutDocumentStats), + false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, + AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_BATCH_CALL_STATS, + Integer.toString(samplingIntervalBatchCallStats), + false); + + AppSearchConfig appSearchConfig = AppSearchConfig.create(DIRECT_EXECUTOR); + + assertThat(appSearchConfig.getCachedSamplingIntervalDefault()).isEqualTo( + samplingIntervalDefault); + assertThat(appSearchConfig.getCachedSamplingIntervalForPutDocumentStats()).isEqualTo( + samplingIntervalPutDocumentStats); + assertThat(appSearchConfig.getCachedSamplingIntervalForBatchCallStats()).isEqualTo( + samplingIntervalBatchCallStats); + } + + @Test + public void testCustomizedValueOverride_allSamplingIntervals() { + int samplingIntervalDefault = -1; + int samplingIntervalPutDocumentStats = -2; + int samplingIntervalBatchCallStats = -3; + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, + AppSearchConfig.KEY_SAMPLING_INTERVAL_DEFAULT, + Integer.toString(samplingIntervalDefault), + false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, + AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_PUT_DOCUMENT_STATS, + Integer.toString(samplingIntervalPutDocumentStats), + false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, + AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_BATCH_CALL_STATS, + Integer.toString(samplingIntervalBatchCallStats), + false); + AppSearchConfig appSearchConfig = AppSearchConfig.create(DIRECT_EXECUTOR); + + // Overrides + samplingIntervalDefault = -4; + samplingIntervalPutDocumentStats = -5; + samplingIntervalBatchCallStats = -6; + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, + AppSearchConfig.KEY_SAMPLING_INTERVAL_DEFAULT, + Integer.toString(samplingIntervalDefault), + false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, + AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_PUT_DOCUMENT_STATS, + Integer.toString(samplingIntervalPutDocumentStats), + false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, + AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_BATCH_CALL_STATS, + Integer.toString(samplingIntervalBatchCallStats), + false); + + assertThat(appSearchConfig.getCachedSamplingIntervalDefault()).isEqualTo( + samplingIntervalDefault); + assertThat(appSearchConfig.getCachedSamplingIntervalForPutDocumentStats()).isEqualTo( + samplingIntervalPutDocumentStats); + assertThat(appSearchConfig.getCachedSamplingIntervalForBatchCallStats()).isEqualTo( + samplingIntervalBatchCallStats); + } + + /** + * Tests if we fall back to {@link AppSearchConfig#DEFAULT_SAMPLING_INTERVAL} if both default + * sampling + * interval and custom value are not set in DeviceConfig, and there is some other sampling + * interval + * set. + */ + @Test + public void testFallbackToDefaultSamplingValue_useHardCodedDefault() { + final int samplingIntervalPutDocumentStats = -1; + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, + AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_PUT_DOCUMENT_STATS, + Integer.toString(samplingIntervalPutDocumentStats), + false); + + AppSearchConfig appSearchConfig = AppSearchConfig.create(DIRECT_EXECUTOR); + + assertThat(appSearchConfig.getCachedSamplingIntervalForPutDocumentStats()).isEqualTo( + samplingIntervalPutDocumentStats); + assertThat(appSearchConfig.getCachedSamplingIntervalForBatchCallStats()).isEqualTo( + AppSearchConfig.DEFAULT_SAMPLING_INTERVAL); + } + + // Tests if we fall back to configured default sampling interval if custom value is not set in + // DeviceConfig. + @Test + public void testFallbackDefaultSamplingValue_useConfiguredDefault() { + final int samplingIntervalPutDocumentStats = -1; + final int samplingIntervalDefault = -2; + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, + AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_PUT_DOCUMENT_STATS, + Integer.toString(samplingIntervalPutDocumentStats), + false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, + AppSearchConfig.KEY_SAMPLING_INTERVAL_DEFAULT, + Integer.toString(samplingIntervalDefault), + false); + + AppSearchConfig appSearchConfig = AppSearchConfig.create(DIRECT_EXECUTOR); + + assertThat(appSearchConfig.getCachedSamplingIntervalForPutDocumentStats()).isEqualTo( + samplingIntervalPutDocumentStats); + assertThat(appSearchConfig.getCachedSamplingIntervalForBatchCallStats()).isEqualTo( + samplingIntervalDefault); + } + + // Tests that cached values should reflect latest values in DeviceConfig. + @Test + public void testFallbackDefaultSamplingValue_defaultValueChanged() { + int samplingIntervalPutDocumentStats = -1; + int samplingIntervalDefault = -2; + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, + AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_PUT_DOCUMENT_STATS, + Integer.toString(samplingIntervalPutDocumentStats), + false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, + AppSearchConfig.KEY_SAMPLING_INTERVAL_DEFAULT, + Integer.toString(samplingIntervalDefault), + false); + + AppSearchConfig appSearchConfig = AppSearchConfig.create(DIRECT_EXECUTOR); + + // Sampling values changed. + samplingIntervalPutDocumentStats = -3; + samplingIntervalDefault = -4; + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, + AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_PUT_DOCUMENT_STATS, + Integer.toString(samplingIntervalPutDocumentStats), + false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, + AppSearchConfig.KEY_SAMPLING_INTERVAL_DEFAULT, + Integer.toString(samplingIntervalDefault), + false); + + assertThat(appSearchConfig.getCachedSamplingIntervalForPutDocumentStats()).isEqualTo( + samplingIntervalPutDocumentStats); + assertThat(appSearchConfig.getCachedSamplingIntervalForBatchCallStats()).isEqualTo( + samplingIntervalDefault); + } + + // Tests default sampling interval won't affect custom sampling intervals if they are set. + @Test + public void testShouldNotFallBack_ifValueConfigured() { + int samplingIntervalDefault = -1; + int samplingIntervalBatchCallStats = -2; + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, + AppSearchConfig.KEY_SAMPLING_INTERVAL_DEFAULT, + Integer.toString(samplingIntervalDefault), + false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, + AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_BATCH_CALL_STATS, + Integer.toString(samplingIntervalBatchCallStats), + false); + + AppSearchConfig appSearchConfig = AppSearchConfig.create(DIRECT_EXECUTOR); + + // Default sampling interval changed. + samplingIntervalDefault = -3; + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, + AppSearchConfig.KEY_SAMPLING_INTERVAL_DEFAULT, + Integer.toString(samplingIntervalDefault), + false); + + assertThat(appSearchConfig.getCachedSamplingIntervalForBatchCallStats()).isEqualTo( + samplingIntervalBatchCallStats); + } + + @Test + public void testNotUsable_afterClose() { + AppSearchConfig appSearchConfig = AppSearchConfig.create(DIRECT_EXECUTOR); + + appSearchConfig.close(); + + Assert.assertThrows("Trying to use a closed AppSearchConfig instance.", + IllegalStateException.class, + () -> appSearchConfig.getCachedMinTimeIntervalBetweenSamplesMillis()); + Assert.assertThrows("Trying to use a closed AppSearchConfig instance.", + IllegalStateException.class, + () -> appSearchConfig.getCachedSamplingIntervalDefault()); + Assert.assertThrows("Trying to use a closed AppSearchConfig instance.", + IllegalStateException.class, + () -> appSearchConfig.getCachedSamplingIntervalForBatchCallStats()); + Assert.assertThrows("Trying to use a closed AppSearchConfig instance.", + IllegalStateException.class, + () -> appSearchConfig.getCachedSamplingIntervalForPutDocumentStats()); + } +} diff --git a/services/tests/servicestests/src/com/android/server/appop/AppOpsActiveWatcherTest.java b/services/tests/servicestests/src/com/android/server/appop/AppOpsActiveWatcherTest.java index 98bc0673f79c..a2aaccc679dc 100644 --- a/services/tests/servicestests/src/com/android/server/appop/AppOpsActiveWatcherTest.java +++ b/services/tests/servicestests/src/com/android/server/appop/AppOpsActiveWatcherTest.java @@ -20,6 +20,8 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; @@ -66,7 +68,8 @@ public class AppOpsActiveWatcherTest { // Verify that we got called for the op being active verify(listener, timeout(NOTIFICATION_TIMEOUT_MILLIS) .times(1)).onOpActiveChanged(eq(AppOpsManager.OPSTR_CAMERA), - eq(Process.myUid()), eq(getContext().getPackageName()), eq(true)); + eq(Process.myUid()), eq(getContext().getPackageName()), + isNull(), eq(true), anyInt(), anyInt()); // This should be the only callback we got verifyNoMoreInteractions(listener); @@ -84,7 +87,8 @@ public class AppOpsActiveWatcherTest { // Verify that we got called for the op being active verify(listener, timeout(NOTIFICATION_TIMEOUT_MILLIS) .times(1)).onOpActiveChanged(eq(AppOpsManager.OPSTR_CAMERA), - eq(Process.myUid()), eq(getContext().getPackageName()), eq(false)); + eq(Process.myUid()), eq(getContext().getPackageName()), isNull(), + eq(false), anyInt(), anyInt()); // Verify that the op is not active assertThat(appOpsManager.isOperationActive(AppOpsManager.OP_CAMERA, @@ -121,7 +125,8 @@ public class AppOpsActiveWatcherTest { // We should get the callback again (and since we reset the listener, we therefore expect 1) verify(listener, timeout(NOTIFICATION_TIMEOUT_MILLIS) .times(1)).onOpActiveChanged(eq(AppOpsManager.OPSTR_CAMERA), - eq(Process.myUid()), eq(getContext().getPackageName()), eq(true)); + eq(Process.myUid()), eq(getContext().getPackageName()), isNull(), + eq(true), anyInt(), anyInt()); // Finish up appOpsManager.finishOp(AppOpsManager.OP_CAMERA); diff --git a/services/tests/servicestests/src/com/android/server/appsearch/stats/PlatformLoggerTest.java b/services/tests/servicestests/src/com/android/server/appsearch/stats/PlatformLoggerTest.java index 747dd1df1869..734f05a8de91 100644 --- a/services/tests/servicestests/src/com/android/server/appsearch/stats/PlatformLoggerTest.java +++ b/services/tests/servicestests/src/com/android/server/appsearch/stats/PlatformLoggerTest.java @@ -46,7 +46,7 @@ import java.security.NoSuchAlgorithmException; public class PlatformLoggerTest { private static final int TEST_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS = 100; - private static final int TEST_DEFAULT_SAMPLING_RATIO = 10; + private static final int TEST_DEFAULT_SAMPLING_INTERVAL = 10; private static final String TEST_PACKAGE_NAME = "packageName"; private MockPackageManager mMockPackageManager = new MockPackageManager(); private Context mContext; @@ -72,63 +72,63 @@ public class PlatformLoggerTest { } @Test - public void testCreateExtraStatsLocked_nullSamplingRatioMap_returnsDefaultSamplingRatio() { + public void testCreateExtraStatsLocked_nullSamplingIntervalMap_returnsDefault() { PlatformLogger logger = new PlatformLogger( ApplicationProvider.getApplicationContext(), UserHandle.of(UserHandle.USER_NULL), new PlatformLogger.Config( TEST_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS, - TEST_DEFAULT_SAMPLING_RATIO, - /*samplingRatios=*/ new SparseIntArray())); + TEST_DEFAULT_SAMPLING_INTERVAL, + /*samplingIntervals=*/ new SparseIntArray())); - // Make sure default sampling ratio is used if samplingMap is not provided. + // Make sure default sampling interval is used if samplingMap is not provided. assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME, - CallStats.CALL_TYPE_UNKNOWN).mSamplingRatio).isEqualTo( - TEST_DEFAULT_SAMPLING_RATIO); + CallStats.CALL_TYPE_UNKNOWN).mSamplingInterval).isEqualTo( + TEST_DEFAULT_SAMPLING_INTERVAL); assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME, - CallStats.CALL_TYPE_INITIALIZE).mSamplingRatio).isEqualTo( - TEST_DEFAULT_SAMPLING_RATIO); + CallStats.CALL_TYPE_INITIALIZE).mSamplingInterval).isEqualTo( + TEST_DEFAULT_SAMPLING_INTERVAL); assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME, - CallStats.CALL_TYPE_SEARCH).mSamplingRatio).isEqualTo( - TEST_DEFAULT_SAMPLING_RATIO); + CallStats.CALL_TYPE_SEARCH).mSamplingInterval).isEqualTo( + TEST_DEFAULT_SAMPLING_INTERVAL); assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME, - CallStats.CALL_TYPE_FLUSH).mSamplingRatio).isEqualTo( - TEST_DEFAULT_SAMPLING_RATIO); + CallStats.CALL_TYPE_FLUSH).mSamplingInterval).isEqualTo( + TEST_DEFAULT_SAMPLING_INTERVAL); } @Test - public void testCreateExtraStatsLocked_with_samplingRatioMap_returnsConfiguredSamplingRatio() { - int putDocumentSamplingRatio = 1; - int querySamplingRatio = 2; - final SparseIntArray samplingRatios = new SparseIntArray(); - samplingRatios.put(CallStats.CALL_TYPE_PUT_DOCUMENT, putDocumentSamplingRatio); - samplingRatios.put(CallStats.CALL_TYPE_SEARCH, querySamplingRatio); + public void testCreateExtraStatsLocked_with_samplingIntervalMap_returnsConfigured() { + int putDocumentSamplingInterval = 1; + int querySamplingInterval = 2; + final SparseIntArray samplingIntervals = new SparseIntArray(); + samplingIntervals.put(CallStats.CALL_TYPE_PUT_DOCUMENT, putDocumentSamplingInterval); + samplingIntervals.put(CallStats.CALL_TYPE_SEARCH, querySamplingInterval); PlatformLogger logger = new PlatformLogger( ApplicationProvider.getApplicationContext(), UserHandle.of(UserHandle.USER_NULL), new PlatformLogger.Config( TEST_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS, - TEST_DEFAULT_SAMPLING_RATIO, - samplingRatios)); + TEST_DEFAULT_SAMPLING_INTERVAL, + samplingIntervals)); - // The default sampling ratio should be used if no sampling ratio is + // The default sampling interval should be used if no sampling interval is // provided for certain call type. assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME, - CallStats.CALL_TYPE_INITIALIZE).mSamplingRatio).isEqualTo( - TEST_DEFAULT_SAMPLING_RATIO); + CallStats.CALL_TYPE_INITIALIZE).mSamplingInterval).isEqualTo( + TEST_DEFAULT_SAMPLING_INTERVAL); assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME, - CallStats.CALL_TYPE_FLUSH).mSamplingRatio).isEqualTo( - TEST_DEFAULT_SAMPLING_RATIO); + CallStats.CALL_TYPE_FLUSH).mSamplingInterval).isEqualTo( + TEST_DEFAULT_SAMPLING_INTERVAL); - // The configured sampling ratio is used if sampling ratio is available + // The configured sampling interval is used if sampling interval is available // for certain call type. assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME, - CallStats.CALL_TYPE_PUT_DOCUMENT).mSamplingRatio).isEqualTo( - putDocumentSamplingRatio); + CallStats.CALL_TYPE_PUT_DOCUMENT).mSamplingInterval).isEqualTo( + putDocumentSamplingInterval); assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME, - CallStats.CALL_TYPE_SEARCH).mSamplingRatio).isEqualTo( - querySamplingRatio); + CallStats.CALL_TYPE_SEARCH).mSamplingInterval).isEqualTo( + querySamplingInterval); } @Test @@ -202,16 +202,16 @@ public class PlatformLoggerTest { } @Test - public void testShouldLogForTypeLocked_trueWhenSampleRatioIsOne() { - final int samplingRatio = 1; + public void testShouldLogForTypeLocked_trueWhenSampleIntervalIsOne() { + final int samplingInterval = 1; final String testPackageName = "packageName"; PlatformLogger logger = new PlatformLogger( ApplicationProvider.getApplicationContext(), UserHandle.of(UserHandle.USER_NULL), new PlatformLogger.Config( TEST_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS, - samplingRatio, - /*samplingRatios=*/ new SparseIntArray())); + samplingInterval, + /*samplingIntervals=*/ new SparseIntArray())); // Sample should always be logged for the first time if sampling is disabled(value is one). assertThat(logger.shouldLogForTypeLocked(CallStats.CALL_TYPE_PUT_DOCUMENT)).isTrue(); @@ -220,18 +220,18 @@ public class PlatformLoggerTest { } @Test - public void testShouldLogForTypeLocked_falseWhenSampleRatioIsNegative() { - final int samplingRatio = -1; + public void testShouldLogForTypeLocked_falseWhenSampleIntervalIsNegative() { + final int samplingInterval = -1; final String testPackageName = "packageName"; PlatformLogger logger = new PlatformLogger( ApplicationProvider.getApplicationContext(), UserHandle.of(UserHandle.USER_NULL), new PlatformLogger.Config( TEST_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS, - samplingRatio, - /*samplingRatios=*/ new SparseIntArray())); + samplingInterval, + /*samplingIntervals=*/ new SparseIntArray())); - // Makes sure sample will be excluded due to sampling if sample ratio is negative. + // Makes sure sample will be excluded due to sampling if sample interval is negative. assertThat(logger.shouldLogForTypeLocked(CallStats.CALL_TYPE_PUT_DOCUMENT)).isFalse(); // Skipped count should be 0 since it doesn't pass the sampling. assertThat(logger.createExtraStatsLocked(testPackageName, @@ -241,7 +241,7 @@ public class PlatformLoggerTest { @Test public void testShouldLogForTypeLocked_falseWhenWithinCoolOffInterval() { // Next sample won't be excluded due to sampling. - final int samplingRatio = 1; + final int samplingInterval = 1; // Next sample would guaranteed to be too close. final int minTimeIntervalBetweenSamplesMillis = Integer.MAX_VALUE; final String testPackageName = "packageName"; @@ -250,8 +250,8 @@ public class PlatformLoggerTest { UserHandle.of(UserHandle.USER_NULL), new PlatformLogger.Config( minTimeIntervalBetweenSamplesMillis, - samplingRatio, - /*samplingRatios=*/ new SparseIntArray())); + samplingInterval, + /*samplingIntervals=*/ new SparseIntArray())); logger.setLastPushTimeMillisLocked(SystemClock.elapsedRealtime()); // Makes sure sample will be excluded due to rate limiting if samples are too close. @@ -263,7 +263,7 @@ public class PlatformLoggerTest { @Test public void testShouldLogForTypeLocked_trueWhenOutsideOfCoolOffInterval() { // Next sample won't be excluded due to sampling. - final int samplingRatio = 1; + final int samplingInterval = 1; // Next sample would guaranteed to be included. final int minTimeIntervalBetweenSamplesMillis = 0; final String testPackageName = "packageName"; @@ -272,8 +272,8 @@ public class PlatformLoggerTest { UserHandle.of(UserHandle.USER_NULL), new PlatformLogger.Config( minTimeIntervalBetweenSamplesMillis, - samplingRatio, - /*samplingRatios=*/ new SparseIntArray())); + samplingInterval, + /*samplingIntervals=*/ new SparseIntArray())); logger.setLastPushTimeMillisLocked(SystemClock.elapsedRealtime()); // Makes sure sample will be logged if it is not too close to previous sample. @@ -292,8 +292,8 @@ public class PlatformLoggerTest { mContext.getUser(), new PlatformLogger.Config( TEST_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS, - TEST_DEFAULT_SAMPLING_RATIO, - /*samplingRatios=*/ new SparseIntArray())); + TEST_DEFAULT_SAMPLING_INTERVAL, + /*samplingIntervals=*/ new SparseIntArray())); mMockPackageManager.mockGetPackageUidAsUser(testPackageName, mContext.getUserId(), testUid); // diff --git a/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java b/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java index 2162c0b20eac..e811c1f315fe 100644 --- a/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java @@ -5,22 +5,29 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; + import static org.testng.Assert.assertThrows; +import android.Manifest; import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.AppOpsManager; import android.app.IApplicationThread; import android.app.admin.DevicePolicyManagerInternal; +import android.content.AttributionSourceState; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.PermissionChecker; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.CrossProfileAppsInternal; @@ -34,6 +41,7 @@ import android.os.Bundle; import android.os.IBinder; import android.os.UserHandle; import android.os.UserManager; +import android.permission.PermissionCheckerManager; import android.permission.PermissionManager; import android.platform.test.annotations.Presubmit; import android.util.SparseArray; @@ -411,6 +419,18 @@ public class CrossProfileAppsServiceImplTest { } mActivityInfo.exported = false; + + // There's a bug in static mocking if the APK is large - so here is the next best thing... + doReturn(Context.PERMISSION_CHECKER_SERVICE).when(mContext) + .getSystemServiceName(PermissionCheckerManager.class); + PermissionCheckerManager permissionCheckerManager = mock(PermissionCheckerManager.class); + doReturn(PermissionChecker.PERMISSION_HARD_DENIED).when(permissionCheckerManager) + .checkPermission(eq(Manifest.permission.INTERACT_ACROSS_PROFILES), any( + AttributionSourceState.class), anyString(), anyBoolean(), anyBoolean(), + anyBoolean(), anyInt()); + doReturn(permissionCheckerManager).when(mContext).getSystemService( + Context.PERMISSION_CHECKER_SERVICE); + assertThrows( SecurityException.class, () -> diff --git a/services/tests/servicestests/src/com/android/server/vibrator/DeviceVibrationEffectAdapterTest.java b/services/tests/servicestests/src/com/android/server/vibrator/DeviceVibrationEffectAdapterTest.java index f65969833521..00b05d4ad10c 100644 --- a/services/tests/servicestests/src/com/android/server/vibrator/DeviceVibrationEffectAdapterTest.java +++ b/services/tests/servicestests/src/com/android/server/vibrator/DeviceVibrationEffectAdapterTest.java @@ -77,6 +77,38 @@ public class DeviceVibrationEffectAdapterTest { } @Test + public void testStepAndRampSegments_withoutPwleCapability_convertsRampsToSteps() { + VibrationEffect.Composed effect = new VibrationEffect.Composed(Arrays.asList( + new StepSegment(/* amplitude= */ 0, /* frequency= */ 1, /* duration= */ 10), + new StepSegment(/* amplitude= */ 0.5f, /* frequency= */ 0, /* duration= */ 100), + new RampSegment(/* startAmplitude= */ 1, /* endAmplitude= */ 0.2f, + /* startFrequency= */ -4, /* endFrequency= */ 2, /* duration= */ 10), + new RampSegment(/* startAmplitude= */ 0.8f, /* endAmplitude= */ 0.2f, + /* startFrequency= */ 0, /* endFrequency= */ 0, /* duration= */ 11), + new RampSegment(/* startAmplitude= */ 0.65f, /* endAmplitude= */ 0.65f, + /* startFrequency= */ 0, /* endFrequency= */ 1, /* duration= */ 200)), + /* repeatIndex= */ 3); + + VibrationEffect.Composed expected = new VibrationEffect.Composed(Arrays.asList( + new StepSegment(/* amplitude= */ 0, Float.NaN, /* duration= */ 10), + new StepSegment(/* amplitude= */ 0.5f, Float.NaN, /* duration= */ 100), + // 10ms ramp becomes 2 steps + new StepSegment(/* amplitude= */ 1, Float.NaN, /* duration= */ 5), + new StepSegment(/* amplitude= */ 0.2f, Float.NaN, /* duration= */ 5), + // 11ms ramp becomes 3 steps + new StepSegment(/* amplitude= */ 0.8f, Float.NaN, /* duration= */ 5), + new StepSegment(/* amplitude= */ 0.6f, Float.NaN, /* duration= */ 5), + new StepSegment(/* amplitude= */ 0.2f, Float.NaN, /* duration= */ 1), + // 200ms ramp with same amplitude becomes a single step + new StepSegment(/* amplitude= */ 0.65f, Float.NaN, /* duration= */ 200)), + // Repeat index fixed after intermediate steps added + /* repeatIndex= */ 4); + + VibratorInfo info = createVibratorInfo(EMPTY_FREQUENCY_MAPPING); + assertEquals(expected, mAdapter.apply(effect, info)); + } + + @Test public void testStepAndRampSegments_withPwleCapability_convertsStepsToRamps() { VibrationEffect.Composed effect = new VibrationEffect.Composed(Arrays.asList( new StepSegment(/* amplitude= */ 0, /* frequency= */ 1, /* duration= */ 10), @@ -131,7 +163,7 @@ public class DeviceVibrationEffectAdapterTest { } @Test - public void testStepAndRampSegments_emptyMapping_returnsSameAmplitudesAndFrequencyZero() { + public void testStepAndRampSegments_withEmptyFreqMapping_returnsSameAmplitudesAndZeroFreq() { VibrationEffect.Composed effect = new VibrationEffect.Composed(Arrays.asList( new StepSegment(/* amplitude= */ 0, /* frequency= */ 1, /* duration= */ 10), new StepSegment(/* amplitude= */ 0.5f, /* frequency= */ 0, /* duration= */ 100), @@ -142,8 +174,11 @@ public class DeviceVibrationEffectAdapterTest { /* repeatIndex= */ 2); VibrationEffect.Composed expected = new VibrationEffect.Composed(Arrays.asList( - new StepSegment(/* amplitude= */ 0, /* frequency= */ Float.NaN, /* duration= */ 10), - new StepSegment(/* amplitude= */ 0.5f, /* frequency= */ Float.NaN, + new RampSegment(/* startAmplitude= */ 0, /* endAmplitude= */ 0, + /* startFrequency= */ Float.NaN, /* endFrequency= */ Float.NaN, + /* duration= */ 10), + new RampSegment(/* startAmplitude= */ 0.5f, /* endAmplitude= */ 0.5f, + /* startFrequency= */ Float.NaN, /* endFrequency= */ Float.NaN, /* duration= */ 100), new RampSegment(/* startAmplitude= */ 0.8f, /* endAmplitude= */ 1, /* startFrequency= */ Float.NaN, /* endFrequency= */ Float.NaN, @@ -153,11 +188,13 @@ public class DeviceVibrationEffectAdapterTest { /* duration= */ 20)), /* repeatIndex= */ 2); - assertEquals(expected, mAdapter.apply(effect, createVibratorInfo(EMPTY_FREQUENCY_MAPPING))); + VibratorInfo info = createVibratorInfo(EMPTY_FREQUENCY_MAPPING, + IVibrator.CAP_COMPOSE_PWLE_EFFECTS); + assertEquals(expected, mAdapter.apply(effect, info)); } @Test - public void testStepAndRampSegments_nonEmptyMapping_returnsClippedValues() { + public void testStepAndRampSegments_withValidFreqMapping_returnsClippedValues() { VibrationEffect.Composed effect = new VibrationEffect.Composed(Arrays.asList( new StepSegment(/* amplitude= */ 0.5f, /* frequency= */ 0, /* duration= */ 10), new StepSegment(/* amplitude= */ 1, /* frequency= */ -1, /* duration= */ 100), @@ -168,15 +205,21 @@ public class DeviceVibrationEffectAdapterTest { /* repeatIndex= */ 2); VibrationEffect.Composed expected = new VibrationEffect.Composed(Arrays.asList( - new StepSegment(/* amplitude= */ 0.5f, /* frequency= */ 150, /* duration= */ 10), - new StepSegment(/* amplitude= */ 0.8f, /* frequency= */ 125, /* duration= */ 100), + new RampSegment(/* startAmplitude= */ 0.5f, /* endAmplitude= */ 0.5f, + /* startFrequency= */ 150, /* endFrequency= */ 150, + /* duration= */ 10), + new RampSegment(/* startAmplitude= */ 0.8f, /* endAmplitude= */ 0.8f, + /* startFrequency= */ 125, /* endFrequency= */ 125, + /* duration= */ 100), new RampSegment(/* startAmplitude= */ 0.1f, /* endAmplitude= */ 0.8f, /* startFrequency= */ 50, /* endFrequency= */ 200, /* duration= */ 50), new RampSegment(/* startAmplitude= */ 0.8f, /* endAmplitude= */ 0.1f, /* startFrequency= */ 200, /* endFrequency= */ 50, /* duration= */ 20)), /* repeatIndex= */ 2); - assertEquals(expected, mAdapter.apply(effect, createVibratorInfo(TEST_FREQUENCY_MAPPING))); + VibratorInfo info = createVibratorInfo(TEST_FREQUENCY_MAPPING, + IVibrator.CAP_COMPOSE_PWLE_EFFECTS); + assertEquals(expected, mAdapter.apply(effect, info)); } private static VibratorInfo createVibratorInfo(VibratorInfo.FrequencyMapping frequencyMapping, diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index aed3f52bd563..821683043804 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -26,6 +26,7 @@ import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS; import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT; import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED; import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER; +import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; @@ -546,7 +547,7 @@ public class ActivityRecordTests extends WindowTestsBase { } @Test - public void ignoreRequestedOrientationInSplitWindows() { + public void ignoreRequestedOrientationForResizableInSplitWindows() { final ActivityRecord activity = createActivityWith2LevelTask(); final Task task = activity.getTask(); final Task rootTask = activity.getRootTask(); @@ -578,13 +579,45 @@ public class ActivityRecordTests extends WindowTestsBase { } task.setBounds(bounds); + final int activityCurOrientation = activity.getConfiguration().orientation; + // Requests orientation that's different from its bounds. - activity.setRequestedOrientation( - isScreenPortrait ? SCREEN_ORIENTATION_PORTRAIT : SCREEN_ORIENTATION_LANDSCAPE); + activity.setRequestedOrientation(activityCurOrientation == ORIENTATION_LANDSCAPE + ? SCREEN_ORIENTATION_PORTRAIT : SCREEN_ORIENTATION_LANDSCAPE); - // Asserts it has orientation derived requested orientation (fixed orientation letterbox). - assertEquals(isScreenPortrait ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE, - activity.getConfiguration().orientation); + // Asserts fixed orientation request is ignored, and the orientation is not changed + // (fill Task). + assertEquals(activityCurOrientation, activity.getConfiguration().orientation); + assertFalse(activity.isLetterboxedForFixedOrientationAndAspectRatio()); + } + + @Test + public void respectRequestedOrientationForNonResizableInSplitWindows() { + final Task task = new TaskBuilder(mSupervisor) + .setCreateParentTask(true).setCreateActivity(true).build(); + final Task rootTask = task.getRootTask(); + final ActivityRecord activity = new ActivityBuilder(mAtm) + .setParentTask(task) + .setOnTop(true) + .setResizeMode(RESIZE_MODE_UNRESIZEABLE) + .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT) + .build(); + + // Task in landscape. + rootTask.setWindowingMode(WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); + task.setBounds(0, 0, 1000, 500); + assertEquals(ORIENTATION_LANDSCAPE, task.getConfiguration().orientation); + + // Asserts fixed orientation request is respected, and the orientation is not changed. + assertEquals(ORIENTATION_PORTRAIT, activity.getConfiguration().orientation); + + // Clear size compat. + activity.clearSizeCompatMode(); + activity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */); + activity.mDisplayContent.sendNewConfiguration(); + + // Relaunching the app should still respect the orientation request. + assertEquals(ORIENTATION_PORTRAIT, activity.getConfiguration().orientation); assertTrue(activity.isLetterboxedForFixedOrientationAndAspectRatio()); } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java index 152a575c847d..178fabcc6a47 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -691,39 +691,6 @@ public class WindowStateTests extends WindowTestsBase { } @Test - public void testGetTransformationMatrix() { - final int PARENT_WINDOW_OFFSET = 1; - final int DISPLAY_IN_PARENT_WINDOW_OFFSET = 2; - final int WINDOW_OFFSET = 3; - final float OFFSET_SUM = - PARENT_WINDOW_OFFSET + DISPLAY_IN_PARENT_WINDOW_OFFSET + WINDOW_OFFSET; - - final WindowState win0 = createWindow(null, TYPE_APPLICATION, "win0"); - - final DisplayContent dc = createNewDisplay(); - win0.getFrame().offsetTo(PARENT_WINDOW_OFFSET, 0); - dc.reparentDisplayContent(win0, win0.getSurfaceControl()); - dc.updateLocation(win0, DISPLAY_IN_PARENT_WINDOW_OFFSET, 0); - - final float[] values = new float[9]; - final Matrix matrix = new Matrix(); - final SurfaceControl.Transaction t = spy(StubTransaction.class); - final WindowState win1 = createWindow(null, TYPE_APPLICATION, dc, "win1"); - win1.mHasSurface = true; - win1.mSurfaceControl = mock(SurfaceControl.class); - win1.mAttrs.surfaceInsets.set(1, 2, 3, 4); - win1.getFrame().offsetTo(WINDOW_OFFSET, 0); - // Simulate layout - win1.mRelayoutCalled = true; - win1.updateSurfacePosition(t); - win1.getTransformationMatrix(values, matrix); - - matrix.getValues(values); - assertEquals(OFFSET_SUM, values[Matrix.MTRANS_X], 0f); - assertEquals(0f, values[Matrix.MTRANS_Y], 0f); - } - - @Test public void testCantReceiveTouchDuringRecentsAnimation() { final WindowState win0 = createWindow(null, TYPE_APPLICATION, "win0"); diff --git a/tools/aapt/SdkConstants.h b/tools/aapt/SdkConstants.h index 04fbbe1f1069..955581cf8655 100644 --- a/tools/aapt/SdkConstants.h +++ b/tools/aapt/SdkConstants.h @@ -46,6 +46,7 @@ enum { SDK_P = 28, SDK_Q = 29, SDK_R = 30, + SDK_S = 31, }; #endif // H_AAPT_SDK_CONSTANTS diff --git a/tools/aapt2/SdkConstants.cpp b/tools/aapt2/SdkConstants.cpp index e8873bf2d81b..96f6512fe7f5 100644 --- a/tools/aapt2/SdkConstants.cpp +++ b/tools/aapt2/SdkConstants.cpp @@ -58,7 +58,8 @@ static const std::vector<std::pair<uint16_t, ApiVersion>> sAttrIdMap = { {0x056d, SDK_O_MR1}, {0x0586, SDK_P}, {0x0606, SDK_Q}, - {0x0617, SDK_R}, + {0x0616, SDK_R}, + {0x064b, SDK_S}, }; static bool less_entry_id(const std::pair<uint16_t, ApiVersion>& p, uint16_t entryId) { diff --git a/tools/aapt2/SdkConstants.h b/tools/aapt2/SdkConstants.h index aa9aa12d2cee..6bb6ddb13bdb 100644 --- a/tools/aapt2/SdkConstants.h +++ b/tools/aapt2/SdkConstants.h @@ -56,6 +56,7 @@ enum : ApiVersion { SDK_P = 28, SDK_Q = 29, SDK_R = 30, + SDK_S = 31, }; ApiVersion FindAttributeSdkLevel(const ResourceId& id); diff --git a/tools/finalize_res/finalize_res.py b/tools/finalize_res/finalize_res.py new file mode 100755 index 000000000000..aaf01875024e --- /dev/null +++ b/tools/finalize_res/finalize_res.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 +#-*- coding: utf-8 -*- + +# Copyright (C) 2021 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the 'License'); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an 'AS IS' BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +Finalize resource values in <staging-public-group> tags + +Usage: finalize_res.py core/res/res/values/public.xml public_finalized.xml +""" + +import re, sys, codecs + +def finalize_item(raw): + global _type, _id + _id += 1 + return '<public type="%s" name="%s" id="%s" />' % (_type, raw.group(1), '0x{0:0{1}x}'.format(_id-1,8)) + +def finalize_group(raw): + global _type, _id + _type = raw.group(1) + _id = int(raw.group(2), 16) + return re.sub(r'<public name="(.+?)" */>', finalize_item, raw.group(3)) + +with open(sys.argv[1]) as f: + raw = f.read() + raw = re.sub(r'<staging-public-group type="(.+?)" first-id="(.+?)">(.+?)</staging-public-group>', finalize_group, raw, flags=re.DOTALL) + with open(sys.argv[2], "w") as f: + f.write(raw) |