diff options
545 files changed, 10368 insertions, 8964 deletions
diff --git a/Android.bp b/Android.bp index 685c69df6823..acf86a0cfa2d 100644 --- a/Android.bp +++ b/Android.bp @@ -67,6 +67,7 @@ filegroup {      name: "framework-non-updatable-sources",      srcs: [          // Java/AIDL sources under frameworks/base +        ":framework-annotations",          ":framework-blobstore-sources",          ":framework-core-sources",          ":framework-drm-sources", @@ -388,47 +389,6 @@ platform_compat_config {  }  filegroup { -    name: "framework-annotations", -    srcs: [ -        "core/java/android/annotation/AnyThread.java", -        "core/java/android/annotation/AppIdInt.java", -        "core/java/android/annotation/BytesLong.java", -        "core/java/android/annotation/CallbackExecutor.java", -        "core/java/android/annotation/CallSuper.java", -        "core/java/android/annotation/CheckResult.java", -        "core/java/android/annotation/CurrentTimeMillisLong.java", -        "core/java/android/annotation/CurrentTimeSecondsLong.java", -        "core/java/android/annotation/DrawableRes.java", -        "core/java/android/annotation/DurationMillisLong.java", -        "core/java/android/annotation/Hide.java", -        "core/java/android/annotation/IntDef.java", -        "core/java/android/annotation/IntRange.java", -        "core/java/android/annotation/LongDef.java", -        "core/java/android/annotation/MainThread.java", -        "core/java/android/annotation/NonNull.java", -        "core/java/android/annotation/Nullable.java", -        "core/java/android/annotation/RequiresNoPermission.java", -        "core/java/android/annotation/RequiresPermission.java", -        "core/java/android/annotation/SdkConstant.java", -        "core/java/android/annotation/StringDef.java", -        "core/java/android/annotation/SystemApi.java", -        "core/java/android/annotation/SystemService.java", -        "core/java/android/annotation/TestApi.java", -        "core/java/android/annotation/UserIdInt.java", -        "core/java/android/annotation/WorkerThread.java", -        "core/java/com/android/internal/annotations/GuardedBy.java", -        "core/java/com/android/internal/annotations/Immutable.java", -        "core/java/com/android/internal/annotations/VisibleForTesting.java", -    ], -} - -java_library { -    name: "framework-annotations-lib", -    srcs: [":framework-annotations"], -    sdk_version: "core_current", -} - -filegroup {      name: "framework-ike-shared-srcs",      visibility: ["//packages/modules/IPsec"],      srcs: [ diff --git a/apex/appsearch/framework/Android.bp b/apex/appsearch/framework/Android.bp index 5def55fd31ff..5bf0b84b570d 100644 --- a/apex/appsearch/framework/Android.bp +++ b/apex/appsearch/framework/Android.bp @@ -33,9 +33,10 @@ filegroup {  java_sdk_library {      name: "framework-appsearch", -    srcs: [ ":framework-appsearch-sources" ], +    srcs: [":framework-appsearch-sources"],      sdk_version: "core_platform", // TODO(b/146218515) should be module_current      impl_only_libs: ["framework-minus-apex"], // TODO(b/146218515) should be removed +    libs: ["unsupportedappusage"], // TODO(b/181887768) should be removed      defaults: ["framework-module-defaults"],      permitted_packages: ["android.app.appsearch"],      aidl: { diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java index 64ac63c2b849..c112d0efc209 100644 --- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java +++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java @@ -21,6 +21,7 @@ import android.annotation.NonNull;  import android.annotation.UserIdInt;  import android.app.appsearch.exceptions.AppSearchException;  import android.app.appsearch.util.SchemaMigrationUtil; +import android.compat.annotation.UnsupportedAppUsage;  import android.os.Bundle;  import android.os.RemoteException;  import android.os.SystemClock; @@ -295,6 +296,19 @@ public final class AppSearchSession implements Closeable {      }      /** +     * @deprecated TODO(b/181887768): Exists for dogfood transition; must be removed. +     * @hide +     */ +    @Deprecated +    @UnsupportedAppUsage +    public void getByUri( +            @NonNull GetByUriRequest request, +            @NonNull @CallbackExecutor Executor executor, +            @NonNull BatchResultCallback<String, GenericDocument> callback) { +        getByDocumentId(request.toGetByDocumentIdRequest(), executor, callback); +    } + +    /**       * Gets {@link GenericDocument} objects by document IDs in a namespace from the {@link       * AppSearchSession} database.       * @@ -489,6 +503,19 @@ public final class AppSearchSession implements Closeable {      }      /** +     * @deprecated TODO(b/181887768): Exists for dogfood transition; must be removed. +     * @hide +     */ +    @Deprecated +    @UnsupportedAppUsage +    public void remove( +            @NonNull RemoveByUriRequest request, +            @NonNull @CallbackExecutor Executor executor, +            @NonNull BatchResultCallback<String, Void> callback) { +        remove(request.toRemoveByDocumentIdRequest(), executor, callback); +    } + +    /**       * Removes {@link GenericDocument} objects by document IDs in a namespace from the {@link       * AppSearchSession} database.       * diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java b/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java index 2a941fb54833..4378a9811f12 100644 --- a/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java +++ b/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java @@ -21,6 +21,7 @@ import android.annotation.NonNull;  import android.annotation.Nullable;  import android.app.appsearch.exceptions.IllegalSchemaException;  import android.app.appsearch.util.BundleUtil; +import android.compat.annotation.UnsupportedAppUsage;  import android.os.Bundle;  import android.util.ArraySet; @@ -747,6 +748,31 @@ public final class AppSearchSchema {              }              /** +             * @deprecated TODO(b/181887768): Exists for dogfood transition; must be removed. +             * @hide +             */ +            @Deprecated +            @UnsupportedAppUsage +            public Builder(@NonNull String propertyName) { +                mBundle.putString(NAME_FIELD, propertyName); +                mBundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_DOCUMENT); +                mBundle.putInt(CARDINALITY_FIELD, CARDINALITY_OPTIONAL); +                mBundle.putBoolean(INDEX_NESTED_PROPERTIES_FIELD, false); +            } + +            /** +             * @deprecated TODO(b/181887768): Exists for dogfood transition; must be removed. +             * @hide +             */ +            @Deprecated +            @UnsupportedAppUsage +            @NonNull +            public Builder setSchemaType(@NonNull String schemaType) { +                mBundle.putString(SCHEMA_TYPE_FIELD, schemaType); +                return this; +            } + +            /**               * The cardinality of the property (whether it is optional, required or repeated).               *               * <p>If this method is not called, the default cardinality is {@link @@ -778,6 +804,18 @@ public final class AppSearchSchema {              }              /** +             * @deprecated TODO(b/181887768): Exists for dogfood transition; must be removed. +             * @hide +             */ +            @Deprecated +            @UnsupportedAppUsage +            @NonNull +            public DocumentPropertyConfig.Builder setIndexNestedProperties( +                    boolean indexNestedProperties) { +                return setShouldIndexNestedProperties(indexNestedProperties); +            } + +            /**               * Constructs a new {@link PropertyConfig} from the contents of this builder.               *               * <p>After calling this method, the builder must no longer be used. diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java b/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java index 2e427497e16d..39a48847d1c2 100644 --- a/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java +++ b/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java @@ -22,6 +22,7 @@ import android.annotation.NonNull;  import android.annotation.Nullable;  import android.annotation.SuppressLint;  import android.app.appsearch.util.BundleUtil; +import android.compat.annotation.UnsupportedAppUsage;  import android.os.Bundle;  import android.os.Parcelable;  import android.util.Log; @@ -137,6 +138,17 @@ public class GenericDocument {          return mBundle;      } +    /** +     * @deprecated TODO(b/181887768): Exists for dogfood transition; must be removed. +     * @hide +     */ +    @Deprecated +    @UnsupportedAppUsage +    @NonNull +    public String getUri() { +        return getId(); +    } +      /** Returns the unique identifier of the {@link GenericDocument}. */      @NonNull      public String getId() { diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/GetByUriRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/GetByUriRequest.java new file mode 100644 index 000000000000..7b05eac43070 --- /dev/null +++ b/apex/appsearch/framework/java/external/android/app/appsearch/GetByUriRequest.java @@ -0,0 +1,200 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app.appsearch; + +import android.annotation.NonNull; +import android.compat.annotation.UnsupportedAppUsage; +import android.util.ArrayMap; +import android.util.ArraySet; + +import com.android.internal.util.Preconditions; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +/** + * @deprecated TODO(b/181887768): Exists for dogfood transition; must be removed. + * @hide + */ +@Deprecated +public final class GetByUriRequest { +    /** +     * Schema type to be used in {@link GetByUriRequest.Builder#addProjection} to apply property +     * paths to all results, excepting any types that have had their own, specific property paths +     * set. +     */ +    public static final String PROJECTION_SCHEMA_TYPE_WILDCARD = "*"; + +    private final String mNamespace; +    private final Set<String> mIds; +    private final Map<String, List<String>> mTypePropertyPathsMap; + +    GetByUriRequest( +            @NonNull String namespace, +            @NonNull Set<String> ids, +            @NonNull Map<String, List<String>> typePropertyPathsMap) { +        mNamespace = Objects.requireNonNull(namespace); +        mIds = Objects.requireNonNull(ids); +        mTypePropertyPathsMap = Objects.requireNonNull(typePropertyPathsMap); +    } + +    /** Returns the namespace attached to the request. */ +    @NonNull +    public String getNamespace() { +        return mNamespace; +    } + +    /** Returns the set of document IDs attached to the request. */ +    @NonNull +    public Set<String> getUris() { +        return Collections.unmodifiableSet(mIds); +    } + +    /** +     * Returns a map from schema type to property paths to be used for projection. +     * +     * <p>If the map is empty, then all properties will be retrieved for all results. +     * +     * <p>Calling this function repeatedly is inefficient. Prefer to retain the Map returned by this +     * function, rather than calling it multiple times. +     */ +    @NonNull +    public Map<String, List<String>> getProjections() { +        Map<String, List<String>> copy = new ArrayMap<>(); +        for (Map.Entry<String, List<String>> entry : mTypePropertyPathsMap.entrySet()) { +            copy.put(entry.getKey(), new ArrayList<>(entry.getValue())); +        } +        return copy; +    } + +    /** +     * Returns a map from schema type to property paths to be used for projection. +     * +     * <p>If the map is empty, then all properties will be retrieved for all results. +     * +     * <p>A more efficient version of {@link #getProjections}, but it returns a modifiable map. This +     * is not meant to be unhidden and should only be used by internal classes. +     * +     * @hide +     */ +    @NonNull +    public Map<String, List<String>> getProjectionsInternal() { +        return mTypePropertyPathsMap; +    } + +    /** +     * @deprecated TODO(b/181887768): Exists for dogfood transition; must be removed. +     * @hide +     */ +    @Deprecated +    @NonNull +    public GetByDocumentIdRequest toGetByDocumentIdRequest() { +        GetByDocumentIdRequest.Builder builder = +                new GetByDocumentIdRequest.Builder(mNamespace).addIds(mIds); +        for (Map.Entry<String, List<String>> projection : mTypePropertyPathsMap.entrySet()) { +            builder.addProjection(projection.getKey(), projection.getValue()); +        } +        return builder.build(); +    } + +    /** +     * Builder for {@link GetByUriRequest} objects. +     * +     * <p>Once {@link #build} is called, the instance can no longer be used. +     */ +    public static final class Builder { +        private final String mNamespace; +        private final Set<String> mIds = new ArraySet<>(); +        private final Map<String, List<String>> mProjectionTypePropertyPaths = new ArrayMap<>(); +        private boolean mBuilt = false; + +        /** +         * @deprecated TODO(b/181887768): Exists for dogfood transition; must be removed. +         * @hide +         */ +        @Deprecated +        @UnsupportedAppUsage +        public Builder(@NonNull String namespace) { +            mNamespace = Objects.requireNonNull(namespace); +        } + +        /** +         * Adds one or more document IDs to the request. +         * +         * @throws IllegalStateException if the builder has already been used. +         */ +        @NonNull +        public Builder addUris(@NonNull String... ids) { +            Objects.requireNonNull(ids); +            return addUris(Arrays.asList(ids)); +        } + +        /** +         * @deprecated TODO(b/181887768): Exists for dogfood transition; must be removed. +         * @hide +         */ +        @Deprecated +        @UnsupportedAppUsage +        @NonNull +        public Builder addUris(@NonNull Collection<String> ids) { +            Preconditions.checkState(!mBuilt, "Builder has already been used"); +            Objects.requireNonNull(ids); +            mIds.addAll(ids); +            return this; +        } + +        /** +         * @deprecated TODO(b/181887768): Exists for dogfood transition; must be removed. +         * @hide +         */ +        @Deprecated +        @UnsupportedAppUsage +        @NonNull +        public Builder addProjection( +                @NonNull String schemaType, @NonNull Collection<String> propertyPaths) { +            Preconditions.checkState(!mBuilt, "Builder has already been used"); +            Objects.requireNonNull(schemaType); +            Objects.requireNonNull(propertyPaths); +            List<String> propertyPathsList = new ArrayList<>(propertyPaths.size()); +            for (String propertyPath : propertyPaths) { +                Objects.requireNonNull(propertyPath); +                propertyPathsList.add(propertyPath); +            } +            mProjectionTypePropertyPaths.put(schemaType, propertyPathsList); +            return this; +        } + +        /** +         * @deprecated TODO(b/181887768): Exists for dogfood transition; must be removed. +         * @hide +         */ +        @Deprecated +        @UnsupportedAppUsage +        @NonNull +        public GetByUriRequest build() { +            Preconditions.checkState(!mBuilt, "Builder has already been used"); +            mBuilt = true; +            return new GetByUriRequest(mNamespace, mIds, mProjectionTypePropertyPaths); +        } +    } +} diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/RemoveByUriRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/RemoveByUriRequest.java new file mode 100644 index 000000000000..9c74966ada58 --- /dev/null +++ b/apex/appsearch/framework/java/external/android/app/appsearch/RemoveByUriRequest.java @@ -0,0 +1,125 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app.appsearch; + +import android.annotation.NonNull; +import android.compat.annotation.UnsupportedAppUsage; +import android.util.ArraySet; + +import com.android.internal.util.Preconditions; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Objects; +import java.util.Set; + +/** + * @deprecated TODO(b/181887768): Exists for dogfood transition; must be removed. + * @hide + */ +@Deprecated +public final class RemoveByUriRequest { +    private final String mNamespace; +    private final Set<String> mIds; + +    RemoveByUriRequest(String namespace, Set<String> ids) { +        mNamespace = namespace; +        mIds = ids; +    } + +    /** Returns the namespace to remove documents from. */ +    @NonNull +    public String getNamespace() { +        return mNamespace; +    } + +    /** Returns the set of document IDs attached to the request. */ +    @NonNull +    public Set<String> getUris() { +        return Collections.unmodifiableSet(mIds); +    } + +    /** +     * @deprecated TODO(b/181887768): Exists for dogfood transition; must be removed. +     * @hide +     */ +    @Deprecated +    @NonNull +    public RemoveByDocumentIdRequest toRemoveByDocumentIdRequest() { +        return new RemoveByDocumentIdRequest.Builder(mNamespace).addIds(mIds).build(); +    } + +    /** +     * Builder for {@link RemoveByUriRequest} objects. +     * +     * <p>Once {@link #build} is called, the instance can no longer be used. +     */ +    public static final class Builder { +        private final String mNamespace; +        private final Set<String> mIds = new ArraySet<>(); +        private boolean mBuilt = false; + +        /** +         * @deprecated TODO(b/181887768): Exists for dogfood transition; must be removed. +         * @hide +         */ +        @Deprecated +        @UnsupportedAppUsage +        public Builder(@NonNull String namespace) { +            mNamespace = Objects.requireNonNull(namespace); +        } + +        /** +         * Adds one or more document IDs to the request. +         * +         * @throws IllegalStateException if the builder has already been used. +         */ +        @NonNull +        public Builder addUris(@NonNull String... ids) { +            Objects.requireNonNull(ids); +            return addUris(Arrays.asList(ids)); +        } + +        /** +         * @deprecated TODO(b/181887768): Exists for dogfood transition; must be removed. +         * @hide +         */ +        @Deprecated +        @UnsupportedAppUsage +        @NonNull +        public Builder addUris(@NonNull Collection<String> ids) { +            Preconditions.checkState(!mBuilt, "Builder has already been used"); +            Objects.requireNonNull(ids); +            mIds.addAll(ids); +            return this; +        } + +        /** +         * @deprecated TODO(b/181887768): Exists for dogfood transition; must be removed. +         * @hide +         */ +        @Deprecated +        @UnsupportedAppUsage +        @NonNull +        public RemoveByUriRequest build() { +            Preconditions.checkState(!mBuilt, "Builder has already been used"); +            mBuilt = true; +            return new RemoveByUriRequest(mNamespace, mIds); +        } +    } +} diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/ReportUsageRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/ReportUsageRequest.java index 8c8ade8c52d0..5cb59b3030ee 100644 --- a/apex/appsearch/framework/java/external/android/app/appsearch/ReportUsageRequest.java +++ b/apex/appsearch/framework/java/external/android/app/appsearch/ReportUsageRequest.java @@ -18,6 +18,7 @@ package android.app.appsearch;  import android.annotation.CurrentTimeMillisLong;  import android.annotation.NonNull; +import android.compat.annotation.UnsupportedAppUsage;  import com.android.internal.util.Preconditions; @@ -68,7 +69,8 @@ public final class ReportUsageRequest {      /** Builder for {@link ReportUsageRequest} objects. */      public static final class Builder {          private final String mNamespace; -        private final String mDocumentId; +        // TODO(b/181887768): Make this final +        private String mDocumentId;          private Long mUsageTimestampMillis;          private boolean mBuilt = false; @@ -79,6 +81,40 @@ public final class ReportUsageRequest {          }          /** +         * @deprecated TODO(b/181887768): Exists for dogfood transition; must be removed. +         * @hide +         */ +        @Deprecated +        @UnsupportedAppUsage +        public Builder(@NonNull String namespace) { +            mNamespace = Objects.requireNonNull(namespace); +        } + +        /** +         * @deprecated TODO(b/181887768): Exists for dogfood transition; must be removed. +         * @hide +         */ +        @Deprecated +        @UnsupportedAppUsage +        @NonNull +        public Builder setUri(@NonNull String uri) { +            mDocumentId = uri; +            return this; +        } + +        /** +         * @deprecated TODO(b/181887768): Exists for dogfood transition; must be removed. +         * @hide +         */ +        @Deprecated +        @UnsupportedAppUsage +        @NonNull +        public ReportUsageRequest.Builder setUsageTimeMillis( +                @CurrentTimeMillisLong long usageTimestampMillis) { +            return setUsageTimestampMillis(usageTimestampMillis); +        } + +        /**           * Sets the timestamp in milliseconds of the usage report (the time at which the document           * was used).           * diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/SearchResult.java b/apex/appsearch/framework/java/external/android/app/appsearch/SearchResult.java index b648071a93c1..9a1796cbe94e 100644 --- a/apex/appsearch/framework/java/external/android/app/appsearch/SearchResult.java +++ b/apex/appsearch/framework/java/external/android/app/appsearch/SearchResult.java @@ -192,7 +192,7 @@ public final class SearchResult {              return this;          } -        /** @deprecated this method exists only for dogfooder transition and must be removed */ +        /** @deprecated This method exists only for dogfooder transition and must be removed. */          @Deprecated          @NonNull          public Builder addMatch(@NonNull MatchInfo matchInfo) { diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java index b7bd3878d4fa..7ad5fe877480 100644 --- a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java +++ b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java @@ -18,6 +18,7 @@ package android.app.appsearch;  import android.annotation.NonNull;  import android.annotation.Nullable; +import android.compat.annotation.UnsupportedAppUsage;  import android.os.Bundle;  import android.util.ArraySet; @@ -324,6 +325,17 @@ public class SetSchemaResponse {              return mBundle.getString(NAMESPACE_FIELD, /*defaultValue=*/ "");          } +        /** +         * @deprecated TODO(b/181887768): Exists for dogfood transition; must be removed. +         * @hide +         */ +        @Deprecated +        @UnsupportedAppUsage +        @NonNull +        public String getUri() { +            return getDocumentId(); +        } +          /** Returns the id of the {@link GenericDocument} that failed to be migrated. */          @NonNull          public String getDocumentId() { diff --git a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java index 52442a66cf1d..b3c33b6615f4 100644 --- a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java +++ b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java @@ -1703,7 +1703,7 @@ public class JobInfo implements Parcelable {                  throw new IllegalArgumentException("An expedited job cannot be periodic");              }              if ((constraintFlags & ~CONSTRAINT_FLAG_STORAGE_NOT_LOW) != 0 -                    || (flags & ~FLAG_EXPEDITED) != 0) { +                    || (flags & ~(FLAG_EXPEDITED | FLAG_EXEMPT_FROM_APP_STANDBY)) != 0) {                  throw new IllegalArgumentException(                          "An expedited job can only have network and storage-not-low constraints");              } diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java index 0e362759ef4c..64686a1682f0 100644 --- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java +++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java @@ -151,10 +151,10 @@ import java.util.Comparator;  import java.util.Date;  import java.util.HashMap;  import java.util.Locale; -import java.util.Random;  import java.util.Set;  import java.util.TimeZone;  import java.util.TreeSet; +import java.util.concurrent.ThreadLocalRandom;  import java.util.function.Predicate;  /** @@ -251,7 +251,6 @@ public class AlarmManagerService extends SystemService {      Intent mTimeTickIntent;      IAlarmListener mTimeTickTrigger;      PendingIntent mDateChangeSender; -    Random mRandom;      boolean mInteractive = true;      long mNonInteractiveStartTime;      long mNonInteractiveTime; @@ -516,6 +515,10 @@ public class AlarmManagerService extends SystemService {          static final String KEY_PRIORITY_ALARM_DELAY = "priority_alarm_delay";          @VisibleForTesting          static final String KEY_EXACT_ALARM_DENY_LIST = "exact_alarm_deny_list"; +        @VisibleForTesting +        static final String KEY_MIN_DEVICE_IDLE_FUZZ = "min_device_idle_fuzz"; +        @VisibleForTesting +        static final String KEY_MAX_DEVICE_IDLE_FUZZ = "max_device_idle_fuzz";          private static final long DEFAULT_MIN_FUTURITY = 5 * 1000;          private static final long DEFAULT_MIN_INTERVAL = 60 * 1000; @@ -556,6 +559,9 @@ public class AlarmManagerService extends SystemService {          private static final long DEFAULT_PRIORITY_ALARM_DELAY = 9 * 60_000; +        private static final long DEFAULT_MIN_DEVICE_IDLE_FUZZ = 2 * 60_000; +        private static final long DEFAULT_MAX_DEVICE_IDLE_FUZZ = 15 * 60_000; +          // Minimum futurity of a new alarm          public long MIN_FUTURITY = DEFAULT_MIN_FUTURITY; @@ -618,10 +624,23 @@ public class AlarmManagerService extends SystemService {          public long PRIORITY_ALARM_DELAY = DEFAULT_PRIORITY_ALARM_DELAY;          /** -         * Set of apps that won't get SCHEDULE_EXACT_ALARM when the app-op mode for -         * OP_SCHEDULE_EXACT_ALARM is MODE_DEFAULT. +         * Read-only set of apps that won't get SCHEDULE_EXACT_ALARM when the app-op mode for +         * OP_SCHEDULE_EXACT_ALARM is MODE_DEFAULT. Since this is read-only and volatile, this can +         * be accessed without synchronizing on {@link #mLock}. +         */ +        public volatile Set<String> EXACT_ALARM_DENY_LIST = Collections.emptySet(); + +        /** +         * Minimum time interval that an IDLE_UNTIL will be pulled earlier to a subsequent +         * WAKE_FROM_IDLE alarm. +         */ +        public long MIN_DEVICE_IDLE_FUZZ = DEFAULT_MIN_DEVICE_IDLE_FUZZ; + +        /** +         * Maximum time interval that an IDLE_UNTIL will be pulled earlier to a subsequent +         * WAKE_FROM_IDLE alarm.           */ -        public Set<String> EXACT_ALARM_DENY_LIST = Collections.emptySet(); +        public long MAX_DEVICE_IDLE_FUZZ = DEFAULT_MAX_DEVICE_IDLE_FUZZ;          private long mLastAllowWhileIdleWhitelistDuration = -1;          private int mVersion = 0; @@ -660,6 +679,7 @@ public class AlarmManagerService extends SystemService {          @Override          public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) {              boolean standbyQuotaUpdated = false; +            boolean deviceIdleFuzzBoundariesUpdated = false;              synchronized (mLock) {                  mVersion++;                  for (String name : properties.getKeyset()) { @@ -787,6 +807,13 @@ public class AlarmManagerService extends SystemService {                                  updateExactAlarmDenyList(values);                              }                              break; +                        case KEY_MIN_DEVICE_IDLE_FUZZ: +                        case KEY_MAX_DEVICE_IDLE_FUZZ: +                            if (!deviceIdleFuzzBoundariesUpdated) { +                                updateDeviceIdleFuzzBoundaries(); +                                deviceIdleFuzzBoundariesUpdated = true; +                            } +                            break;                          default:                              if (name.startsWith(KEY_PREFIX_STANDBY_QUOTA) && !standbyQuotaUpdated) {                                  // The quotas need to be updated in order, so we can't just rely @@ -824,6 +851,24 @@ public class AlarmManagerService extends SystemService {              mAlarmStore.setAlarmClockRemovalListener(mAlarmClockUpdater);          } +        private void updateDeviceIdleFuzzBoundaries() { +            final DeviceConfig.Properties properties = DeviceConfig.getProperties( +                    DeviceConfig.NAMESPACE_ALARM_MANAGER, +                    KEY_MIN_DEVICE_IDLE_FUZZ, KEY_MAX_DEVICE_IDLE_FUZZ); + +            MIN_DEVICE_IDLE_FUZZ = properties.getLong(KEY_MIN_DEVICE_IDLE_FUZZ, +                    DEFAULT_MIN_DEVICE_IDLE_FUZZ); +            MAX_DEVICE_IDLE_FUZZ = properties.getLong(KEY_MAX_DEVICE_IDLE_FUZZ, +                    DEFAULT_MAX_DEVICE_IDLE_FUZZ); + +            if (MAX_DEVICE_IDLE_FUZZ < MIN_DEVICE_IDLE_FUZZ) { +                Slog.w(TAG, "max_device_idle_fuzz cannot be smaller than" +                        + " min_device_idle_fuzz! Increasing to " +                        + MIN_DEVICE_IDLE_FUZZ); +                MAX_DEVICE_IDLE_FUZZ = MIN_DEVICE_IDLE_FUZZ; +            } +        } +          private void updateStandbyQuotasLocked() {              // The bucket quotas need to be read as an atomic unit but the properties passed to              // onPropertiesChanged may only have one key populated at a time. @@ -1133,12 +1178,8 @@ public class AlarmManagerService extends SystemService {                  if (mNextWakeFromIdle != null && isRtc(mNextWakeFromIdle.type)) {                      // The next wake from idle got updated due to the rtc time change, so we need                      // to update the time we have to come out of idle too. -                    final boolean idleUntilUpdated = mAlarmStore.updateAlarmDeliveries(a -> { -                        if (a != mPendingIdleUntil) { -                            return false; -                        } -                        return adjustIdleUntilTime(a); -                    }); +                    final boolean idleUntilUpdated = mAlarmStore.updateAlarmDeliveries( +                            a -> (a == mPendingIdleUntil) && adjustIdleUntilTime(a));                      if (idleUntilUpdated) {                          mAlarmStore.updateAlarmDeliveries(                                  alarm -> adjustDeliveryTimeBasedOnDeviceIdle(alarm)); @@ -1911,23 +1952,30 @@ public class AlarmManagerService extends SystemService {          if ((alarm.flags & AlarmManager.FLAG_IDLE_UNTIL) == 0) {              return false;          } -        restoreRequestedTime(alarm); -        long triggerBeforeFuzz = alarm.getRequestedElapsed(); -        if (mNextWakeFromIdle != null && triggerBeforeFuzz > mNextWakeFromIdle.getWhenElapsed()) { -            triggerBeforeFuzz = mNextWakeFromIdle.getWhenElapsed(); +        final boolean changedBeforeFuzz = restoreRequestedTime(alarm); +        if (mNextWakeFromIdle == null) { +            // No need to change anything in the absence of a wake-from-idle request. +            return changedBeforeFuzz;          } -        // Add fuzz to make the alarm go off some time before the actual desired time. -        final int fuzz = fuzzForDuration(alarm.getWhenElapsed() - mInjector.getElapsedRealtime()); -        final int delta; -        if (fuzz > 0) { -            if (mRandom == null) { -                mRandom = new Random(); -            } -            delta = mRandom.nextInt(fuzz); +        final long upcomingWakeFromIdle = mNextWakeFromIdle.getWhenElapsed(); +        // Add fuzz to make the alarm go off some time before the next upcoming wake-from-idle, as +        // these alarms are usually wall-clock aligned. +        if (alarm.getWhenElapsed() < (upcomingWakeFromIdle - mConstants.MIN_DEVICE_IDLE_FUZZ)) { +            // No need to fuzz as this is already earlier than the coming wake-from-idle. +            return changedBeforeFuzz; +        } +        final long nowElapsed = mInjector.getElapsedRealtime(); +        final long futurity = upcomingWakeFromIdle - nowElapsed; + +        if (futurity <= mConstants.MIN_DEVICE_IDLE_FUZZ) { +            // No point in fuzzing as the minimum fuzz will take the time in the past. +            alarm.setPolicyElapsed(REQUESTER_POLICY_INDEX, nowElapsed);          } else { -            delta = 0; +            final ThreadLocalRandom random = ThreadLocalRandom.current(); +            final long upperBoundExcl = Math.min(mConstants.MAX_DEVICE_IDLE_FUZZ, futurity) + 1; +            final long fuzz = random.nextLong(mConstants.MIN_DEVICE_IDLE_FUZZ, upperBoundExcl); +            alarm.setPolicyElapsed(REQUESTER_POLICY_INDEX, upcomingWakeFromIdle - fuzz);          } -        alarm.setPolicyElapsed(REQUESTER_POLICY_INDEX, triggerBeforeFuzz - delta);          return true;      } @@ -2130,12 +2178,8 @@ public class AlarmManagerService extends SystemService {                  // If this wake from idle is earlier than whatever was previously scheduled,                  // and we are currently idling, then the idle-until time needs to be updated.                  if (mPendingIdleUntil != null) { -                    final boolean updated = mAlarmStore.updateAlarmDeliveries(alarm -> { -                        if (alarm != mPendingIdleUntil) { -                            return false; -                        } -                        return adjustIdleUntilTime(alarm); -                    }); +                    final boolean updated = mAlarmStore.updateAlarmDeliveries( +                            alarm -> (alarm == mPendingIdleUntil) && adjustIdleUntilTime(alarm));                      if (updated) {                          // idle-until got updated, so also update all alarms not allowed while idle.                          mAlarmStore.updateAlarmDeliveries( @@ -3675,20 +3719,6 @@ public class AlarmManagerService extends SystemService {          }      } -    int fuzzForDuration(long duration) { -        if (duration < 15 * 60 * 1000) { -            // If the duration until the time is less than 15 minutes, the maximum fuzz -            // is the duration. -            return (int) duration; -        } else if (duration < 90 * 60 * 1000) { -            // If duration is less than 1 1/2 hours, the maximum fuzz is 15 minutes, -            return 15 * 60 * 1000; -        } else { -            // Otherwise, we will fuzz by at most half an hour. -            return 30 * 60 * 1000; -        } -    } -      boolean checkAllowNonWakeupDelayLocked(long nowELAPSED) {          if (mInteractive) {              return false; @@ -4698,8 +4728,10 @@ public class AlarmManagerService extends SystemService {                          if (a.creatorUid != alarm.creatorUid || !isAllowedWhileIdleRestricted(a)) {                              return false;                          } -                        return (doze && adjustDeliveryTimeBasedOnDeviceIdle(a)) -                                || (batterySaver && adjustDeliveryTimeBasedOnBatterySaver(a)); +                        final boolean dozeAdjusted = doze && adjustDeliveryTimeBasedOnDeviceIdle(a); +                        final boolean batterySaverAdjusted = +                                batterySaver && adjustDeliveryTimeBasedOnBatterySaver(a); +                        return dozeAdjusted || batterySaverAdjusted;                      });                  } else if ((alarm.flags & FLAG_PRIORITIZE) != 0) {                      mLastPriorityAlarmDispatch.put(alarm.creatorUid, nowELAPSED); @@ -4708,8 +4740,10 @@ public class AlarmManagerService extends SystemService {                                  || (alarm.flags & FLAG_PRIORITIZE) == 0) {                              return false;                          } -                        return (doze && adjustDeliveryTimeBasedOnDeviceIdle(a)) -                                || (batterySaver && adjustDeliveryTimeBasedOnBatterySaver(a)); +                        final boolean dozeAdjusted = doze && adjustDeliveryTimeBasedOnDeviceIdle(a); +                        final boolean batterySaverAdjusted = +                                batterySaver && adjustDeliveryTimeBasedOnBatterySaver(a); +                        return dozeAdjusted || batterySaverAdjusted;                      });                  }                  if (RECORD_DEVICE_IDLE_ALARMS) { diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/LazyAlarmStore.java b/apex/jobscheduler/service/java/com/android/server/alarm/LazyAlarmStore.java index 2e12e2f34ea0..0073335a1332 100644 --- a/apex/jobscheduler/service/java/com/android/server/alarm/LazyAlarmStore.java +++ b/apex/jobscheduler/service/java/com/android/server/alarm/LazyAlarmStore.java @@ -40,6 +40,7 @@ import java.util.function.Predicate;  public class LazyAlarmStore implements AlarmStore {      @VisibleForTesting      static final String TAG = LazyAlarmStore.class.getSimpleName(); +    private static final long ALARM_DEADLINE_SLOP = 500;      private final ArrayList<Alarm> mAlarms = new ArrayList<>();      private Runnable mOnAlarmClockRemoved; @@ -75,7 +76,7 @@ public class LazyAlarmStore implements AlarmStore {              return;          }          mAlarms.addAll(alarms); -        Collections.sort(alarms, sDecreasingTimeOrder); +        Collections.sort(mAlarms, sDecreasingTimeOrder);      }      @Override @@ -163,25 +164,47 @@ public class LazyAlarmStore implements AlarmStore {      @Override      public ArrayList<Alarm> removePendingAlarms(long nowElapsed) {          final ArrayList<Alarm> pending = new ArrayList<>(); -        final ArrayList<Alarm> standAlones = new ArrayList<>(); + +        // Only send wake-up alarms if this is the absolutely latest time we can evaluate +        // for at least one wakeup alarm. This prevents sending other non-wakeup alarms when the +        // screen is off but the CPU is awake for some reason. +        boolean sendWakeups = false; + +        // If any alarm with FLAG_STANDALONE is present, we cannot send any alarms without that flag +        // in the present batch. +        boolean standalonesOnly = false;          for (int i = mAlarms.size() - 1; i >= 0; i--) {              final Alarm alarm = mAlarms.get(i);              if (alarm.getWhenElapsed() > nowElapsed) {                  break;              } +            mAlarms.remove(i);              pending.add(alarm); +            if (alarm.wakeup && alarm.getMaxWhenElapsed() <= nowElapsed + ALARM_DEADLINE_SLOP) { +                // Using some slop as it is better to send the wakeup alarm now, rather than +                // waking up again a short time later, just to send it. +                sendWakeups = true; +            }              if ((alarm.flags & AlarmManager.FLAG_STANDALONE) != 0) { -                standAlones.add(alarm); +                standalonesOnly = true;              }          } -        if (!standAlones.isEmpty()) { -            // If there are deliverable standalone alarms, others must not go out yet. -            mAlarms.removeAll(standAlones); -            return standAlones; +        final ArrayList<Alarm> toSend = new ArrayList<>(); +        for (int i = pending.size() - 1; i >= 0; i--) { +            final Alarm pendingAlarm = pending.get(i); +            if (!sendWakeups && pendingAlarm.wakeup) { +                continue; +            } +            if (standalonesOnly && (pendingAlarm.flags & AlarmManager.FLAG_STANDALONE) == 0) { +                continue; +            } +            pending.remove(i); +            toSend.add(pendingAlarm);          } -        mAlarms.removeAll(pending); -        return pending; +        // Perhaps some alarms could not be sent right now. Adding them back for later. +        addAll(pending); +        return toSend;      }      @Override diff --git a/core/api/current.txt b/core/api/current.txt index f23d24a10702..11dbe6f6f4cf 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -586,7 +586,6 @@ package android {      field public static final int dropDownWidth = 16843362; // 0x1010262      field public static final int duplicateParentState = 16842985; // 0x10100e9      field public static final int duration = 16843160; // 0x1010198 -    field public static final int edgeEffectType;      field public static final int editTextBackground = 16843602; // 0x1010352      field public static final int editTextColor = 16843601; // 0x1010351      field public static final int editTextPreferenceStyle = 16842898; // 0x1010092 @@ -1741,6 +1740,7 @@ package android {      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; @@ -1753,6 +1753,7 @@ package android {      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; @@ -1765,6 +1766,7 @@ package android {      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; @@ -1777,6 +1779,7 @@ package android {      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; @@ -1789,6 +1792,7 @@ package android {      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; @@ -11921,6 +11925,7 @@ package android.content.pm {      method public int getGwpAsanMode();      method public int getMemtagMode();      method public int getNativeHeapZeroInitialized(); +    method public int getRequestRawExternalStorageAccess();      method public boolean isProfileable();      method public boolean isProfileableByShell();      method public boolean isResourceOverlay(); @@ -11976,6 +11981,9 @@ package android.content.pm {      field public static final int MEMTAG_DEFAULT = -1; // 0xffffffff      field public static final int MEMTAG_OFF = 0; // 0x0      field public static final int MEMTAG_SYNC = 2; // 0x2 +    field public static final int RAW_EXTERNAL_STORAGE_ACCESS_DEFAULT = 0; // 0x0 +    field public static final int RAW_EXTERNAL_STORAGE_ACCESS_NOT_REQUESTED = 2; // 0x2 +    field public static final int RAW_EXTERNAL_STORAGE_ACCESS_REQUESTED = 1; // 0x1      field public static final int ZEROINIT_DEFAULT = -1; // 0xffffffff      field public static final int ZEROINIT_DISABLED = 0; // 0x0      field public static final int ZEROINIT_ENABLED = 1; // 0x1 @@ -12582,7 +12590,7 @@ package android.content.pm {      method @NonNull public abstract java.util.List<android.content.pm.ResolveInfo> queryIntentActivityOptions(@Nullable android.content.ComponentName, @Nullable android.content.Intent[], @NonNull android.content.Intent, int);      method @NonNull public abstract java.util.List<android.content.pm.ResolveInfo> queryIntentContentProviders(@NonNull android.content.Intent, int);      method @NonNull public abstract java.util.List<android.content.pm.ResolveInfo> queryIntentServices(@NonNull android.content.Intent, int); -    method @NonNull public abstract java.util.List<android.content.pm.PermissionInfo> queryPermissionsByGroup(@NonNull String, int) throws android.content.pm.PackageManager.NameNotFoundException; +    method @NonNull public abstract java.util.List<android.content.pm.PermissionInfo> queryPermissionsByGroup(@Nullable String, int) throws android.content.pm.PackageManager.NameNotFoundException;      method @NonNull public java.util.List<android.content.pm.PackageManager.Property> queryProviderProperty(@NonNull String);      method @NonNull public java.util.List<android.content.pm.PackageManager.Property> queryReceiverProperty(@NonNull String);      method @NonNull public java.util.List<android.content.pm.PackageManager.Property> queryServiceProperty(@NonNull String); @@ -53791,7 +53799,6 @@ package android.widget {      method public int getCheckedItemPosition();      method public android.util.SparseBooleanArray getCheckedItemPositions();      method public int getChoiceMode(); -    method public int getEdgeEffectType();      method public int getListPaddingBottom();      method public int getListPaddingLeft();      method public int getListPaddingRight(); @@ -53833,7 +53840,6 @@ package android.widget {      method public void setChoiceMode(int);      method public void setDrawSelectorOnTop(boolean);      method public void setEdgeEffectColor(@ColorInt int); -    method public void setEdgeEffectType(int);      method public void setFastScrollAlwaysVisible(boolean);      method public void setFastScrollEnabled(boolean);      method public void setFastScrollStyle(int); @@ -54524,7 +54530,6 @@ package android.widget {      method @ColorInt public int getColor();      method public float getDistance();      method public int getMaxHeight(); -    method public int getType();      method public boolean isFinished();      method public void onAbsorb(int);      method public void onPull(float); @@ -54534,10 +54539,7 @@ package android.widget {      method public void setBlendMode(@Nullable android.graphics.BlendMode);      method public void setColor(@ColorInt int);      method public void setSize(int, int); -    method public void setType(int);      field public static final android.graphics.BlendMode DEFAULT_BLEND_MODE; -    field public static final int TYPE_GLOW = 0; // 0x0 -    field public static final int TYPE_STRETCH = 1; // 0x1    }    public class EditText extends android.widget.TextView { @@ -54842,7 +54844,6 @@ package android.widget {      method public boolean executeKeyEvent(android.view.KeyEvent);      method public void fling(int);      method public boolean fullScroll(int); -    method public int getEdgeEffectType();      method @ColorInt public int getLeftEdgeEffectColor();      method public int getMaxScrollAmount();      method @ColorInt public int getRightEdgeEffectColor(); @@ -54850,7 +54851,6 @@ package android.widget {      method public boolean isSmoothScrollingEnabled();      method public boolean pageScroll(int);      method public void setEdgeEffectColor(@ColorInt int); -    method public void setEdgeEffectType(int);      method public void setFillViewport(boolean);      method public void setLeftEdgeEffectColor(@ColorInt int);      method public void setRightEdgeEffectColor(@ColorInt int); @@ -55736,7 +55736,6 @@ package android.widget {      method public void fling(int);      method public boolean fullScroll(int);      method @ColorInt public int getBottomEdgeEffectColor(); -    method public int getEdgeEffectType();      method public int getMaxScrollAmount();      method @ColorInt public int getTopEdgeEffectColor();      method public boolean isFillViewport(); @@ -55745,7 +55744,6 @@ package android.widget {      method public void scrollToDescendant(@NonNull android.view.View);      method public void setBottomEdgeEffectColor(@ColorInt int);      method public void setEdgeEffectColor(@ColorInt int); -    method public void setEdgeEffectType(int);      method public void setFillViewport(boolean);      method public void setSmoothScrollingEnabled(boolean);      method public void setTopEdgeEffectColor(@ColorInt int); diff --git a/core/api/system-current.txt b/core/api/system-current.txt index c7960dd406ed..990f43de5ec5 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -2520,7 +2520,6 @@ package android.content.om {  package android.content.pm {    public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable { -    method @Nullable public Boolean hasRequestRawExternalStorageAccess();      method public boolean isEncryptionAware();      method public boolean isInstantApp();      method public boolean isOem(); diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 35767b3acb8c..196799345efd 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -429,7 +429,6 @@ package android.app {      field public static final int ROTATION_UNDEFINED = -1; // 0xffffffff      field public static final int WINDOWING_MODE_FREEFORM = 5; // 0x5      field public static final int WINDOWING_MODE_FULLSCREEN = 1; // 0x1 -    field public static final int WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY = 4; // 0x4      field public static final int WINDOWING_MODE_MULTI_WINDOW = 6; // 0x6      field public static final int WINDOWING_MODE_PINNED = 2; // 0x2      field public static final int WINDOWING_MODE_SPLIT_SCREEN_PRIMARY = 3; // 0x3 @@ -1810,6 +1809,7 @@ package android.os {    public class VintfObject {      method public static String[] getHalNamesAndVersions(); +    method @NonNull public static String getPlatformSepolicyVersion();      method public static String getSepolicyVersion();      method public static Long getTargetFrameworkCompatibilityMatrixVersion();      method public static java.util.Map<java.lang.String,java.lang.String[]> getVndkSnapshots(); diff --git a/core/java/Android.bp b/core/java/Android.bp index c8a8d36a1b20..793d0ef164fa 100644 --- a/core/java/Android.bp +++ b/core/java/Android.bp @@ -46,44 +46,6 @@ filegroup {          "android/accounts/AccountsException.java",          "android/accounts/AuthenticatorException.java",          "android/accounts/OperationCanceledException.java", -        "android/annotation/AnimatorRes.java", -        "android/annotation/AnimRes.java", -        "android/annotation/AnyRes.java", -        "android/annotation/ArrayRes.java", -        "android/annotation/AttrRes.java", -        "android/annotation/BoolRes.java", -        "android/annotation/BroadcastBehavior.java", -        "android/annotation/CallbackExecutor.java", -        "android/annotation/CallSuper.java", -        "android/annotation/CheckResult.java", -        "android/annotation/ColorInt.java", -        "android/annotation/ColorRes.java", -        "android/annotation/DimenRes.java", -        "android/annotation/DrawableRes.java", -        "android/annotation/FontRes.java", -        "android/annotation/FractionRes.java", -        "android/annotation/IntDef.java", -        "android/annotation/IntegerRes.java", -        "android/annotation/IntRange.java", -        "android/annotation/LayoutRes.java", -        "android/annotation/NonNull.java", -        "android/annotation/Nullable.java", -        "android/annotation/PluralsRes.java", -        "android/annotation/RawRes.java", -        "android/annotation/RequiresNoPermission.java", -        "android/annotation/RequiresPermission.java", -        "android/annotation/SdkConstant.java", -        "android/annotation/Size.java", -        "android/annotation/StringDef.java", -        "android/annotation/StringRes.java", -        "android/annotation/StyleableRes.java", -        "android/annotation/StyleRes.java", -        "android/annotation/SuppressLint.java", -        "android/annotation/SystemApi.java", -        "android/annotation/SystemService.java", -        "android/annotation/TestApi.java", -        "android/annotation/UserIdInt.java", -        "android/annotation/XmlRes.java",          "android/app/Application.java",          "android/app/IApplicationThread.aidl",          "android/app/IServiceConnection.aidl", @@ -124,7 +86,6 @@ filegroup {          "android/util/AndroidException.java",          "android/view/DisplayAdjustments.java",          "android/view/ViewDebug.java", -        "com/android/internal/annotations/VisibleForTesting.java",      ],      visibility: ["//frameworks/base/test-mock"],  } diff --git a/core/java/android/annotation/AnimRes.java b/core/java/android/annotation/AnimRes.java deleted file mode 100644 index 56f8acf82313..000000000000 --- a/core/java/android/annotation/AnimRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2013 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that an integer parameter, field or method return value is expected - * to be an anim resource reference (e.g. {@link android.R.anim#fade_in}). - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface AnimRes { -} diff --git a/core/java/android/annotation/AnimatorRes.java b/core/java/android/annotation/AnimatorRes.java deleted file mode 100644 index cd4c189b7531..000000000000 --- a/core/java/android/annotation/AnimatorRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2013 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that an integer parameter, field or method return value is expected - * to be an animator resource reference (e.g. {@link android.R.animator#fade_in}). - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface AnimatorRes { -} diff --git a/core/java/android/annotation/AnyRes.java b/core/java/android/annotation/AnyRes.java deleted file mode 100644 index 44411a04a8e7..000000000000 --- a/core/java/android/annotation/AnyRes.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2013 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that an integer parameter, field or method return value is expected - * to be a resource reference of any type. If the specific type is known, use - * one of the more specific annotations instead, such as {@link StringRes} or - * {@link DrawableRes}. - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface AnyRes { -} diff --git a/core/java/android/annotation/AnyThread.java b/core/java/android/annotation/AnyThread.java deleted file mode 100644 index ee36a42b3fc6..000000000000 --- a/core/java/android/annotation/AnyThread.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2016 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.annotation; - -import static java.lang.annotation.ElementType.CONSTRUCTOR; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * Denotes that the annotated method can be called from any thread (e.g. it is - * "thread safe".) If the annotated element is a class, then all methods in the - * class can be called from any thread. - * <p> - * The main purpose of this method is to indicate that you believe a method can - * be called from any thread; static tools can then check that nothing you call - * from within this method or class have more strict threading requirements. - * <p> - * Example: - * - * <pre> - * <code> - *  @AnyThread - *  public void deliverResult(D data) { ... } - * </code> - * </pre> - * - * @memberDoc This method is safe to call from any thread. - * @hide - */ -@Retention(SOURCE) -@Target({METHOD,CONSTRUCTOR,TYPE,PARAMETER}) -public @interface AnyThread { -} diff --git a/core/java/android/annotation/AppIdInt.java b/core/java/android/annotation/AppIdInt.java deleted file mode 100644 index 29838dd5bd7c..000000000000 --- a/core/java/android/annotation/AppIdInt.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2016 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.annotation; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * Denotes that the annotated element is a multi-user application ID. This is - * <em>not</em> the same as a UID. - * - * @hide - */ -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface AppIdInt { -} diff --git a/core/java/android/annotation/ArrayRes.java b/core/java/android/annotation/ArrayRes.java deleted file mode 100644 index 1407af1d1422..000000000000 --- a/core/java/android/annotation/ArrayRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2013 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that an integer parameter, field or method return value is expected - * to be an array resource reference (e.g. {@link android.R.array#phoneTypes}). - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface ArrayRes { -} diff --git a/core/java/android/annotation/AttrRes.java b/core/java/android/annotation/AttrRes.java deleted file mode 100644 index 285b80ce45ca..000000000000 --- a/core/java/android/annotation/AttrRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2013 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that an integer parameter, field or method return value is expected - * to be an attribute reference (e.g. {@link android.R.attr#action}). - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface AttrRes { -} diff --git a/core/java/android/annotation/BinderThread.java b/core/java/android/annotation/BinderThread.java deleted file mode 100644 index ca5e14c2adb9..000000000000 --- a/core/java/android/annotation/BinderThread.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2015 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.annotation; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.CONSTRUCTOR; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that the annotated method should only be called on the binder thread. - * If the annotated element is a class, then all methods in the class should be called - * on the binder thread. - * <p> - * Example: - * <pre><code> - *  @BinderThread - *  public BeamShareData createBeamShareData() { ... } - * </code></pre> - * - * {@hide} - */ -@Retention(SOURCE) -@Target({METHOD,CONSTRUCTOR,TYPE,PARAMETER}) -public @interface BinderThread { -}
\ No newline at end of file diff --git a/core/java/android/annotation/BoolRes.java b/core/java/android/annotation/BoolRes.java deleted file mode 100644 index f50785b1e1cf..000000000000 --- a/core/java/android/annotation/BoolRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2013 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that an integer parameter, field or method return value is expected - * to be a boolean resource reference. - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface BoolRes { -} diff --git a/core/java/android/annotation/BroadcastBehavior.java b/core/java/android/annotation/BroadcastBehavior.java deleted file mode 100644 index 70d82cb5151b..000000000000 --- a/core/java/android/annotation/BroadcastBehavior.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2017 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.annotation; - -import android.content.Intent; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Description of how the annotated broadcast action behaves. - * - * @hide - */ -@Target({ ElementType.FIELD }) -@Retention(RetentionPolicy.SOURCE) -public @interface BroadcastBehavior { -    /** -     * This broadcast will only be delivered to an explicit target. -     * -     * @see Intent#setPackage(String) -     * @see Intent#setComponent(android.content.ComponentName) -     */ -    boolean explicitOnly() default false; - -    /** -     * This broadcast will only be delivered to registered receivers. -     * -     * @see Intent#FLAG_RECEIVER_REGISTERED_ONLY -     */ -    boolean registeredOnly() default false; - -    /** -     * This broadcast will include all {@code AndroidManifest.xml} receivers -     * regardless of process state. -     * -     * @see Intent#FLAG_RECEIVER_INCLUDE_BACKGROUND -     */ -    boolean includeBackground() default false; - -    /** -     * This broadcast is protected and can only be sent by the OS. -     */ -    boolean protectedBroadcast() default false; -} diff --git a/core/java/android/annotation/BytesLong.java b/core/java/android/annotation/BytesLong.java deleted file mode 100644 index f5e1a9c5f7fd..000000000000 --- a/core/java/android/annotation/BytesLong.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2017 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.annotation; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * @memberDoc Value is a non-negative number of bytes. - * @paramDoc Value is a non-negative number of bytes. - * @returnDoc Value is a non-negative number of bytes. - * @hide - */ -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface BytesLong { -} diff --git a/core/java/android/annotation/CallSuper.java b/core/java/android/annotation/CallSuper.java deleted file mode 100644 index c16b51161cac..000000000000 --- a/core/java/android/annotation/CallSuper.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2015 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.annotation; - -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * Denotes that any overriding methods should invoke this method as well. - * <p> - * Example: - * - * <pre> - * <code> - *  @CallSuper - *  public abstract void onFocusLost(); - * </code> - * </pre> - * - * @memberDoc If you override this method you <em>must</em> call through to the - *            superclass implementation. - * @hide - */ -@Retention(SOURCE) -@Target({METHOD}) -public @interface CallSuper { -} diff --git a/core/java/android/annotation/CallbackExecutor.java b/core/java/android/annotation/CallbackExecutor.java deleted file mode 100644 index 4258f730eb16..000000000000 --- a/core/java/android/annotation/CallbackExecutor.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2017 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.annotation; - -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; -import java.util.concurrent.Executor; - -/** - * @paramDoc Callback and listener events are dispatched through this - *           {@link Executor}, providing an easy way to control which thread is - *           used. To dispatch events through the main thread of your - *           application, you can use - *           {@link android.content.Context#getMainExecutor() Context.getMainExecutor()}. - *           To dispatch events through a shared thread pool, you can use - *           {@link android.os.AsyncTask#THREAD_POOL_EXECUTOR AsyncTask#THREAD_POOL_EXECUTOR}. - * @hide - */ -@Retention(SOURCE) -@Target(PARAMETER) -public @interface CallbackExecutor { -} diff --git a/core/java/android/annotation/CheckResult.java b/core/java/android/annotation/CheckResult.java deleted file mode 100644 index 97d031a760a6..000000000000 --- a/core/java/android/annotation/CheckResult.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2015 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.annotation; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that the annotated method returns a result that it typically is - * an error to ignore. This is usually used for methods that have no side effect, - * so calling it without actually looking at the result usually means the developer - * has misunderstood what the method does. - * <p> - * Example: - * <pre>{@code - *  public @CheckResult String trim(String s) { return s.trim(); } - *  ... - *  s.trim(); // this is probably an error - *  s = s.trim(); // ok - * }</pre> - * - * @hide - */ -@Retention(SOURCE) -@Target({METHOD}) -public @interface CheckResult { -    /** Defines the name of the suggested method to use instead, if applicable (using -     * the same signature format as javadoc.) If there is more than one possibility, -     * list them all separated by commas. -     * <p> -     * For example, ProcessBuilder has a method named {@code redirectErrorStream()} -     * which sounds like it might redirect the error stream. It does not. It's just -     * a getter which returns whether the process builder will redirect the error stream, -     * and to actually set it, you must call {@code redirectErrorStream(boolean)}. -     * In that case, the method should be defined like this: -     * <pre> -     *  @CheckResult(suggest="#redirectErrorStream(boolean)") -     *  public boolean redirectErrorStream() { ... } -     * </pre> -     */ -    String suggest() default ""; -}
\ No newline at end of file diff --git a/core/java/android/annotation/ColorInt.java b/core/java/android/annotation/ColorInt.java deleted file mode 100644 index 4671b1b9f887..000000000000 --- a/core/java/android/annotation/ColorInt.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2015 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.annotation; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.LOCAL_VARIABLE; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that the annotated element represents a packed color - * int, {@code AARRGGBB}. If applied to an int array, every element - * in the array represents a color integer. - * <p> - * Example: - * <pre>{@code - *  public abstract void setTextColor(@ColorInt int color); - * }</pre> - * - * @hide - */ -@Retention(SOURCE) -@Target({PARAMETER,METHOD,LOCAL_VARIABLE,FIELD}) -public @interface ColorInt { -}
\ No newline at end of file diff --git a/core/java/android/annotation/ColorLong.java b/core/java/android/annotation/ColorLong.java deleted file mode 100644 index 9b19c76802c9..000000000000 --- a/core/java/android/annotation/ColorLong.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2016 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.annotation; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.LOCAL_VARIABLE; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * <p>Denotes that the annotated element represents a packed color - * long. If applied to a long array, every element in the array - * represents a color long. For more information on how colors - * are packed in a long, please refer to the documentation of - * the {@link android.graphics.Color} class.</p> - * - * <p>Example:</p> - * - * <pre>{@code - *  public void setFillColor(@ColorLong long color); - * }</pre> - * - * @see android.graphics.Color - * - * @hide - */ -@Retention(SOURCE) -@Target({PARAMETER,METHOD,LOCAL_VARIABLE,FIELD}) -public @interface ColorLong { -} diff --git a/core/java/android/annotation/ColorRes.java b/core/java/android/annotation/ColorRes.java deleted file mode 100644 index 061faa05c738..000000000000 --- a/core/java/android/annotation/ColorRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2013 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that an integer parameter, field or method return value is expected - * to be a color resource reference (e.g. {@link android.R.color#black}). - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface ColorRes { -} diff --git a/core/java/android/annotation/Condemned.java b/core/java/android/annotation/Condemned.java deleted file mode 100644 index 186409b3e204..000000000000 --- a/core/java/android/annotation/Condemned.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2017 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.annotation; - -import static java.lang.annotation.ElementType.CONSTRUCTOR; -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.LOCAL_VARIABLE; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PACKAGE; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * A program element annotated @Condemned is one that programmers are - * blocked from using, typically because it's about to be completely destroyed. - * <p> - * This is a stronger version of @Deprecated, and it's typically used to - * mark APIs that only existed temporarily in a preview SDK, and which only - * continue to exist temporarily to support binary compatibility. - * - * @hide - */ -@Retention(SOURCE) -@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE}) -public @interface Condemned { -} diff --git a/core/java/android/annotation/CurrentTimeMillisLong.java b/core/java/android/annotation/CurrentTimeMillisLong.java deleted file mode 100644 index 355bb5a2f960..000000000000 --- a/core/java/android/annotation/CurrentTimeMillisLong.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2017 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.annotation; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * @memberDoc Value is a non-negative timestamp measured as the number of - *            milliseconds since 1970-01-01T00:00:00Z. - * @paramDoc Value is a non-negative timestamp measured as the number of - *            milliseconds since 1970-01-01T00:00:00Z. - * @returnDoc Value is a non-negative timestamp measured as the number of - *            milliseconds since 1970-01-01T00:00:00Z. - * @hide - */ -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface CurrentTimeMillisLong { -} diff --git a/core/java/android/annotation/CurrentTimeSecondsLong.java b/core/java/android/annotation/CurrentTimeSecondsLong.java deleted file mode 100644 index 2b4ffd77ad34..000000000000 --- a/core/java/android/annotation/CurrentTimeSecondsLong.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2019 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.annotation; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * @memberDoc Value is a non-negative timestamp measured as the number of - *            seconds since 1970-01-01T00:00:00Z. - * @paramDoc Value is a non-negative timestamp measured as the number of - *            seconds since 1970-01-01T00:00:00Z. - * @returnDoc Value is a non-negative timestamp measured as the number of - *            seconds since 1970-01-01T00:00:00Z. - * @hide - */ -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface CurrentTimeSecondsLong { -} diff --git a/core/java/android/annotation/DimenRes.java b/core/java/android/annotation/DimenRes.java deleted file mode 100644 index 02ae00c6868c..000000000000 --- a/core/java/android/annotation/DimenRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2013 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that an integer parameter, field or method return value is expected - * to be a dimension resource reference (e.g. {@link android.R.dimen#app_icon_size}). - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface DimenRes { -} diff --git a/core/java/android/annotation/Dimension.java b/core/java/android/annotation/Dimension.java deleted file mode 100644 index 5f705ad52d9b..000000000000 --- a/core/java/android/annotation/Dimension.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2016 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.ANNOTATION_TYPE; -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.LOCAL_VARIABLE; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that a numeric parameter, field or method return value is expected - * to represent a dimension. - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD,PARAMETER,FIELD,LOCAL_VARIABLE,ANNOTATION_TYPE}) -public @interface Dimension { -    @Unit -    int unit() default PX; - -    int DP = 0; -    int PX = 1; -    int SP = 2; - -    @IntDef({PX, DP, SP}) -    @Retention(SOURCE) -    @interface Unit {} -} diff --git a/core/java/android/annotation/DisplayContext.java b/core/java/android/annotation/DisplayContext.java deleted file mode 100644 index e6b464ac237a..000000000000 --- a/core/java/android/annotation/DisplayContext.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - *      http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.annotation; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import android.app.Activity; -import android.app.WallpaperManager; -import android.content.Context; -import android.os.Bundle; -import android.view.Display; -import android.view.LayoutInflater; -import android.view.WindowManager; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * Denotes a {@link Context} that is tied to a {@link Display} and can be used to obtain one - * via {@link Context#getDisplay}, but <b>may not</b> be able to obtain {@link WindowManager}, - * {@link LayoutInflater} or {@link WallpaperManager} via {@link Context#getSystemService(String)}. - * If the UI services mentioned above are required, please use contexts which are marked as - * {@link UiContext}. - * <p> - * {@link Activity}, and the result of {@link Context#createWindowContext(int, Bundle)} or - * {@link Context#createDisplayContext(Display)} can be - * used where a {@link DisplayContext} is required. - * <p> - * This is a marker annotation and has no specific attributes. - * - * @see Context#getDisplay() - * @see Context#getSystemService(String) - * @see Context#getSystemService(Class) - * @see Context#createDisplayContext(Display) - * @see Context#createWindowContext(int, Bundle) - * @see UiContext - * @hide - */ -@Retention(SOURCE) -@Target({TYPE, METHOD, PARAMETER, FIELD}) -public @interface DisplayContext { -} diff --git a/core/java/android/annotation/DrawableRes.java b/core/java/android/annotation/DrawableRes.java deleted file mode 100644 index ebefa1d78ab1..000000000000 --- a/core/java/android/annotation/DrawableRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2013 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that an integer parameter, field or method return value is expected - * to be a drawable resource reference (e.g. {@link android.R.attr#alertDialogIcon}). - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface DrawableRes { -} diff --git a/core/java/android/annotation/DurationMillisLong.java b/core/java/android/annotation/DurationMillisLong.java deleted file mode 100644 index ce77532a6c6e..000000000000 --- a/core/java/android/annotation/DurationMillisLong.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2017 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.annotation; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * @memberDoc Value is a non-negative duration in milliseconds. - * @paramDoc Value is a non-negative duration in milliseconds. - * @returnDoc Value is a non-negative duration in milliseconds. - * @hide - */ -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface DurationMillisLong { -} diff --git a/core/java/android/annotation/ElapsedRealtimeLong.java b/core/java/android/annotation/ElapsedRealtimeLong.java deleted file mode 100644 index f77ff72062a6..000000000000 --- a/core/java/android/annotation/ElapsedRealtimeLong.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2017 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.annotation; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import android.os.SystemClock; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * @memberDoc Value is a non-negative timestamp in the - *            {@link SystemClock#elapsedRealtime()} time base. - * @paramDoc Value is a non-negative timestamp in the - *           {@link SystemClock#elapsedRealtime()} time base. - * @returnDoc Value is a non-negative timestamp in the - *            {@link SystemClock#elapsedRealtime()} time base. - * @hide - */ -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface ElapsedRealtimeLong { -} diff --git a/core/java/android/annotation/FloatRange.java b/core/java/android/annotation/FloatRange.java deleted file mode 100644 index 05b51680b1b0..000000000000 --- a/core/java/android/annotation/FloatRange.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2015 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.annotation; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.LOCAL_VARIABLE; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that the annotated element should be a float or double in the given range - * <p> - * Example: - * <pre><code> - *  @FloatRange(from=0.0,to=1.0) - *  public float getAlpha() { - *      ... - *  } - * </code></pre> - * - * @hide - */ -@Retention(SOURCE) -@Target({METHOD,PARAMETER,FIELD,LOCAL_VARIABLE}) -public @interface FloatRange { -    /** Smallest value. Whether it is inclusive or not is determined -     * by {@link #fromInclusive} */ -    double from() default Double.NEGATIVE_INFINITY; -    /** Largest value. Whether it is inclusive or not is determined -     * by {@link #toInclusive} */ -    double to() default Double.POSITIVE_INFINITY; - -    /** Whether the from value is included in the range */ -    boolean fromInclusive() default true; - -    /** Whether the to value is included in the range */ -    boolean toInclusive() default true; -}
\ No newline at end of file diff --git a/core/java/android/annotation/FontRes.java b/core/java/android/annotation/FontRes.java deleted file mode 100644 index dbacb5876dce..000000000000 --- a/core/java/android/annotation/FontRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2017 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that an integer parameter, field or method return value is expected - * to be a Font resource reference (e.g. R.font.myfont). - * - * @hide - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface FontRes { -} diff --git a/core/java/android/annotation/FractionRes.java b/core/java/android/annotation/FractionRes.java deleted file mode 100644 index fd84d3e85fdf..000000000000 --- a/core/java/android/annotation/FractionRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2013 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that an integer parameter, field or method return value is expected - * to be a fraction resource reference. - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface FractionRes { -} diff --git a/core/java/android/annotation/HalfFloat.java b/core/java/android/annotation/HalfFloat.java deleted file mode 100644 index 256008c5e31f..000000000000 --- a/core/java/android/annotation/HalfFloat.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2016 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.annotation; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.LOCAL_VARIABLE; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * <p>Denotes that the annotated element represents a half-precision floating point - * value. Such values are stored in short data types and can be manipulated with - * the {@link android.util.Half} class. If applied to an array of short, every - * element in the array represents a half-precision float.</p> - * - * <p>Example:</p> - * - * <pre>{@code - * public abstract void setPosition(@HalfFloat short x, @HalfFloat short y, @HalfFloat short z); - * }</pre> - * - * @see android.util.Half - * @see android.util.Half#toHalf(float) - * @see android.util.Half#toFloat(short) - * - * @hide - */ -@Retention(SOURCE) -@Target({PARAMETER, METHOD, LOCAL_VARIABLE, FIELD}) -public @interface HalfFloat { -} diff --git a/core/java/android/annotation/Hide.java b/core/java/android/annotation/Hide.java deleted file mode 100644 index c8e5a4a97ae7..000000000000 --- a/core/java/android/annotation/Hide.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2019 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.annotation; - -import static java.lang.annotation.ElementType.ANNOTATION_TYPE; -import static java.lang.annotation.ElementType.CONSTRUCTOR; -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PACKAGE; -import static java.lang.annotation.ElementType.TYPE; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Indicates that an API is hidden by default, in a similar fashion to the - * <pre>@hide</pre> javadoc tag. - * - * <p>Note that, in order for this to work, metalava has to be invoked with - * the flag {@code --hide-annotation android.annotation.Hide}. - * @hide - */ -@Target({TYPE, FIELD, METHOD, CONSTRUCTOR, ANNOTATION_TYPE, PACKAGE}) -@Retention(RetentionPolicy.CLASS) -public @interface Hide { -} diff --git a/core/java/android/annotation/IdRes.java b/core/java/android/annotation/IdRes.java deleted file mode 100644 index b286965c99d9..000000000000 --- a/core/java/android/annotation/IdRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2013 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that an integer parameter, field or method return value is expected - * to be an id resource reference (e.g. {@link android.R.id#copy}). - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface IdRes { -} diff --git a/core/java/android/annotation/IntDef.java b/core/java/android/annotation/IntDef.java deleted file mode 100644 index f84a67655dc3..000000000000 --- a/core/java/android/annotation/IntDef.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2013 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.annotation; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.ANNOTATION_TYPE; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that the annotated element of integer type, represents - * a logical type and that its value should be one of the explicitly - * named constants. If the {@link #flag()} attribute is set to true, - * multiple constants can be combined. - * <p> - * <pre><code> - *  @Retention(SOURCE) - *  @IntDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS}) - *  public @interface NavigationMode {} - *  public static final int NAVIGATION_MODE_STANDARD = 0; - *  public static final int NAVIGATION_MODE_LIST = 1; - *  public static final int NAVIGATION_MODE_TABS = 2; - *  ... - *  public abstract void setNavigationMode(@NavigationMode int mode); - *  @NavigationMode - *  public abstract int getNavigationMode(); - * </code></pre> - * For a flag, set the flag attribute: - * <pre><code> - *  @IntDef( - *      flag = true, - *      value = {NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS}) - * </code></pre> - * - * @hide - */ -@Retention(SOURCE) -@Target({ANNOTATION_TYPE}) -public @interface IntDef { -    /** Defines the constant prefix for this element */ -    String[] prefix() default {}; -    /** Defines the constant suffix for this element */ -    String[] suffix() default {}; - -    /** Defines the allowed constants for this element */ -    int[] value() default {}; - -    /** Defines whether the constants can be used as a flag, or just as an enum (the default) */ -    boolean flag() default false; -} diff --git a/core/java/android/annotation/IntRange.java b/core/java/android/annotation/IntRange.java deleted file mode 100644 index c043e2db6a98..000000000000 --- a/core/java/android/annotation/IntRange.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2015 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.annotation; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.ANNOTATION_TYPE; -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.LOCAL_VARIABLE; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that the annotated element should be an int or long in the given range - * <p> - * Example: - * <pre><code> - *  @IntRange(from=0,to=255) - *  public int getAlpha() { - *      ... - *  } - * </code></pre> - * - * @hide - */ -@Retention(SOURCE) -@Target({METHOD,PARAMETER,FIELD,LOCAL_VARIABLE,ANNOTATION_TYPE}) -public @interface IntRange { -    /** Smallest value, inclusive */ -    long from() default Long.MIN_VALUE; -    /** Largest value, inclusive */ -    long to() default Long.MAX_VALUE; -}
\ No newline at end of file diff --git a/core/java/android/annotation/IntegerRes.java b/core/java/android/annotation/IntegerRes.java deleted file mode 100644 index 5313f4adf46e..000000000000 --- a/core/java/android/annotation/IntegerRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2013 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that an integer parameter, field or method return value is expected - * to be an integer resource reference (e.g. {@link android.R.integer#config_shortAnimTime}). - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface IntegerRes { -} diff --git a/core/java/android/annotation/InterpolatorRes.java b/core/java/android/annotation/InterpolatorRes.java deleted file mode 100644 index 8877a5f9a4f1..000000000000 --- a/core/java/android/annotation/InterpolatorRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2013 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that an integer parameter, field or method return value is expected - * to be an interpolator resource reference (e.g. {@link android.R.interpolator#cycle}). - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface InterpolatorRes { -} diff --git a/core/java/android/annotation/LayoutRes.java b/core/java/android/annotation/LayoutRes.java deleted file mode 100644 index 15ba86f98159..000000000000 --- a/core/java/android/annotation/LayoutRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2013 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that an integer parameter, field or method return value is expected - * to be a layout resource reference (e.g. {@link android.R.layout#list_content}). - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface LayoutRes { -} diff --git a/core/java/android/annotation/LongDef.java b/core/java/android/annotation/LongDef.java deleted file mode 100644 index 8723eef86328..000000000000 --- a/core/java/android/annotation/LongDef.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2017 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.annotation; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.ANNOTATION_TYPE; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that the annotated long element represents - * a logical type and that its value should be one of the explicitly - * named constants. If the {@link #flag()} attribute is set to true, - * multiple constants can be combined. - * <p> - * <pre><code> - *  @Retention(SOURCE) - *  @LongDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS}) - *  public @interface NavigationMode {} - *  public static final long NAVIGATION_MODE_STANDARD = 0; - *  public static final long NAVIGATION_MODE_LIST = 1; - *  public static final long NAVIGATION_MODE_TABS = 2; - *  ... - *  public abstract void setNavigationMode(@NavigationMode long mode); - *  @NavigationMode - *  public abstract long getNavigationMode(); - * </code></pre> - * For a flag, set the flag attribute: - * <pre><code> - *  @LongDef( - *      flag = true, - *      value = {NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS}) - * </code></pre> - * - * @hide - */ -@Retention(SOURCE) -@Target({ANNOTATION_TYPE}) -public @interface LongDef { -    /** Defines the constant prefix for this element */ -    String[] prefix() default ""; - -    /** Defines the allowed constants for this element */ -    long[] value() default {}; - -    /** Defines whether the constants can be used as a flag, or just as an enum (the default) */ -    boolean flag() default false; -} diff --git a/core/java/android/annotation/MainThread.java b/core/java/android/annotation/MainThread.java deleted file mode 100644 index a070246e5ef3..000000000000 --- a/core/java/android/annotation/MainThread.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2015 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.annotation; - -import static java.lang.annotation.ElementType.CONSTRUCTOR; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * Denotes that the annotated method should only be called on the main thread. - * If the annotated element is a class, then all methods in the class should be - * called on the main thread. - * <p> - * Example: - * - * <pre> - * <code> - *  @MainThread - *  public void deliverResult(D data) { ... } - * </code> - * </pre> - * - * @memberDoc This method must be called from the main thread of your app. - * @hide - */ -@Retention(SOURCE) -@Target({METHOD,CONSTRUCTOR,TYPE,PARAMETER}) -public @interface MainThread { -} diff --git a/core/java/android/annotation/MenuRes.java b/core/java/android/annotation/MenuRes.java deleted file mode 100644 index b6dcc4604cfb..000000000000 --- a/core/java/android/annotation/MenuRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2013 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that an integer parameter, field or method return value is expected - * to be a menu resource reference. - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface MenuRes { -} diff --git a/core/java/android/annotation/NavigationRes.java b/core/java/android/annotation/NavigationRes.java deleted file mode 100644 index 3af5ecff84a6..000000000000 --- a/core/java/android/annotation/NavigationRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2017 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that an integer parameter, field or method return value is expected - * to be a navigation resource reference (e.g. {@code R.navigation.flow}). - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface NavigationRes { -} diff --git a/core/java/android/annotation/NonNull.java b/core/java/android/annotation/NonNull.java deleted file mode 100644 index 20472bacf6ad..000000000000 --- a/core/java/android/annotation/NonNull.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2013 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.annotation; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * Denotes that a parameter, field or method return value can never be null. - * <p> - * This is a marker annotation and it has no specific attributes. - * - * @paramDoc This value cannot be {@code null}. - * @returnDoc This value cannot be {@code null}. - * @hide - */ -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface NonNull { -} diff --git a/core/java/android/annotation/NonUiContext.java b/core/java/android/annotation/NonUiContext.java deleted file mode 100644 index c119ca20ba11..000000000000 --- a/core/java/android/annotation/NonUiContext.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - *      http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.annotation; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import android.app.WallpaperManager; -import android.content.Context; -import android.view.Display; -import android.view.LayoutInflater; -import android.view.WindowManager; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * Denotes a {@link Context} that <b>can not</b> be used to obtain a {@link Display} via - * {@link Context#getDisplay} nor to obtain a {@link WindowManager}, {@link LayoutInflater} or - * {@link WallpaperManager} via {@link Context#getSystemService(String)}. - * <p> - * This is a marker annotation and has no specific attributes. - * - * @see Context#getDisplay() - * @see Context#getSystemService(String) - * @see Context#getSystemService(Class) - * @hide - */ -@Retention(SOURCE) -@Target({TYPE, METHOD, PARAMETER, FIELD}) -public @interface NonUiContext { -} diff --git a/core/java/android/annotation/Nullable.java b/core/java/android/annotation/Nullable.java deleted file mode 100644 index b8473e750c95..000000000000 --- a/core/java/android/annotation/Nullable.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2013 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.annotation; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * Denotes that a parameter, field or method return value can be null. - * <p> - * When decorating a method call parameter, this denotes that the parameter can - * legitimately be null and the method will gracefully deal with it. Typically - * used on optional parameters. - * <p> - * When decorating a method, this denotes the method might legitimately return - * null. - * <p> - * This is a marker annotation and it has no specific attributes. - * - * @paramDoc This value may be {@code null}. - * @returnDoc This value may be {@code null}. - * @hide - */ -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface Nullable { -} diff --git a/core/java/android/annotation/OWNERS b/core/java/android/annotation/OWNERS deleted file mode 100644 index e1ef54460b56..000000000000 --- a/core/java/android/annotation/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -tnorbye@google.com -aurimas@google.com -per-file UnsupportedAppUsage.java = mathewi@google.com, satayev@google.com, andreionea@google.com diff --git a/core/java/android/annotation/PluralsRes.java b/core/java/android/annotation/PluralsRes.java deleted file mode 100644 index 31ac729aaa47..000000000000 --- a/core/java/android/annotation/PluralsRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2013 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that an integer parameter, field or method return value is expected - * to be a plurals resource reference. - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface PluralsRes { -} diff --git a/core/java/android/annotation/Px.java b/core/java/android/annotation/Px.java deleted file mode 100644 index cec7f80405d3..000000000000 --- a/core/java/android/annotation/Px.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2016 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.LOCAL_VARIABLE; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that a numeric parameter, field or method return value is expected - * to represent a pixel dimension. - * - * @memberDoc This units of this value are pixels. - * @paramDoc This units of this value are pixels. - * @returnDoc This units of this value are pixels. - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE}) -@Dimension(unit = Dimension.PX) -public @interface Px { -} diff --git a/core/java/android/annotation/RawRes.java b/core/java/android/annotation/RawRes.java deleted file mode 100644 index 39970b36fd95..000000000000 --- a/core/java/android/annotation/RawRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2013 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that an integer parameter, field or method return value is expected - * to be a raw resource reference. - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface RawRes { -} diff --git a/core/java/android/annotation/RequiresFeature.java b/core/java/android/annotation/RequiresFeature.java deleted file mode 100644 index 08861d42be39..000000000000 --- a/core/java/android/annotation/RequiresFeature.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - *      http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.annotation; - -import static java.lang.annotation.ElementType.CONSTRUCTOR; -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import android.content.pm.PackageManager; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * Denotes that the annotated element requires one or more device features. This - * is used to auto-generate documentation. - * - * @hide - */ -@Retention(SOURCE) -@Target({TYPE,FIELD,METHOD,CONSTRUCTOR}) -public @interface RequiresFeature { -    /** -     * The name of the device feature that is required. -     */ -    String value(); - -    /** -     * Defines the name of the method that should be called to check whether the feature is -     * available, using the same signature format as javadoc. The feature checking method can have -     * multiple parameters, but the feature name parameter must be of type String and must also be -     * the first String-type parameter. -     * <p> -     * By default, the enforcement is {@link PackageManager#hasSystemFeature(String)}. -     */ -    String enforcement() default("android.content.pm.PackageManager#hasSystemFeature"); -} diff --git a/core/java/android/annotation/RequiresNoPermission.java b/core/java/android/annotation/RequiresNoPermission.java deleted file mode 100644 index cdbf36ec20dd..000000000000 --- a/core/java/android/annotation/RequiresNoPermission.java +++ /dev/null @@ -1,48 +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 android.annotation; - -import static java.lang.annotation.ElementType.ANNOTATION_TYPE; -import static java.lang.annotation.ElementType.CONSTRUCTOR; -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.CLASS; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * Denotes that the annotated element requires no permissions. - * <p> - * This explicit annotation helps distinguish which of three states that an - * element may exist in: - * <ul> - * <li>Annotated with {@link RequiresPermission}, indicating that an element - * requires (or may require) one or more permissions. - * <li>Annotated with {@link RequiresNoPermission}, indicating that an element - * requires no permissions. - * <li>Neither annotation, indicating that no explicit declaration about - * permissions has been made for that element. - * </ul> - * - * @see RequiresPermission - * @hide - */ -@Retention(CLASS) -@Target({ANNOTATION_TYPE,METHOD,CONSTRUCTOR,FIELD,PARAMETER}) -public @interface RequiresNoPermission { -} diff --git a/core/java/android/annotation/RequiresPermission.java b/core/java/android/annotation/RequiresPermission.java deleted file mode 100644 index 0379d303ab92..000000000000 --- a/core/java/android/annotation/RequiresPermission.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (C) 2015 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.annotation; - -import static java.lang.annotation.ElementType.ANNOTATION_TYPE; -import static java.lang.annotation.ElementType.CONSTRUCTOR; -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.CLASS; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * Denotes that the annotated element requires (or may require) one or more permissions. - * <p/> - * Example of requiring a single permission: - * <pre>{@code - *   {@literal @}RequiresPermission(Manifest.permission.SET_WALLPAPER) - *   public abstract void setWallpaper(Bitmap bitmap) throws IOException; - * - *   {@literal @}RequiresPermission(ACCESS_COARSE_LOCATION) - *   public abstract Location getLastKnownLocation(String provider); - * }</pre> - * Example of requiring at least one permission from a set: - * <pre>{@code - *   {@literal @}RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION}) - *   public abstract Location getLastKnownLocation(String provider); - * }</pre> - * Example of requiring multiple permissions: - * <pre>{@code - *   {@literal @}RequiresPermission(allOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION}) - *   public abstract Location getLastKnownLocation(String provider); - * }</pre> - * Example of requiring separate read and write permissions for a content provider: - * <pre>{@code - *   {@literal @}RequiresPermission.Read(@RequiresPermission(READ_HISTORY_BOOKMARKS)) - *   {@literal @}RequiresPermission.Write(@RequiresPermission(WRITE_HISTORY_BOOKMARKS)) - *   public static final Uri BOOKMARKS_URI = Uri.parse("content://browser/bookmarks"); - * }</pre> - * <p> - * When specified on a parameter, the annotation indicates that the method requires - * a permission which depends on the value of the parameter. For example, consider - * {@link android.app.Activity#startActivity(android.content.Intent) - * Activity#startActivity(Intent)}: - * <pre>{@code - *   public void startActivity(@RequiresPermission Intent intent) { ... } - * }</pre> - * Notice how there are no actual permission names listed in the annotation. The actual - * permissions required will depend on the particular intent passed in. For example, - * the code may look like this: - * <pre>{@code - *   Intent intent = new Intent(Intent.ACTION_CALL); - *   startActivity(intent); - * }</pre> - * and the actual permission requirement for this particular intent is described on - * the Intent name itself: - * <pre>{@code - *   {@literal @}RequiresPermission(Manifest.permission.CALL_PHONE) - *   public static final String ACTION_CALL = "android.intent.action.CALL"; - * }</pre> - * - * @see RequiresNoPermission - * @hide - */ -@Retention(CLASS) -@Target({ANNOTATION_TYPE,METHOD,CONSTRUCTOR,FIELD,PARAMETER}) -public @interface RequiresPermission { -    /** -     * The name of the permission that is required, if precisely one permission -     * is required. If more than one permission is required, specify either -     * {@link #allOf()} or {@link #anyOf()} instead. -     * <p> -     * If specified, {@link #anyOf()} and {@link #allOf()} must both be null. -     */ -    String value() default ""; - -    /** -     * Specifies a list of permission names that are all required. -     * <p> -     * If specified, {@link #anyOf()} and {@link #value()} must both be null. -     */ -    String[] allOf() default {}; - -    /** -     * Specifies a list of permission names where at least one is required -     * <p> -     * If specified, {@link #allOf()} and {@link #value()} must both be null. -     */ -    String[] anyOf() default {}; - -    /** -     * If true, the permission may not be required in all cases (e.g. it may only be -     * enforced on certain platforms, or for certain call parameters, etc. -     */ -    boolean conditional() default false; - -    /** -     * Specifies that the given permission is required for read operations. -     * <p> -     * When specified on a parameter, the annotation indicates that the method requires -     * a permission which depends on the value of the parameter (and typically -     * the corresponding field passed in will be one of a set of constants which have -     * been annotated with a <code>@RequiresPermission</code> annotation.) -     */ -    @Target({FIELD, METHOD, PARAMETER}) -    @interface Read { -        RequiresPermission value() default @RequiresPermission; -    } - -    /** -     * Specifies that the given permission is required for write operations. -     * <p> -     * When specified on a parameter, the annotation indicates that the method requires -     * a permission which depends on the value of the parameter (and typically -     * the corresponding field passed in will be one of a set of constants which have -     * been annotated with a <code>@RequiresPermission</code> annotation.) -     */ -    @Target({FIELD, METHOD, PARAMETER}) -    @interface Write { -        RequiresPermission value() default @RequiresPermission; -    } -} diff --git a/core/java/android/annotation/SdkConstant.java b/core/java/android/annotation/SdkConstant.java deleted file mode 100644 index 0a5318609847..000000000000 --- a/core/java/android/annotation/SdkConstant.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2008 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.annotation; - -import java.lang.annotation.Target; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Indicates a constant field value should be exported to be used in the SDK tools. - * @hide - */ -@Target({ ElementType.FIELD }) -@Retention(RetentionPolicy.SOURCE) -public @interface SdkConstant { -    public static enum SdkConstantType { -        ACTIVITY_INTENT_ACTION, BROADCAST_INTENT_ACTION, SERVICE_ACTION, INTENT_CATEGORY, FEATURE; -    } - -    SdkConstantType value(); -} diff --git a/core/java/android/annotation/Size.java b/core/java/android/annotation/Size.java deleted file mode 100644 index 7c3e70f658e9..000000000000 --- a/core/java/android/annotation/Size.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2015 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.annotation; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.LOCAL_VARIABLE; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that the annotated element should have a given size or length. - * Note that "-1" means "unset". Typically used with a parameter or - * return value of type array or collection. - * <p> - * Example: - * <pre>{@code - *  public void getLocationInWindow(@Size(2) int[] location) { - *      ... - *  } - * }</pre> - * - * @hide - */ -@Retention(SOURCE) -@Target({PARAMETER,LOCAL_VARIABLE,METHOD,FIELD}) -public @interface Size { -    /** An exact size (or -1 if not specified) */ -    long value() default -1; -    /** A minimum size, inclusive */ -    long min() default Long.MIN_VALUE; -    /** A maximum size, inclusive */ -    long max() default Long.MAX_VALUE; -    /** The size must be a multiple of this factor */ -    long multiple() default 1; -}
\ No newline at end of file diff --git a/core/java/android/annotation/StringDef.java b/core/java/android/annotation/StringDef.java deleted file mode 100644 index a37535b9c98e..000000000000 --- a/core/java/android/annotation/StringDef.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2013 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.annotation; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.ANNOTATION_TYPE; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that the annotated String element, represents a logical - * type and that its value should be one of the explicitly named constants. - * <p> - * Example: - * <pre><code> - *  @Retention(SOURCE) - *  @StringDef({ - *     POWER_SERVICE, - *     WINDOW_SERVICE, - *     LAYOUT_INFLATER_SERVICE - *  }) - *  public @interface ServiceName {} - *  public static final String POWER_SERVICE = "power"; - *  public static final String WINDOW_SERVICE = "window"; - *  public static final String LAYOUT_INFLATER_SERVICE = "layout_inflater"; - *  ... - *  public abstract Object getSystemService(@ServiceName String name); - * </code></pre> - * - * @hide - */ -@Retention(SOURCE) -@Target({ANNOTATION_TYPE}) -public @interface StringDef { -    /** Defines the constant prefix for this element */ -    String[] prefix() default {}; -    /** Defines the constant suffix for this element */ -    String[] suffix() default {}; - -    /** Defines the allowed constants for this element */ -    String[] value() default {}; -} diff --git a/core/java/android/annotation/StringRes.java b/core/java/android/annotation/StringRes.java deleted file mode 100644 index 190b68a9960b..000000000000 --- a/core/java/android/annotation/StringRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2013 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that an integer parameter, field or method return value is expected - * to be a String resource reference (e.g. {@link android.R.string#ok}). - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface StringRes { -} diff --git a/core/java/android/annotation/StyleRes.java b/core/java/android/annotation/StyleRes.java deleted file mode 100644 index 4453b8d89153..000000000000 --- a/core/java/android/annotation/StyleRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2013 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that a integer parameter, field or method return value is expected - * to be a style resource reference (e.g. {@link android.R.style#TextAppearance}). - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface StyleRes { -} diff --git a/core/java/android/annotation/StyleableRes.java b/core/java/android/annotation/StyleableRes.java deleted file mode 100644 index 3c1895e6dce9..000000000000 --- a/core/java/android/annotation/StyleableRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2013 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that a integer parameter, field or method return value is expected - * to be a styleable resource reference (e.g. {@link android.R.styleable#TextView_text}). - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface StyleableRes { -} diff --git a/core/java/android/annotation/SuppressAutoDoc.java b/core/java/android/annotation/SuppressAutoDoc.java deleted file mode 100644 index e34e03bcee29..000000000000 --- a/core/java/android/annotation/SuppressAutoDoc.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2017 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.annotation; - -import static java.lang.annotation.ElementType.CONSTRUCTOR; -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.LOCAL_VARIABLE; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * Denotes that any automatically generated documentation should be suppressed - * for the annotated method, parameter, or field. - * - * @hide - */ -@Retention(SOURCE) -@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) -public @interface SuppressAutoDoc { -} diff --git a/core/java/android/annotation/SuppressLint.java b/core/java/android/annotation/SuppressLint.java deleted file mode 100644 index 2d3456b0ea46..000000000000 --- a/core/java/android/annotation/SuppressLint.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2012 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.annotation; - -import static java.lang.annotation.ElementType.CONSTRUCTOR; -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.LOCAL_VARIABLE; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.ElementType.TYPE; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** Indicates that Lint should ignore the specified warnings for the annotated element. */ -@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) -@Retention(RetentionPolicy.CLASS) -public @interface SuppressLint { -    /** -     * The set of warnings (identified by the lint issue id) that should be -     * ignored by lint. It is not an error to specify an unrecognized name. -     */ -    String[] value(); -} diff --git a/core/java/android/annotation/SystemApi.java b/core/java/android/annotation/SystemApi.java deleted file mode 100644 index a468439c8e74..000000000000 --- a/core/java/android/annotation/SystemApi.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2014 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.annotation; - -import static java.lang.annotation.ElementType.ANNOTATION_TYPE; -import static java.lang.annotation.ElementType.CONSTRUCTOR; -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PACKAGE; -import static java.lang.annotation.ElementType.TYPE; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Indicates an API is exposed for use by bundled system applications. - * <p> - * These APIs are not guaranteed to remain consistent release-to-release, - * and are not for use by apps linking against the Android SDK. - * </p><p> - * This annotation should only appear on API that is already marked <pre>@hide</pre>. - * </p> - * - * @hide - */ -@Target({TYPE, FIELD, METHOD, CONSTRUCTOR, ANNOTATION_TYPE, PACKAGE}) -@Retention(RetentionPolicy.RUNTIME) -public @interface SystemApi { -    enum Client { -        /** -         * Specifies that the intended clients of a SystemApi are privileged apps. -         * This is the default value for {@link #client}. -         */ -        PRIVILEGED_APPS, - -        /** -         * Specifies that the intended clients of a SystemApi are used by classes in -         * <pre>BOOTCLASSPATH</pre> in mainline modules. Mainline modules can also expose -         * this type of system APIs too when they're used only by the non-updatable -         * platform code. -         */ -        MODULE_LIBRARIES, - -        /** -         * Specifies that the system API is available only in the system server process. -         * Use this to expose APIs from code loaded by the system server process <em>but</em> -         * not in <pre>BOOTCLASSPATH</pre>. -         */ -        SYSTEM_SERVER -    } - -    /** -     * The intended client of this SystemAPI. -     */ -    Client client() default android.annotation.SystemApi.Client.PRIVILEGED_APPS; - -    /** -     * Container for {@link SystemApi} that allows it to be applied repeatedly to types. -     */ -    @Retention(RetentionPolicy.RUNTIME) -    @Target(TYPE) -    @interface Container { -        SystemApi[] value(); -    } -} diff --git a/core/java/android/annotation/SystemService.java b/core/java/android/annotation/SystemService.java deleted file mode 100644 index c05c1bab06d2..000000000000 --- a/core/java/android/annotation/SystemService.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2017 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.annotation; - -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * Description of a system service available through - * {@link android.content.Context#getSystemService(Class)}. This is used to auto-generate - * documentation explaining how to obtain a reference to the service. - * - * @hide - */ -@Retention(SOURCE) -@Target(TYPE) -public @interface SystemService { -    /** -     * The string name of the system service that can be passed to -     * {@link android.content.Context#getSystemService(String)}. -     * -     * @see android.content.Context#getSystemServiceName(Class) -     */ -    String value(); -} diff --git a/core/java/android/annotation/TargetApi.java b/core/java/android/annotation/TargetApi.java deleted file mode 100644 index 975318e4de67..000000000000 --- a/core/java/android/annotation/TargetApi.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2012 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.annotation; - -import static java.lang.annotation.ElementType.CONSTRUCTOR; -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.TYPE; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** Indicates that Lint should treat this type as targeting a given API level, no matter what the -    project target is. */ -@Target({TYPE, METHOD, CONSTRUCTOR, FIELD}) -@Retention(RetentionPolicy.CLASS) -public @interface TargetApi { -    /** -     * This sets the target api level for the type.. -     */ -    int value(); -} diff --git a/core/java/android/annotation/TestApi.java b/core/java/android/annotation/TestApi.java deleted file mode 100644 index 0e9ed3751246..000000000000 --- a/core/java/android/annotation/TestApi.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2015 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.annotation; - -import static java.lang.annotation.ElementType.ANNOTATION_TYPE; -import static java.lang.annotation.ElementType.CONSTRUCTOR; -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PACKAGE; -import static java.lang.annotation.ElementType.TYPE; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Indicates an API is exposed for use by CTS. - * <p> - * These APIs are not guaranteed to remain consistent release-to-release, - * and are not for use by apps linking against the Android SDK. - * </p> - * - * @hide - */ -@Target({TYPE, FIELD, METHOD, CONSTRUCTOR, ANNOTATION_TYPE, PACKAGE}) -@Retention(RetentionPolicy.SOURCE) -public @interface TestApi { -} diff --git a/core/java/android/annotation/TransitionRes.java b/core/java/android/annotation/TransitionRes.java deleted file mode 100644 index 06bac74984a5..000000000000 --- a/core/java/android/annotation/TransitionRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2015 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that an integer parameter, field or method return value is expected - * to be a transition resource reference. - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface TransitionRes { -} diff --git a/core/java/android/annotation/UiContext.java b/core/java/android/annotation/UiContext.java deleted file mode 100644 index 47becc08c2f3..000000000000 --- a/core/java/android/annotation/UiContext.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - *      http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.annotation; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import android.app.Activity; -import android.app.WallpaperManager; -import android.content.Context; -import android.os.Bundle; -import android.view.Display; -import android.view.LayoutInflater; -import android.view.WindowManager; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * Denotes a {@link Context} that can be used to create UI, meaning that it can provide a - * {@link Display} via {@link Context#getDisplay} and can be used to obtain a {@link WindowManager}, - * {@link LayoutInflater} or {@link WallpaperManager} via {@link Context#getSystemService(String)}. - * A {@link Context} which is marked as {@link UiContext} implies that the {@link Context} is also - * a {@link DisplayContext}. - * <p> - * This kind of {@link Context} is usually an {@link Activity} or - * created via {@link Context#createWindowContext(int, Bundle)}. - * </p> - * This is a marker annotation and has no specific attributes. - * - * @see Context#getDisplay() - * @see Context#getSystemService(String) - * @see Context#getSystemService(Class) - * @see Context#createWindowContext(int, Bundle) - * @see DisplayContext - * @hide - */ -@Retention(SOURCE) -@Target({TYPE, METHOD, PARAMETER, FIELD}) -public @interface UiContext { -} diff --git a/core/java/android/annotation/UiThread.java b/core/java/android/annotation/UiThread.java deleted file mode 100644 index 6d7eedc7d2e2..000000000000 --- a/core/java/android/annotation/UiThread.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2015 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.annotation; - -import static java.lang.annotation.ElementType.CONSTRUCTOR; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import android.os.Looper; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * Denotes that the annotated method or constructor should only be called on the - * UI thread. If the annotated element is a class, then all methods in the class - * should be called on the UI thread. - * <p> - * Example: - * - * <pre> - * <code> - *  @UiThread - *  public abstract void setText(@NonNull String text) { ... } - * </code> - * </pre> - * - * @memberDoc This method must be called on the thread that originally created - *            this UI element. This is typically the - *            {@linkplain Looper#getMainLooper() main thread} of your app. - * @hide - */ -@Retention(SOURCE) -@Target({METHOD,CONSTRUCTOR,TYPE,PARAMETER}) -public @interface UiThread { -} diff --git a/core/java/android/annotation/UptimeMillisLong.java b/core/java/android/annotation/UptimeMillisLong.java deleted file mode 100644 index 8946eea0249c..000000000000 --- a/core/java/android/annotation/UptimeMillisLong.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - *      http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.annotation; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import android.os.SystemClock; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * @memberDoc Value is a non-negative timestamp in the - *            {@link SystemClock#uptimeMillis()} time base. - * @paramDoc Value is a non-negative timestamp in the - *            {@link SystemClock#uptimeMillis()} time base. - * @returnDoc Value is a non-negative timestamp in the - *            {@link SystemClock#uptimeMillis()} time base. - * @hide - */ -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface UptimeMillisLong { -} diff --git a/core/java/android/annotation/UserHandleAware.java b/core/java/android/annotation/UserHandleAware.java deleted file mode 100644 index 7d3d20b31b2a..000000000000 --- a/core/java/android/annotation/UserHandleAware.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2019 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.annotation; - -import static java.lang.annotation.ElementType.CONSTRUCTOR; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PACKAGE; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * Indicates an API that uses {@code context.getUser} or {@code context.getUserId} - * to operate across users (as the user associated with the context) - * <p> - * To create a {@link android.content.Context} associated with a different user, - *  use {@link android.content.Context#createContextAsUser} or - *  {@link android.content.Context#createPackageContextAsUser} - * <p> - * Example: - * <pre>{@code - * {@literal @}UserHandleAware - * public abstract PackageInfo getPackageInfo({@literal @}NonNull String packageName, - *      {@literal @}PackageInfoFlags int flags) throws NameNotFoundException; - * }</pre> - * - * @memberDoc This method uses {@linkplain android.content.Context#getUser} - *            or {@linkplain android.content.Context#getUserId} to execute across users. - * @hide - */ -@Retention(SOURCE) -@Target({TYPE, METHOD, CONSTRUCTOR, PACKAGE}) -public @interface UserHandleAware { -} diff --git a/core/java/android/annotation/UserIdInt.java b/core/java/android/annotation/UserIdInt.java deleted file mode 100644 index 7b9ce25e3f1a..000000000000 --- a/core/java/android/annotation/UserIdInt.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2016 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.annotation; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * Denotes that the annotated element is a multi-user user ID. This is - * <em>not</em> the same as a UID. - * - * @hide - */ -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface UserIdInt { -} diff --git a/core/java/android/annotation/Widget.java b/core/java/android/annotation/Widget.java deleted file mode 100644 index 6756cd73c5fe..000000000000 --- a/core/java/android/annotation/Widget.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2008 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.annotation; - -import java.lang.annotation.Target; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Indicates a class is a widget usable by application developers to create UI. - * <p> - * This must be used in cases where: - * <ul> - * <li>The widget is not in the package <code>android.widget</code></li> - * <li>The widget extends <code>android.view.ViewGroup</code></li> - * </ul> - * @hide - */ -@Target({ ElementType.TYPE }) -@Retention(RetentionPolicy.SOURCE) -public @interface Widget { -} diff --git a/core/java/android/annotation/WorkerThread.java b/core/java/android/annotation/WorkerThread.java deleted file mode 100644 index 8c2a4d381ab1..000000000000 --- a/core/java/android/annotation/WorkerThread.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2015 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.annotation; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.CONSTRUCTOR; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that the annotated method should only be called on a worker thread. - * If the annotated element is a class, then all methods in the class should be - * called on a worker thread. - * <p> - * Example: - * - * <pre> - * <code> - *  @WorkerThread - *  protected abstract FilterResults performFiltering(CharSequence constraint); - * </code> - * </pre> - * - * @memberDoc This method may take several seconds to complete, so it should - *            only be called from a worker thread. - * @hide - */ -@Retention(SOURCE) -@Target({METHOD,CONSTRUCTOR,TYPE,PARAMETER}) -public @interface WorkerThread { -} diff --git a/core/java/android/annotation/XmlRes.java b/core/java/android/annotation/XmlRes.java deleted file mode 100644 index 5fb8a4a47127..000000000000 --- a/core/java/android/annotation/XmlRes.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2013 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * Denotes that an integer parameter, field or method return value is expected - * to be an XML resource reference. - * - * {@hide} - */ -@Documented -@Retention(SOURCE) -@Target({METHOD, PARAMETER, FIELD}) -public @interface XmlRes { -} diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java index c21de62ed38e..80f1e6eab9df 100644 --- a/core/java/android/app/ActivityOptions.java +++ b/core/java/android/app/ActivityOptions.java @@ -1447,13 +1447,7 @@ public class ActivityOptions {      }      /** -     * Sets the windowing mode the activity should launch into. If the input windowing mode is -     * {@link android.app.WindowConfiguration#WINDOWING_MODE_SPLIT_SCREEN_SECONDARY} and the device -     * isn't currently in split-screen windowing mode, then the activity will be launched in -     * {@link android.app.WindowConfiguration#WINDOWING_MODE_FULLSCREEN} windowing mode. For clarity -     * on this you can use -     * {@link android.app.WindowConfiguration#WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY} -     * +     * Sets the windowing mode the activity should launch into.       * @hide       */      @TestApi diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index b3e656d30752..ff210e1c0ea6 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -5613,7 +5613,7 @@ public final class ActivityThread extends ClientTransactionHandler      }      /** Performs the activity relaunch locally vs. requesting from system-server. */ -    private void handleRelaunchActivityLocally(IBinder token) { +    public void handleRelaunchActivityLocally(IBinder token) {          final ActivityClientRecord r = mActivities.get(token);          if (r == null) {              Log.w(TAG, "Activity to relaunch no longer exists"); @@ -5977,20 +5977,6 @@ public final class ActivityThread extends ClientTransactionHandler              // Update all affected Resources objects to use new ResourcesImpl              mResourcesManager.applyNewResourceDirsLocked(ai, oldResDirs);          } - -        ApplicationPackageManager.configurationChanged(); - -        // Trigger a regular Configuration change event, only with a different assetsSeq number -        // so that we actually call through to all components. -        // TODO(adamlesinski): Change this to make use of ActivityManager's upcoming ability to -        // store configurations per-process. -        final Configuration config = mConfigurationController.getConfiguration(); -        Configuration newConfig = new Configuration(); -        newConfig.assetsSeq = (config != null ? config.assetsSeq : 0) + 1; -        mConfigurationController.handleConfigurationChanged(newConfig, null /* compat */); - -        // Preserve windows to avoid black flickers when overlays change. -        relaunchAllActivities(true /* preserveWindows */, "handleApplicationInfoChanged");      }      /** diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index d77ce4addacc..75a38c2380b9 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -1894,7 +1894,7 @@ public class AppOpsManager {              OP_MANAGE_MEDIA,                    // MANAGE_MEDIA              OP_BLUETOOTH_CONNECT,               // OP_BLUETOOTH_CONNECT              OP_UWB_RANGING,                     // OP_UWB_RANGING -            OP_ACTIVITY_RECOGNITION_SOURCE,     // OP_ACTIVITY_RECOGNITION_SOURCE +            OP_ACTIVITY_RECOGNITION,            // OP_ACTIVITY_RECOGNITION_SOURCE              OP_BLUETOOTH_ADVERTISE,             // OP_BLUETOOTH_ADVERTISE              OP_RECORD_INCOMING_PHONE_AUDIO,     // OP_RECORD_INCOMING_PHONE_AUDIO      }; @@ -4723,8 +4723,8 @@ public class AppOpsManager {      }      /** -     * Flag for querying app op history: get only aggregate information and no -     * discrete accesses. +     * Flag for querying app op history: get only aggregate information (counts of events) and no +     * discret accesses information - specific accesses with timestamp.       *       * @see #getHistoricalOps(HistoricalOpsRequest, Executor, Consumer)       * @@ -4735,8 +4735,8 @@ public class AppOpsManager {      public static final int HISTORY_FLAG_AGGREGATE = 1 << 0;      /** -     * Flag for querying app op history: get only discrete information and no -     * aggregate accesses. +     * Flag for querying app op history: get only discrete access information (only specific +     * accesses with timestamps) and no aggregate information (counts over time).       *       * @see #getHistoricalOps(HistoricalOpsRequest, Executor, Consumer)       * @@ -4747,7 +4747,7 @@ public class AppOpsManager {      public static final int HISTORY_FLAG_DISCRETE = 1 << 1;      /** -     * Flag for querying app op history: get all types of historical accesses. +     * Flag for querying app op history: get all types of historical access information.       *       * @see #getHistoricalOps(HistoricalOpsRequest, Executor, Consumer)       * diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index dba62b9d3b63..5a70f925fc02 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -881,7 +881,7 @@ public class ApplicationPackageManager extends PackageManager {      @Override      public void requestChecksums(@NonNull String packageName, boolean includeSplits, -            @Checksum.Type int required, @NonNull List<Certificate> trustedInstallers, +            @Checksum.TypeMask int required, @NonNull List<Certificate> trustedInstallers,              @NonNull OnChecksumsReadyListener onChecksumsReadyListener)              throws CertificateEncodingException, NameNotFoundException {          Objects.requireNonNull(packageName); diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java index d04ca1d9a48e..4ff7924c4b98 100644 --- a/core/java/android/app/WindowConfiguration.java +++ b/core/java/android/app/WindowConfiguration.java @@ -106,19 +106,9 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu       * {@link ActivityOptions#setLaunchWindowingMode(int)} will be launched in       * {@link #WINDOWING_MODE_FULLSCREEN} if the display isn't currently in split-screen windowing       * mode -     * @see #WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY       */      // TODO: Remove once split-screen is migrated to wm-shell.      public static final int WINDOWING_MODE_SPLIT_SCREEN_SECONDARY = 4; -    /** -     * Alias for {@link #WINDOWING_MODE_SPLIT_SCREEN_SECONDARY} that makes it clear that the usage -     * points for APIs like {@link ActivityOptions#setLaunchWindowingMode(int)} that the container -     * will launch into fullscreen or split-screen secondary depending on if the device is currently -     * in fullscreen mode or split-screen mode. -     */ -    // TODO: Remove once split-screen is migrated to wm-shell. -    public static final int WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY = -            WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;      /** Can be freely resized within its parent container. */      // TODO: Remove once freeform is migrated to wm-shell.      public static final int WINDOWING_MODE_FREEFORM = 5; @@ -133,7 +123,6 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu              WINDOWING_MODE_PINNED,              WINDOWING_MODE_SPLIT_SCREEN_PRIMARY,              WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, -            WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY,              WINDOWING_MODE_FREEFORM,      })      public @interface WindowingMode {} diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 7dc662abe0c1..609c014feb5b 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -5513,6 +5513,10 @@ public class DevicePolicyManager {       * This method requires the caller to be the device owner.       * <p>       * This proxy is only a recommendation and it is possible that some apps will ignore it. +     * <p> +     * Note: The device owner won't be able to set a global HTTP proxy if there are unaffiliated +     * secondary users or profiles on the device. It's recommended that affiliation ids are set for +     * new users as soon as possible after provisioning via {@link #setAffiliationIds}.       *       * @see ProxyInfo       * @param admin Which {@link DeviceAdminReceiver} this request is associated with. @@ -12791,6 +12795,11 @@ public class DevicePolicyManager {       * <p>In this mode, the DNS subsystem will attempt a TLS handshake to the network-supplied       * resolver prior to attempting name resolution in cleartext.       * +     * <p>Note: The device owner won't be able to set the global private DNS mode if there are +     * unaffiliated secondary users or profiles on the device. It's recommended that affiliation +     * ids are set for new users as soon as possible after provisioning via +     * {@link #setAffiliationIds}. +     *       * @param admin which {@link DeviceAdminReceiver} this request is associated with.       *       * @return {@code PRIVATE_DNS_SET_NO_ERROR} if the mode was set successfully, or @@ -12826,6 +12835,11 @@ public class DevicePolicyManager {       * the ability to resolve hostnames as system traffic to the resolver may not go through the       * VPN.       * +     * <p>Note: The device owner won't be able to set the global private DNS mode if there are +     * unaffiliated secondary users or profiles on the device. It's recommended that affiliation +     * ids are set for new users as soon as possible after provisioning via +     * {@link #setAffiliationIds}. +     *       * @param admin which {@link DeviceAdminReceiver} this request is associated with.       * @param privateDnsHost The hostname of a server that implements DNS over TLS (RFC7858).       * diff --git a/core/java/android/app/people/PeopleSpaceTile.java b/core/java/android/app/people/PeopleSpaceTile.java index de3eeee281ac..2dbbfdf660aa 100644 --- a/core/java/android/app/people/PeopleSpaceTile.java +++ b/core/java/android/app/people/PeopleSpaceTile.java @@ -43,6 +43,12 @@ import java.util.List;   */  public class PeopleSpaceTile implements Parcelable { +    public static final int SHOW_CONVERSATIONS = 1 << 0; +    public static final int BLOCK_CONVERSATIONS =  1 << 1; +    public static final int SHOW_IMPORTANT_CONVERSATIONS = 1 << 2; +    public static final int SHOW_STARRED_CONTACTS = 1 << 3; +    public static final int SHOW_CONTACTS = 1 << 4; +      private String mId;      private CharSequence mUserName;      private Icon mUserIcon; @@ -61,6 +67,11 @@ public class PeopleSpaceTile implements Parcelable {      private Intent mIntent;      private long mNotificationTimestamp;      private List<ConversationStatus> mStatuses; +    private boolean mCanBypassDnd; +    private boolean mIsPackageSuspended; +    private boolean mIsUserQuieted; +    private int mNotificationPolicyState; +    private float mContactAffinity;      private PeopleSpaceTile(Builder b) {          mId = b.mId; @@ -81,6 +92,11 @@ public class PeopleSpaceTile implements Parcelable {          mIntent = b.mIntent;          mNotificationTimestamp = b.mNotificationTimestamp;          mStatuses = b.mStatuses; +        mCanBypassDnd = b.mCanBypassDnd; +        mIsPackageSuspended = b.mIsPackageSuspended; +        mIsUserQuieted = b.mIsUserQuieted; +        mNotificationPolicyState = b.mNotificationPolicyState; +        mContactAffinity = b.mContactAffinity;      }      public String getId() { @@ -173,6 +189,41 @@ public class PeopleSpaceTile implements Parcelable {          return mStatuses;      } +    /** +     * Whether the app associated with the conversation can bypass DND. +     */ +    public boolean canBypassDnd() { +        return mCanBypassDnd; +    } + +    /** +     * Whether the app associated with the conversation is suspended. +     */ +    public boolean isPackageSuspended() { +        return mIsPackageSuspended; +    } + +    /** +     * Whether the user associated with the conversation is quieted. +     */ +    public boolean isUserQuieted() { +        return mIsUserQuieted; +    } + +    /** +     * Returns the state of notifications for the conversation. +     */ +    public int getNotificationPolicyState() { +        return mNotificationPolicyState; +    } + +    /** +     * Returns the contact affinity (whether the contact is starred). +     */ +    public float getContactAffinity() { +        return mContactAffinity; +    } +      /** Converts a {@link PeopleSpaceTile} into a {@link PeopleSpaceTile.Builder}. */      public Builder toBuilder() {          Builder builder = @@ -192,6 +243,11 @@ public class PeopleSpaceTile implements Parcelable {          builder.setIntent(mIntent);          builder.setNotificationTimestamp(mNotificationTimestamp);          builder.setStatuses(mStatuses); +        builder.setCanBypassDnd(mCanBypassDnd); +        builder.setIsPackageSuspended(mIsPackageSuspended); +        builder.setIsUserQuieted(mIsUserQuieted); +        builder.setNotificationPolicyState(mNotificationPolicyState); +        builder.setContactAffinity(mContactAffinity);          return builder;      } @@ -215,6 +271,11 @@ public class PeopleSpaceTile implements Parcelable {          private Intent mIntent;          private long mNotificationTimestamp;          private List<ConversationStatus> mStatuses; +        private boolean mCanBypassDnd; +        private boolean mIsPackageSuspended; +        private boolean mIsUserQuieted; +        private int mNotificationPolicyState; +        private float mContactAffinity;          /** Builder for use only if a shortcut is not available for the tile. */          public Builder(String id, CharSequence userName, Icon userIcon, Intent intent) { @@ -223,6 +284,7 @@ public class PeopleSpaceTile implements Parcelable {              mUserIcon = userIcon;              mIntent = intent;              mPackageName = intent == null ? null : intent.getPackage(); +            mNotificationPolicyState = SHOW_CONVERSATIONS;          }          public Builder(ShortcutInfo info, LauncherApps launcherApps) { @@ -232,6 +294,7 @@ public class PeopleSpaceTile implements Parcelable {              mUserHandle = info.getUserHandle();              mPackageName = info.getPackage();              mContactUri = getContactUri(info); +            mNotificationPolicyState = SHOW_CONVERSATIONS;          }          public Builder(ConversationChannel channel, LauncherApps launcherApps) { @@ -246,6 +309,9 @@ public class PeopleSpaceTile implements Parcelable {              mLastInteractionTimestamp = channel.getLastEventTimestamp();              mIsImportantConversation = channel.getParentNotificationChannel() != null                      && channel.getParentNotificationChannel().isImportantConversation(); +            mCanBypassDnd = channel.getParentNotificationChannel() != null +                    && channel.getParentNotificationChannel().canBypassDnd(); +            mNotificationPolicyState = SHOW_CONVERSATIONS;          }          /** Returns the Contact's Uri if present. */ @@ -366,6 +432,36 @@ public class PeopleSpaceTile implements Parcelable {              return this;          } +        /** Sets whether the conversation channel can bypass DND. */ +        public Builder setCanBypassDnd(boolean canBypassDnd) { +            mCanBypassDnd = canBypassDnd; +            return this; +        } + +        /** Sets whether the package is suspended. */ +        public Builder setIsPackageSuspended(boolean isPackageSuspended) { +            mIsPackageSuspended = isPackageSuspended; +            return this; +        } + +        /** Sets whether the user has been quieted. */ +        public Builder setIsUserQuieted(boolean isUserQuieted) { +            mIsUserQuieted = isUserQuieted; +            return this; +        } + +        /** Sets the state of blocked notifications for the conversation. */ +        public Builder setNotificationPolicyState(int notificationPolicyState) { +            mNotificationPolicyState = notificationPolicyState; +            return this; +        } + +        /** Sets the contact's affinity. */ +        public Builder setContactAffinity(float contactAffinity) { +            mContactAffinity = contactAffinity; +            return this; +        } +          /** Builds a {@link PeopleSpaceTile}. */          @NonNull          public PeopleSpaceTile build() { @@ -393,6 +489,11 @@ public class PeopleSpaceTile implements Parcelable {          mNotificationTimestamp = in.readLong();          mStatuses = new ArrayList<>();          in.readParcelableList(mStatuses, ConversationStatus.class.getClassLoader()); +        mCanBypassDnd = in.readBoolean(); +        mIsPackageSuspended = in.readBoolean(); +        mIsUserQuieted = in.readBoolean(); +        mNotificationPolicyState = in.readInt(); +        mContactAffinity = in.readFloat();      }      @Override @@ -420,6 +521,11 @@ public class PeopleSpaceTile implements Parcelable {          dest.writeParcelable(mIntent, flags);          dest.writeLong(mNotificationTimestamp);          dest.writeParcelableList(mStatuses, flags); +        dest.writeBoolean(mCanBypassDnd); +        dest.writeBoolean(mIsPackageSuspended); +        dest.writeBoolean(mIsUserQuieted); +        dest.writeInt(mNotificationPolicyState); +        dest.writeFloat(mContactAffinity);      }      public static final @android.annotation.NonNull @@ -427,7 +533,6 @@ public class PeopleSpaceTile implements Parcelable {                  public PeopleSpaceTile createFromParcel(Parcel source) {                      return new PeopleSpaceTile(source);                  } -                  public PeopleSpaceTile[] newArray(int size) {                      return new PeopleSpaceTile[size];                  } diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java index 114ad874d0c4..7e1df1b0e59c 100644 --- a/core/java/android/content/ContentProvider.java +++ b/core/java/android/content/ContentProvider.java @@ -1885,9 +1885,9 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall       * in {@link android.provider.MediaStore.MediaColumns}.</p>       *       * @param uri The URI whose file is to be opened. -     * @param mode The string representation of the file mode. Can be "r", "w", -     *            "wt", "wa", "rw" or "rwt". See -     *            {@link ParcelFileDescriptor#parseMode} for more details. +     * @param mode Access mode for the file.  May be "r" for read-only access, +     * "rw" for read and write access, or "rwt" for read and write access +     * that truncates any existing file.       *       * @return Returns a new ParcelFileDescriptor which you can use to access       * the file. @@ -1948,9 +1948,10 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall       * in {@link android.provider.MediaStore.MediaColumns}.</p>       *       * @param uri The URI whose file is to be opened. -     * @param mode The string representation of the file mode. Can be "r", "w", -     *            "wt", "wa", "rw" or "rwt". See -     *            {@link ParcelFileDescriptor#parseMode} for more details. +     * @param mode Access mode for the file. May be "r" for read-only access, +     *            "w" for write-only access, "rw" for read and write access, or +     *            "rwt" for read and write access that truncates any existing +     *            file.       * @param signal A signal to cancel the operation in progress, or       *            {@code null} if none. For example, if you are downloading a       *            file from the network to service a "rw" mode request, you @@ -2010,9 +2011,11 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall       * containing at least the columns specified by {@link android.provider.OpenableColumns}.</p>       *       * @param uri The URI whose file is to be opened. -     * @param mode The string representation of the file mode. Can be "r", "w", -     *            "wt", "wa", "rw" or "rwt". See -     *            {@link ParcelFileDescriptor#parseMode} for more details. +     * @param mode Access mode for the file.  May be "r" for read-only access, +     * "w" for write-only access (erasing whatever data is currently in +     * the file), "wa" for write-only access to append to any existing data, +     * "rw" for read and write access on any existing data, and "rwt" for read +     * and write access that truncates any existing file.       *       * @return Returns a new AssetFileDescriptor which you can use to access       * the file. @@ -2065,9 +2068,11 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall       * containing at least the columns specified by {@link android.provider.OpenableColumns}.</p>       *       * @param uri The URI whose file is to be opened. -     * @param mode The string representation of the file mode. Can be "r", "w", -     *            "wt", "wa", "rw" or "rwt". See -     *            {@link ParcelFileDescriptor#parseMode} for more details. +     * @param mode Access mode for the file.  May be "r" for read-only access, +     * "w" for write-only access (erasing whatever data is currently in +     * the file), "wa" for write-only access to append to any existing data, +     * "rw" for read and write access on any existing data, and "rwt" for read +     * and write access that truncates any existing file.       * @param signal A signal to cancel the operation in progress, or       *            {@code null} if none. For example, if you are downloading a       *            file from the network to service a "rw" mode request, you @@ -2098,9 +2103,11 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall       * by looking up a column named "_data" at the given URI.       *       * @param uri The URI to be opened. -     * @param mode The string representation of the file mode. Can be "r", "w", -     *            "wt", "wa", "rw" or "rwt". See -     *            {@link ParcelFileDescriptor#parseMode} for more details. +     * @param mode The file mode.  May be "r" for read-only access, +     * "w" for write-only access (erasing whatever data is currently in +     * the file), "wa" for write-only access to append to any existing data, +     * "rw" for read and write access on any existing data, and "rwt" for read +     * and write access that truncates any existing file.       *       * @return Returns a new ParcelFileDescriptor that can be used by the       * client to access the file. diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java index 1132991a57f8..aec39da973f0 100644 --- a/core/java/android/content/ContentResolver.java +++ b/core/java/android/content/ContentResolver.java @@ -63,9 +63,7 @@ import android.os.RemoteException;  import android.os.ServiceManager;  import android.os.SystemClock;  import android.os.UserHandle; -import android.system.ErrnoException;  import android.system.Int64Ref; -import android.system.Os;  import android.text.TextUtils;  import android.util.EventLog;  import android.util.Log; @@ -78,10 +76,8 @@ import com.android.internal.util.MimeIconUtils;  import dalvik.system.CloseGuard;  import java.io.File; -import java.io.FileDescriptor;  import java.io.FileInputStream;  import java.io.FileNotFoundException; -import java.io.FileOutputStream;  import java.io.IOException;  import java.io.InputStream;  import java.io.OutputStream; @@ -868,20 +864,6 @@ public abstract class ContentResolver implements ContentInterface {          return wrap((ContentInterface) wrapped);      } -    /** -     * Offer to locally truncate the given file when opened using the write-only -     * mode. This is typically used to preserve legacy compatibility behavior. -     */ -    private static void maybeTruncate(FileDescriptor fd, String mode) throws FileNotFoundException { -        if ("w".equals(mode)) { -            try { -                Os.ftruncate(fd, 0); -            } catch (ErrnoException e) { -                throw new FileNotFoundException("Failed to truncate: " + e.getMessage()); -            } -        } -    } -      /** @hide */      @SuppressWarnings("HiddenAbstractMethod")      @UnsupportedAppUsage @@ -1543,20 +1525,8 @@ public abstract class ContentResolver implements ContentInterface {      }      /** -     * Open a stream on to the content associated with a content URI.  If there -     * is no data associated with the URI, FileNotFoundException is thrown. -     * -     * <h5>Accepts the following URI schemes:</h5> -     * <ul> -     * <li>content ({@link #SCHEME_CONTENT})</li> -     * <li>file ({@link #SCHEME_FILE})</li> -     * </ul> -     * -     * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information -     * on these schemes. -     * -     * <p>This method behaves like {@link FileOutputStream} and automatically -     * truncates any existing contents. +     * Synonym for {@link #openOutputStream(Uri, String) +     * openOutputStream(uri, "w")}.       *       * @param uri The desired URI.       * @return an OutputStream or {@code null} if the provider recently crashed. @@ -1564,16 +1534,7 @@ public abstract class ContentResolver implements ContentInterface {       */      public final @Nullable OutputStream openOutputStream(@NonNull Uri uri)              throws FileNotFoundException { -        AssetFileDescriptor fd = openAssetFileDescriptor(uri, "w", null); -        if (fd == null) return null; -        try { -            final FileOutputStream res = fd.createOutputStream(); -            // Unconditionally truncate to mirror FileOutputStream behavior -            maybeTruncate(res.getFD(), "w"); -            return res; -        } catch (IOException e) { -            throw new FileNotFoundException("Unable to create stream"); -        } +        return openOutputStream(uri, "w");      }      /** @@ -1590,9 +1551,7 @@ public abstract class ContentResolver implements ContentInterface {       * on these schemes.       *       * @param uri The desired URI. -     * @param mode The string representation of the file mode. Can be "r", "w", -     *            "wt", "wa", "rw" or "rwt". See -     *            {@link ParcelFileDescriptor#parseMode} for more details. +     * @param mode May be "w", "wa", "rw", or "rwt".       * @return an OutputStream or {@code null} if the provider recently crashed.       * @throws FileNotFoundException if the provided URI could not be opened.       * @see #openAssetFileDescriptor(Uri, String) @@ -1600,14 +1559,8 @@ public abstract class ContentResolver implements ContentInterface {      public final @Nullable OutputStream openOutputStream(@NonNull Uri uri, @NonNull String mode)              throws FileNotFoundException {          AssetFileDescriptor fd = openAssetFileDescriptor(uri, mode, null); -        if (fd == null) return null;          try { -            final FileOutputStream res = fd.createOutputStream(); -            // Preserve legacy behavior by offering to truncate -            if (mTargetSdkVersion < Build.VERSION_CODES.Q) { -                maybeTruncate(res.getFD(), mode); -            } -            return res; +            return fd != null ? fd.createOutputStream() : null;          } catch (IOException e) {              throw new FileNotFoundException("Unable to create stream");          } @@ -1654,9 +1607,8 @@ public abstract class ContentResolver implements ContentInterface {       * provider, use {@link ParcelFileDescriptor#closeWithError(String)}.       *       * @param uri The desired URI to open. -     * @param mode The string representation of the file mode. Can be "r", "w", -     *            "wt", "wa", "rw" or "rwt". See -     *            {@link ParcelFileDescriptor#parseMode} for more details. +     * @param mode The file mode to use, as per {@link ContentProvider#openFile +     * ContentProvider.openFile}.       * @return Returns a new ParcelFileDescriptor pointing to the file or {@code null} if the       * provider recently crashed. You own this descriptor and are responsible for closing it       * when done. @@ -1698,9 +1650,8 @@ public abstract class ContentResolver implements ContentInterface {       * provider, use {@link ParcelFileDescriptor#closeWithError(String)}.       *       * @param uri The desired URI to open. -     * @param mode The string representation of the file mode. Can be "r", "w", -     *            "wt", "wa", "rw" or "rwt". See -     *            {@link ParcelFileDescriptor#parseMode} for more details. +     * @param mode The file mode to use, as per {@link ContentProvider#openFile +     * ContentProvider.openFile}.       * @param cancellationSignal A signal to cancel the operation in progress,       *         or null if none. If the operation is canceled, then       *         {@link OperationCanceledException} will be thrown. @@ -1793,9 +1744,8 @@ public abstract class ContentResolver implements ContentInterface {       * from any built-in data conversion that a provider implements.       *       * @param uri The desired URI to open. -     * @param mode The string representation of the file mode. Can be "r", "w", -     *            "wt", "wa", "rw" or "rwt". See -     *            {@link ParcelFileDescriptor#parseMode} for more details. +     * @param mode The file mode to use, as per {@link ContentProvider#openAssetFile +     * ContentProvider.openAssetFile}.       * @return Returns a new ParcelFileDescriptor pointing to the file or {@code null} if the       * provider recently crashed. You own this descriptor and are responsible for closing it       * when done. @@ -1848,9 +1798,8 @@ public abstract class ContentResolver implements ContentInterface {       * from any built-in data conversion that a provider implements.       *       * @param uri The desired URI to open. -     * @param mode The string representation of the file mode. Can be "r", "w", -     *            "wt", "wa", "rw" or "rwt". See -     *            {@link ParcelFileDescriptor#parseMode} for more details. +     * @param mode The file mode to use, as per {@link ContentProvider#openAssetFile +     * ContentProvider.openAssetFile}.       * @param cancellationSignal A signal to cancel the operation in progress, or null if       *            none. If the operation is canceled, then       *            {@link OperationCanceledException} will be thrown. @@ -1886,10 +1835,6 @@ public abstract class ContentResolver implements ContentInterface {          } else if (SCHEME_FILE.equals(scheme)) {              ParcelFileDescriptor pfd = ParcelFileDescriptor.open(                      new File(uri.getPath()), ParcelFileDescriptor.parseMode(mode)); -            // Preserve legacy behavior by offering to truncate -            if (mTargetSdkVersion < Build.VERSION_CODES.Q) { -                maybeTruncate(pfd.getFileDescriptor(), mode); -            }              return new AssetFileDescriptor(pfd, 0, -1);          } else {              if ("r".equals(mode)) { @@ -1947,11 +1892,6 @@ public abstract class ContentResolver implements ContentInterface {                      // ParcelFileDescriptorInner do that when it is closed.                      stableProvider = null; -                    // Preserve legacy behavior by offering to truncate -                    if (mTargetSdkVersion < Build.VERSION_CODES.Q) { -                        maybeTruncate(pfd.getFileDescriptor(), mode); -                    } -                      return new AssetFileDescriptor(pfd, fd.getStartOffset(),                              fd.getDeclaredLength()); diff --git a/core/java/android/content/pm/ApkChecksum.java b/core/java/android/content/pm/ApkChecksum.java index eca48eca9e4b..d550f411f6f7 100644 --- a/core/java/android/content/pm/ApkChecksum.java +++ b/core/java/android/content/pm/ApkChecksum.java @@ -118,7 +118,7 @@ public final class ApkChecksum implements Parcelable { -    // Code below generated by codegen v1.0.15. +    // Code below generated by codegen v1.0.23.      //      // DO NOT MODIFY!      // CHECKSTYLE:OFF Generated code @@ -235,8 +235,8 @@ public final class ApkChecksum implements Parcelable {      };      @DataClass.Generated( -            time = 1601589269293L, -            codegenVersion = "1.0.15", +            time = 1619810171079L, +            codegenVersion = "1.0.23",              sourceFile = "frameworks/base/core/java/android/content/pm/ApkChecksum.java",              inputSignatures = "private final @android.annotation.Nullable java.lang.String mSplitName\nprivate final @android.annotation.NonNull android.content.pm.Checksum mChecksum\nprivate final @android.annotation.Nullable java.lang.String mInstallerPackageName\nprivate final @android.annotation.Nullable byte[] mInstallerCertificate\npublic @android.content.pm.Checksum.Type int getType()\npublic @android.annotation.NonNull byte[] getValue()\npublic @android.annotation.Nullable byte[] getInstallerCertificateBytes()\npublic @android.annotation.Nullable java.security.cert.Certificate getInstallerCertificate()\nclass ApkChecksum extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true)")      @Deprecated diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index e302f9e404fb..a3e0473e39cc 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -2141,22 +2141,57 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {      }      /** +     * Use default value for +     * {@link android.R.styleable#AndroidManifestApplication_requestRawExternalStorageAccess}. +     */ +    public static final int RAW_EXTERNAL_STORAGE_ACCESS_DEFAULT = 0; + +    /** +     * Raw external storage was requested by this app. +     */ +    public static final int RAW_EXTERNAL_STORAGE_ACCESS_REQUESTED = 1; + +    /** +     * Raw external storage was not requested by this app. +     */ +    public static final int RAW_EXTERNAL_STORAGE_ACCESS_NOT_REQUESTED = 2; + +    /** +     * These constants need to match the value of +     * {@link android.R.styleable#AndroidManifestApplication_requestRawExternalStorageAccess}. +     * in application manifest. +     * @hide +     */ +    @IntDef(prefix = {"RAW_EXTERNAL_STORAGE_"}, value = { +            RAW_EXTERNAL_STORAGE_ACCESS_DEFAULT, +            RAW_EXTERNAL_STORAGE_ACCESS_REQUESTED, +            RAW_EXTERNAL_STORAGE_ACCESS_NOT_REQUESTED, +    }) +    @Retention(RetentionPolicy.SOURCE) +    public @interface RawExternalStorage {} + +    /**       * @return       * <ul> -     * <li>{@code true} if this app requested raw external storage access -     * <li>{@code false} if this app requests to disable raw external storage access. -     * <li>{@code null} if the app didn't specify +     * <li>{@link ApplicationInfo#RAW_EXTERNAL_STORAGE_ACCESS_DEFAULT} if app didn't specify       * {@link android.R.styleable#AndroidManifestApplication_requestRawExternalStorageAccess} -     * in its manifest file. -     * </ul> -     * -     * @hide +     * attribute in the manifest. +     * <li>{@link ApplicationInfo#RAW_EXTERNAL_STORAGE_ACCESS_REQUESTED} if this app requested raw +     * external storage access. +     * <li>{@link ApplicationInfo#RAW_EXTERNAL_STORAGE_ACCESS_NOT_REQUESTED} if this app requests to +     * disable raw external storage access +     * </ul +     * <p> +     * Note that this doesn't give any hints on whether the app gets raw external storage access or +     * not. Also, apps may get raw external storage access by default in some cases, see +     * {@link android.R.styleable#AndroidManifestApplication_requestRawExternalStorageAccess}.       */ -    @SuppressWarnings("AutoBoxing") -    @SystemApi -    @Nullable -    public Boolean hasRequestRawExternalStorageAccess() { -        return requestRawExternalStorageAccess; +    public @RawExternalStorage int getRequestRawExternalStorageAccess() { +        if (requestRawExternalStorageAccess == null) { +            return RAW_EXTERNAL_STORAGE_ACCESS_DEFAULT; +        } +        return requestRawExternalStorageAccess ? RAW_EXTERNAL_STORAGE_ACCESS_REQUESTED +                : RAW_EXTERNAL_STORAGE_ACCESS_NOT_REQUESTED;      }      /** diff --git a/core/java/android/content/pm/Checksum.java b/core/java/android/content/pm/Checksum.java index 4f4898af278b..ff17496c7457 100644 --- a/core/java/android/content/pm/Checksum.java +++ b/core/java/android/content/pm/Checksum.java @@ -113,7 +113,7 @@ public final class Checksum implements Parcelable {      public static final int TYPE_PARTIAL_MERKLE_ROOT_1M_SHA512 = 0x00000040;      /** @hide */ -    @IntDef(flag = true, prefix = {"TYPE_"}, value = { +    @IntDef(prefix = {"TYPE_"}, value = {              TYPE_WHOLE_MERKLE_ROOT_4K_SHA256,              TYPE_WHOLE_MD5,              TYPE_WHOLE_SHA1, @@ -125,6 +125,19 @@ public final class Checksum implements Parcelable {      @Retention(RetentionPolicy.SOURCE)      public @interface Type {} +    /** @hide */ +    @IntDef(flag = true, prefix = {"TYPE_"}, value = { +            TYPE_WHOLE_MERKLE_ROOT_4K_SHA256, +            TYPE_WHOLE_MD5, +            TYPE_WHOLE_SHA1, +            TYPE_WHOLE_SHA256, +            TYPE_WHOLE_SHA512, +            TYPE_PARTIAL_MERKLE_ROOT_1M_SHA256, +            TYPE_PARTIAL_MERKLE_ROOT_1M_SHA512, +    }) +    @Retention(RetentionPolicy.SOURCE) +    public @interface TypeMask {} +      /**       * Serialize checksum to the stream in binary format.       * @hide @@ -163,7 +176,7 @@ public final class Checksum implements Parcelable { -    // Code below generated by codegen v1.0.22. +    // Code below generated by codegen v1.0.23.      //      // DO NOT MODIFY!      // CHECKSTYLE:OFF Generated code @@ -263,8 +276,8 @@ public final class Checksum implements Parcelable {      };      @DataClass.Generated( -            time = 1611601571576L, -            codegenVersion = "1.0.22", +            time = 1619810358402L, +            codegenVersion = "1.0.23",              sourceFile = "frameworks/base/core/java/android/content/pm/Checksum.java",              inputSignatures = "public static final  int TYPE_WHOLE_MERKLE_ROOT_4K_SHA256\npublic static final @java.lang.Deprecated int TYPE_WHOLE_MD5\npublic static final @java.lang.Deprecated int TYPE_WHOLE_SHA1\npublic static final @java.lang.Deprecated int TYPE_WHOLE_SHA256\npublic static final @java.lang.Deprecated int TYPE_WHOLE_SHA512\npublic static final  int TYPE_PARTIAL_MERKLE_ROOT_1M_SHA256\npublic static final  int TYPE_PARTIAL_MERKLE_ROOT_1M_SHA512\nprivate final @android.content.pm.Checksum.Type int mType\nprivate final @android.annotation.NonNull byte[] mValue\npublic static  void writeToStream(java.io.DataOutputStream,android.content.pm.Checksum)\npublic static @android.annotation.NonNull android.content.pm.Checksum readFromStream(java.io.DataInputStream)\nclass Checksum extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstDefs=false)")      @Deprecated diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 99bbcdea06fc..a1d419e82174 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -4605,7 +4605,7 @@ public abstract class PackageManager {       * Query for all of the permissions associated with a particular group.       *       * @param permissionGroup The fully qualified name (i.e. com.google.permission.LOGIN) -     *            of the permission group you are interested in. Use null to +     *            of the permission group you are interested in. Use {@code null} to       *            find all of the permissions not associated with a group.       * @param flags Additional option flags to modify the data returned.       * @return Returns a list of {@link PermissionInfo} containing information @@ -4615,7 +4615,7 @@ public abstract class PackageManager {       */      //@Deprecated      @NonNull -    public abstract List<PermissionInfo> queryPermissionsByGroup(@NonNull String permissionGroup, +    public abstract List<PermissionInfo> queryPermissionsByGroup(@Nullable String permissionGroup,              @PermissionInfoFlags int flags) throws NameNotFoundException;      /** @@ -8711,7 +8711,7 @@ public abstract class PackageManager {       * @throws NameNotFoundException if a package with the given name cannot be found on the system.       */      public void requestChecksums(@NonNull String packageName, boolean includeSplits, -            @Checksum.Type int required, @NonNull List<Certificate> trustedInstallers, +            @Checksum.TypeMask int required, @NonNull List<Certificate> trustedInstallers,              @NonNull OnChecksumsReadyListener onChecksumsReadyListener)              throws CertificateEncodingException, NameNotFoundException {          throw new UnsupportedOperationException("requestChecksums not implemented in subclass"); diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java index 22d75ef93137..725576fda389 100644 --- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java +++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java @@ -3069,6 +3069,13 @@ public class ParsingPackageUtils {      /**       * @hide       */ +    public static void setCompatibilityModeEnabled(boolean compatibilityModeEnabled) { +        sCompatibilityModeEnabled = compatibilityModeEnabled; +    } + +    /** +     * @hide +     */      public static void readConfigUseRoundIcon(Resources r) {          if (r != null) {              sUseRoundIcon = r.getBoolean(com.android.internal.R.bool.config_useRoundIcon); diff --git a/core/java/android/hardware/devicestate/DeviceStateManager.java b/core/java/android/hardware/devicestate/DeviceStateManager.java index 250145e92b89..52dad3efefb8 100644 --- a/core/java/android/hardware/devicestate/DeviceStateManager.java +++ b/core/java/android/hardware/devicestate/DeviceStateManager.java @@ -24,7 +24,10 @@ import android.annotation.SystemService;  import android.annotation.TestApi;  import android.content.Context; +import com.android.internal.util.ArrayUtils; +  import java.util.concurrent.Executor; +import java.util.function.Consumer;  /**   * Manages the state of the system for devices with user-configurable hardware like a foldable @@ -170,4 +173,34 @@ public final class DeviceStateManager {           */          void onStateChanged(int state);      } + +    /** +     * Listens to changes in device state and reports the state as folded if the device state +     * matches the value in the {@link com.android.internal.R.integer.config_foldedDeviceState} +     * resource. +     * @hide +     */ +    public static class FoldStateListener implements DeviceStateCallback { +        private final int[] mFoldedDeviceStates; +        private final Consumer<Boolean> mDelegate; + +        @Nullable +        private Boolean lastResult; + +        public FoldStateListener(Context context, Consumer<Boolean> listener) { +            mFoldedDeviceStates = context.getResources().getIntArray( +                    com.android.internal.R.array.config_foldedDeviceStates); +            mDelegate = listener; +        } + +        @Override +        public final void onStateChanged(int state) { +            final boolean folded = ArrayUtils.contains(mFoldedDeviceStates, state); + +            if (lastResult == null || !lastResult.equals(folded)) { +                lastResult = folded; +                mDelegate.accept(folded); +            } +        } +    }  } diff --git a/core/java/android/os/AggregateBatteryConsumer.java b/core/java/android/os/AggregateBatteryConsumer.java new file mode 100644 index 000000000000..449e3aeb6be6 --- /dev/null +++ b/core/java/android/os/AggregateBatteryConsumer.java @@ -0,0 +1,94 @@ +/* + * 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 android.os; + +import android.annotation.NonNull; + +/** + * Contains power consumption data across the entire device. + * + * {@hide} + */ +public final class AggregateBatteryConsumer extends BatteryConsumer implements Parcelable { + +    private final double mConsumedPowerMah; + +    public AggregateBatteryConsumer(@NonNull Builder builder) { +        super(builder.mPowerComponentsBuilder.build()); +        mConsumedPowerMah = builder.mConsumedPowerMah; +    } + +    private AggregateBatteryConsumer(@NonNull Parcel source) { +        super(new PowerComponents(source)); +        mConsumedPowerMah = source.readDouble(); +    } + +    @Override +    public void writeToParcel(@NonNull Parcel dest, int flags) { +        super.writeToParcel(dest, flags); +        dest.writeDouble(mConsumedPowerMah); +    } + +    @Override +    public int describeContents() { +        return 0; +    } + +    @NonNull +    public static final Creator<AggregateBatteryConsumer> CREATOR = +            new Creator<AggregateBatteryConsumer>() { +                public AggregateBatteryConsumer createFromParcel(@NonNull Parcel source) { +                    return new AggregateBatteryConsumer(source); +                } + +                public AggregateBatteryConsumer[] newArray(int size) { +                    return new AggregateBatteryConsumer[size]; +                } +            }; + +    @Override +    public double getConsumedPower() { +        return mConsumedPowerMah; +    } + +    /** +     * Builder for DeviceBatteryConsumer. +     */ +    public static final class Builder extends BaseBuilder<AggregateBatteryConsumer.Builder> { +        private double mConsumedPowerMah; + +        public Builder(@NonNull String[] customPowerComponentNames, boolean includePowerModels) { +            super(customPowerComponentNames, includePowerModels); +        } + +        /** +         * Sets the total power included in this aggregate. +         */ +        public Builder setConsumedPower(double consumedPowerMah) { +            mConsumedPowerMah = consumedPowerMah; +            return this; +        } + +        /** +         * Creates a read-only object out of the Builder values. +         */ +        @NonNull +        public AggregateBatteryConsumer build() { +            return new AggregateBatteryConsumer(this); +        } +    } +} diff --git a/core/java/android/os/BatteryConsumer.java b/core/java/android/os/BatteryConsumer.java index 32ca92cc97b0..6b628b0140e6 100644 --- a/core/java/android/os/BatteryConsumer.java +++ b/core/java/android/os/BatteryConsumer.java @@ -27,7 +27,7 @@ import java.lang.annotation.RetentionPolicy;   *   * @hide   */ -public abstract class BatteryConsumer { +public class BatteryConsumer {      /**       * Power usage component, describing the particular part of the system @@ -72,14 +72,15 @@ public abstract class BatteryConsumer {      public static final int POWER_COMPONENT_WIFI = 11;      public static final int POWER_COMPONENT_WAKELOCK = 12;      public static final int POWER_COMPONENT_MEMORY = 13; -    public static final int POWER_COMPONENT_PHONE = 13; -    public static final int POWER_COMPONENT_IDLE = 15; +    public static final int POWER_COMPONENT_PHONE = 14; +    public static final int POWER_COMPONENT_AMBIENT_DISPLAY = 15; +    public static final int POWER_COMPONENT_IDLE = 16;      // Power that is re-attributed to other battery consumers. For example, for System Server      // this represents the power attributed to apps requesting system services.      // The value should be negative or zero. -    public static final int POWER_COMPONENT_REATTRIBUTED_TO_OTHER_CONSUMERS = 16; +    public static final int POWER_COMPONENT_REATTRIBUTED_TO_OTHER_CONSUMERS = 17; -    public static final int POWER_COMPONENT_COUNT = 17; +    public static final int POWER_COMPONENT_COUNT = 18;      public static final int FIRST_CUSTOM_POWER_COMPONENT_ID = 1000;      public static final int LAST_CUSTOM_POWER_COMPONENT_ID = 9999; diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index 9ec6938de271..eec6810fa8bc 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -3234,6 +3234,11 @@ public abstract class BatteryStats implements Parcelable {      public abstract int getMaxLearnedBatteryCapacity() ;      /** +     * @return The latest learned battery capacity in uAh. +     */ +    public abstract int getLearnedBatteryCapacity(); + +    /**       * Return the array of discharge step durations.       */      public abstract LevelStepTracker getDischargeLevelStepTracker(); @@ -3925,7 +3930,9 @@ public abstract class BatteryStats implements Parcelable {                  getStartClockTime(),                  whichBatteryScreenOffRealtime / 1000, whichBatteryScreenOffUptime / 1000,                  getEstimatedBatteryCapacity(), -                getMinLearnedBatteryCapacity(), getMaxLearnedBatteryCapacity(), +                getLearnedBatteryCapacity(), +                getMinLearnedBatteryCapacity(), +                getMaxLearnedBatteryCapacity(),                  screenDozeTime / 1000); @@ -4688,22 +4695,31 @@ public abstract class BatteryStats implements Parcelable {              pw.println(sb.toString());          } +        final int lastLearnedBatteryCapacity = getLearnedBatteryCapacity(); +        if (lastLearnedBatteryCapacity > 0) { +            sb.setLength(0); +            sb.append(prefix); +            sb.append("  Last learned battery capacity: "); +            sb.append(BatteryStatsHelper.makemAh(lastLearnedBatteryCapacity / 1000)); +            sb.append(" mAh"); +            pw.println(sb.toString()); +        }          final int minLearnedBatteryCapacity = getMinLearnedBatteryCapacity();          if (minLearnedBatteryCapacity > 0) {              sb.setLength(0);              sb.append(prefix); -                sb.append("  Min learned battery capacity: "); -                sb.append(BatteryStatsHelper.makemAh(minLearnedBatteryCapacity / 1000)); -                sb.append(" mAh"); +            sb.append("  Min learned battery capacity: "); +            sb.append(BatteryStatsHelper.makemAh(minLearnedBatteryCapacity / 1000)); +            sb.append(" mAh");              pw.println(sb.toString());          }          final int maxLearnedBatteryCapacity = getMaxLearnedBatteryCapacity();          if (maxLearnedBatteryCapacity > 0) {              sb.setLength(0);              sb.append(prefix); -                sb.append("  Max learned battery capacity: "); -                sb.append(BatteryStatsHelper.makemAh(maxLearnedBatteryCapacity / 1000)); -                sb.append(" mAh"); +            sb.append("  Max learned battery capacity: "); +            sb.append(BatteryStatsHelper.makemAh(maxLearnedBatteryCapacity / 1000)); +            sb.append(" mAh");              pw.println(sb.toString());          } diff --git a/core/java/android/os/BatteryUsageStats.java b/core/java/android/os/BatteryUsageStats.java index efdef62d98ff..6bc861f87e48 100644 --- a/core/java/android/os/BatteryUsageStats.java +++ b/core/java/android/os/BatteryUsageStats.java @@ -16,6 +16,7 @@  package android.os; +import android.annotation.IntDef;  import android.annotation.NonNull;  import android.util.Range;  import android.util.SparseArray; @@ -23,16 +24,53 @@ import android.util.SparseArray;  import com.android.internal.os.BatteryStatsHistory;  import com.android.internal.os.BatteryStatsHistoryIterator; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy;  import java.util.ArrayList;  import java.util.List;  /**   * Contains a snapshot of battery attribution data, on a per-subsystem and per-UID basis. + * <p> + * The totals for the entire device are returned as AggregateBatteryConsumers, which can be + * obtained by calling {@link #getAggregateBatteryConsumer(int)}. + * <p> + * Power attributed to individual apps is returned as UidBatteryConsumers, see + * {@link #getUidBatteryConsumers()}.   *   * @hide   */  public final class BatteryUsageStats implements Parcelable { -    private final double mConsumedPower; + +    /** +     * Scope of battery stats included in a BatteryConsumer: the entire device, just +     * the apps, etc. +     * +     * @hide +     */ +    @IntDef(prefix = {"AGGREGATE_BATTERY_CONSUMER_SCOPE_"}, value = { +            AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE, +            AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS, +    }) +    @Retention(RetentionPolicy.SOURCE) +    public static @interface AggregateBatteryConsumerScope { +    } + +    /** +     * Power consumption by the entire device, since last charge.  The power usage in this +     * scope includes both the power attributed to apps and the power unattributed to any +     * apps. +     */ +    public static final int AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE = 0; + +    /** +     * Aggregated power consumed by all applications, combined, since last charge. This is +     * the sum of power reported in UidBatteryConsumers. +     */ +    public static final int AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS = 1; + +    public static final int AGGREGATE_BATTERY_CONSUMER_SCOPE_COUNT = 2; +      private final int mDischargePercentage;      private final long mStatsStartTimestampMs;      private final double mDischargedPowerLowerBound; @@ -41,8 +79,8 @@ public final class BatteryUsageStats implements Parcelable {      private final long mChargeTimeRemainingMs;      private final String[] mCustomPowerComponentNames;      private final List<UidBatteryConsumer> mUidBatteryConsumers; -    private final List<SystemBatteryConsumer> mSystemBatteryConsumers;      private final List<UserBatteryConsumer> mUserBatteryConsumers; +    private final AggregateBatteryConsumer[] mAggregateBatteryConsumers;      private final Parcel mHistoryBuffer;      private final List<BatteryStats.HistoryTag> mHistoryTagPool; @@ -57,8 +95,7 @@ public final class BatteryUsageStats implements Parcelable {          mChargeTimeRemainingMs = builder.mChargeTimeRemainingMs;          mCustomPowerComponentNames = builder.mCustomPowerComponentNames; -        double totalPower = 0; - +        double totalPowerMah = 0;          final int uidBatteryConsumerCount = builder.mUidBatteryConsumerBuilders.size();          mUidBatteryConsumers = new ArrayList<>(uidBatteryConsumerCount);          for (int i = 0; i < uidBatteryConsumerCount; i++) { @@ -66,30 +103,28 @@ public final class BatteryUsageStats implements Parcelable {                      builder.mUidBatteryConsumerBuilders.valueAt(i);              if (!uidBatteryConsumerBuilder.isExcludedFromBatteryUsageStats()) {                  final UidBatteryConsumer consumer = uidBatteryConsumerBuilder.build(); -                totalPower += consumer.getConsumedPower(); +                totalPowerMah += consumer.getConsumedPower();                  mUidBatteryConsumers.add(consumer);              }          } -        final int systemBatteryConsumerCount = builder.mSystemBatteryConsumerBuilders.size(); -        mSystemBatteryConsumers = new ArrayList<>(systemBatteryConsumerCount); -        for (int i = 0; i < systemBatteryConsumerCount; i++) { -            final SystemBatteryConsumer consumer = -                    builder.mSystemBatteryConsumerBuilders.valueAt(i).build(); -            totalPower += consumer.getConsumedPower() - consumer.getPowerConsumedByApps(); -            mSystemBatteryConsumers.add(consumer); -        } -          final int userBatteryConsumerCount = builder.mUserBatteryConsumerBuilders.size();          mUserBatteryConsumers = new ArrayList<>(userBatteryConsumerCount);          for (int i = 0; i < userBatteryConsumerCount; i++) {              final UserBatteryConsumer consumer =                      builder.mUserBatteryConsumerBuilders.valueAt(i).build(); -            totalPower += consumer.getConsumedPower(); +            totalPowerMah += consumer.getConsumedPower();              mUserBatteryConsumers.add(consumer);          } -        mConsumedPower = totalPower; +        builder.getAggregateBatteryConsumerBuilder(AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS) +                .setConsumedPower(totalPowerMah); + +        mAggregateBatteryConsumers = +                new AggregateBatteryConsumer[AGGREGATE_BATTERY_CONSUMER_SCOPE_COUNT]; +        for (int i = 0; i < AGGREGATE_BATTERY_CONSUMER_SCOPE_COUNT; i++) { +            mAggregateBatteryConsumers[i] = builder.mAggregateBatteryConsumersBuilders[i].build(); +        }      }      /** @@ -101,6 +136,15 @@ public final class BatteryUsageStats implements Parcelable {      }      /** +     * Total amount of battery charge drained since BatteryStats reset (e.g. due to being fully +     * charged), in mAh +     */ +    public double getConsumedPower() { +        return mAggregateBatteryConsumers[AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE] +                .getConsumedPower(); +    } + +    /**       * Portion of battery charge drained since BatteryStats reset (e.g. due to being fully       * charged), as percentage of the full charge in the range [0:100]       */ @@ -136,11 +180,11 @@ public final class BatteryUsageStats implements Parcelable {      }      /** -     * Total amount of battery charge drained since BatteryStats reset (e.g. due to being fully -     * charged), in mAh +     * Returns a battery consumer for the specified battery consumer type.       */ -    public double getConsumedPower() { -        return mConsumedPower; +    public BatteryConsumer getAggregateBatteryConsumer( +            @AggregateBatteryConsumerScope int scope) { +        return mAggregateBatteryConsumers[scope];      }      @NonNull @@ -149,11 +193,6 @@ public final class BatteryUsageStats implements Parcelable {      }      @NonNull -    public List<SystemBatteryConsumer> getSystemBatteryConsumers() { -        return mSystemBatteryConsumers; -    } - -    @NonNull      public List<UserBatteryConsumer> getUserBatteryConsumers() {          return mUserBatteryConsumers;      } @@ -178,13 +217,19 @@ public final class BatteryUsageStats implements Parcelable {      private BatteryUsageStats(@NonNull Parcel source) {          mStatsStartTimestampMs = source.readLong(); -        mConsumedPower = source.readDouble();          mDischargePercentage = source.readInt();          mDischargedPowerLowerBound = source.readDouble();          mDischargedPowerUpperBound = source.readDouble();          mBatteryTimeRemainingMs = source.readLong();          mChargeTimeRemainingMs = source.readLong();          mCustomPowerComponentNames = source.readStringArray(); +        mAggregateBatteryConsumers = +                new AggregateBatteryConsumer[AGGREGATE_BATTERY_CONSUMER_SCOPE_COUNT]; +        for (int i = 0; i < AGGREGATE_BATTERY_CONSUMER_SCOPE_COUNT; i++) { +            mAggregateBatteryConsumers[i] = +                    AggregateBatteryConsumer.CREATOR.createFromParcel(source); +            mAggregateBatteryConsumers[i].setCustomPowerComponentNames(mCustomPowerComponentNames); +        }          int uidCount = source.readInt();          mUidBatteryConsumers = new ArrayList<>(uidCount);          for (int i = 0; i < uidCount; i++) { @@ -193,14 +238,6 @@ public final class BatteryUsageStats implements Parcelable {              consumer.setCustomPowerComponentNames(mCustomPowerComponentNames);              mUidBatteryConsumers.add(consumer);          } -        int sysCount = source.readInt(); -        mSystemBatteryConsumers = new ArrayList<>(sysCount); -        for (int i = 0; i < sysCount; i++) { -            final SystemBatteryConsumer consumer = -                    SystemBatteryConsumer.CREATOR.createFromParcel(source); -            consumer.setCustomPowerComponentNames(mCustomPowerComponentNames); -            mSystemBatteryConsumers.add(consumer); -        }          int userCount = source.readInt();          mUserBatteryConsumers = new ArrayList<>(userCount);          for (int i = 0; i < userCount; i++) { @@ -237,21 +274,19 @@ public final class BatteryUsageStats implements Parcelable {      @Override      public void writeToParcel(@NonNull Parcel dest, int flags) {          dest.writeLong(mStatsStartTimestampMs); -        dest.writeDouble(mConsumedPower);          dest.writeInt(mDischargePercentage);          dest.writeDouble(mDischargedPowerLowerBound);          dest.writeDouble(mDischargedPowerUpperBound);          dest.writeLong(mBatteryTimeRemainingMs);          dest.writeLong(mChargeTimeRemainingMs);          dest.writeStringArray(mCustomPowerComponentNames); +        for (int i = 0; i < AGGREGATE_BATTERY_CONSUMER_SCOPE_COUNT; i++) { +            mAggregateBatteryConsumers[i].writeToParcel(dest, flags); +        }          dest.writeInt(mUidBatteryConsumers.size());          for (int i = mUidBatteryConsumers.size() - 1; i >= 0; i--) {              mUidBatteryConsumers.get(i).writeToParcel(dest, flags);          } -        dest.writeInt(mSystemBatteryConsumers.size()); -        for (int i = mSystemBatteryConsumers.size() - 1; i >= 0; i--) { -            mSystemBatteryConsumers.get(i).writeToParcel(dest, flags); -        }          dest.writeInt(mUserBatteryConsumers.size());          for (int i = mUserBatteryConsumers.size() - 1; i >= 0; i--) {              mUserBatteryConsumers.get(i).writeToParcel(dest, flags); @@ -299,10 +334,10 @@ public final class BatteryUsageStats implements Parcelable {          private double mDischargedPowerUpperBoundMah;          private long mBatteryTimeRemainingMs = -1;          private long mChargeTimeRemainingMs = -1; +        private final AggregateBatteryConsumer.Builder[] mAggregateBatteryConsumersBuilders = +                new AggregateBatteryConsumer.Builder[AGGREGATE_BATTERY_CONSUMER_SCOPE_COUNT];          private final SparseArray<UidBatteryConsumer.Builder> mUidBatteryConsumerBuilders =                  new SparseArray<>(); -        private final SparseArray<SystemBatteryConsumer.Builder> mSystemBatteryConsumerBuilders = -                new SparseArray<>();          private final SparseArray<UserBatteryConsumer.Builder> mUserBatteryConsumerBuilders =                  new SparseArray<>();          private Parcel mHistoryBuffer; @@ -315,6 +350,10 @@ public final class BatteryUsageStats implements Parcelable {          public Builder(@NonNull String[] customPowerComponentNames,  boolean includePowerModels) {              mCustomPowerComponentNames = customPowerComponentNames;              mIncludePowerModels = includePowerModels; +            for (int i = 0; i < AGGREGATE_BATTERY_CONSUMER_SCOPE_COUNT; i++) { +                mAggregateBatteryConsumersBuilders[i] = new AggregateBatteryConsumer.Builder( +                        customPowerComponentNames, includePowerModels); +            }          }          /** @@ -386,7 +425,17 @@ public final class BatteryUsageStats implements Parcelable {          }          /** -         * Creates or returns a exiting UidBatteryConsumer, which represents battery attribution +         * Creates or returns an AggregateBatteryConsumer builder, which represents aggregate +         * battery consumption data for the specified scope. +         */ +        @NonNull +        public AggregateBatteryConsumer.Builder getAggregateBatteryConsumerBuilder( +                @AggregateBatteryConsumerScope int scope) { +            return mAggregateBatteryConsumersBuilders[scope]; +        } + +        /** +         * Creates or returns a UidBatteryConsumer, which represents battery attribution           * data for an individual UID.           */          @NonNull @@ -403,23 +452,7 @@ public final class BatteryUsageStats implements Parcelable {          }          /** -         * Creates or returns a exiting SystemBatteryConsumer, which represents battery attribution -         * data for a specific drain type. -         */ -        @NonNull -        public SystemBatteryConsumer.Builder getOrCreateSystemBatteryConsumerBuilder( -                @SystemBatteryConsumer.DrainType int drainType) { -            SystemBatteryConsumer.Builder builder = mSystemBatteryConsumerBuilders.get(drainType); -            if (builder == null) { -                builder = new SystemBatteryConsumer.Builder(mCustomPowerComponentNames, -                        mIncludePowerModels, drainType); -                mSystemBatteryConsumerBuilders.put(drainType, builder); -            } -            return builder; -        } - -        /** -         * Creates or returns a exiting UserBatteryConsumer, which represents battery attribution +         * Creates or returns a UserBatteryConsumer, which represents battery attribution           * data for an individual {@link UserHandle}.           */          @NonNull diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java index a06a8577a56a..f3e0ce9cd19e 100644 --- a/core/java/android/os/FileUtils.java +++ b/core/java/android/os/FileUtils.java @@ -1470,7 +1470,7 @@ public final class FileUtils {              return MediaStore.getOriginalMediaFormatFileDescriptor(context,                      ParcelFileDescriptor.dup(fd));          } catch (Exception e) { -            Log.w(TAG, "Failed to convert to modern format file descriptor", e); +            Log.d(TAG, "Failed to convert to modern format file descriptor", e);              return null;          }      } diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java index 0c9ad1b17a7e..c0847872a45a 100644 --- a/core/java/android/os/ParcelFileDescriptor.java +++ b/core/java/android/os/ParcelFileDescriptor.java @@ -31,7 +31,6 @@ import static android.system.OsConstants.S_ISLNK;  import static android.system.OsConstants.S_ISREG;  import static android.system.OsConstants.S_IWOTH; -import android.annotation.IntDef;  import android.annotation.NonNull;  import android.annotation.SuppressLint;  import android.annotation.SystemApi; @@ -64,8 +63,6 @@ import java.io.FileOutputStream;  import java.io.IOException;  import java.io.InterruptedIOException;  import java.io.UncheckedIOException; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy;  import java.net.DatagramSocket;  import java.net.Socket;  import java.nio.ByteOrder; @@ -113,20 +110,6 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {      private final CloseGuard mGuard = CloseGuard.get(); -    /** @hide */ -    @IntDef(prefix = {"MODE_"}, value = { -            MODE_WORLD_READABLE, -            MODE_WORLD_WRITEABLE, -            MODE_READ_ONLY, -            MODE_WRITE_ONLY, -            MODE_READ_WRITE, -            MODE_CREATE, -            MODE_TRUNCATE, -            MODE_APPEND, -    }) -    @Retention(RetentionPolicy.SOURCE) -    public @interface Mode { } -      /**       * For use with {@link #open}: if {@link #MODE_CREATE} has been supplied and       * this file doesn't already exist, then create the file with permissions @@ -244,8 +227,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {       *             be opened with the requested mode.       * @see #parseMode(String)       */ -    public static ParcelFileDescriptor open(File file, @Mode int mode) -            throws FileNotFoundException { +    public static ParcelFileDescriptor open(File file, int mode) throws FileNotFoundException {          final FileDescriptor fd = openInternal(file, mode);          if (fd == null) return null; @@ -277,7 +259,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {      // We can't accept a generic Executor here, since we need to use      // MessageQueue.addOnFileDescriptorEventListener()      @SuppressLint("ExecutorRegistration") -    public static ParcelFileDescriptor open(File file, @Mode int mode, Handler handler, +    public static ParcelFileDescriptor open(File file, int mode, Handler handler,              final OnCloseListener listener) throws IOException {          if (handler == null) {              throw new IllegalArgumentException("Handler must not be null"); @@ -348,8 +330,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {          return pfd;      } -    private static FileDescriptor openInternal(File file, @Mode int mode) -            throws FileNotFoundException { +    private static FileDescriptor openInternal(File file, int mode) throws FileNotFoundException {          final int flags = FileUtils.translateModePfdToPosix(mode) | ifAtLeastQ(O_CLOEXEC);          int realMode = S_IRWXU | S_IRWXG; @@ -642,36 +623,15 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {      }      /** -     * Converts a string representing a file mode, such as "rw", into a bitmask -     * suitable for use with {@link #open}. +     * Converts a string representing a file mode, such as "rw", into a bitmask suitable for use +     * with {@link #open}.       * <p> -     * The argument must define at least one of the following base access modes: -     * <ul> -     * <li>"r" indicates the file should be opened in read-only mode, equivalent -     * to {@link OsConstants#O_RDONLY}. -     * <li>"w" indicates the file should be opened in write-only mode, -     * equivalent to {@link OsConstants#O_WRONLY}. -     * <li>"rw" indicates the file should be opened in read-write mode, -     * equivalent to {@link OsConstants#O_RDWR}. -     * </ul> -     * In addition to a base access mode, the following additional modes may -     * requested: -     * <ul> -     * <li>"a" indicates the file should be opened in append mode, equivalent to -     * {@link OsConstants#O_APPEND}. Before each write, the file offset is -     * positioned at the end of the file. -     * <li>"t" indicates the file should be opened in truncate mode, equivalent -     * to {@link OsConstants#O_TRUNC}. If the file already exists and is a -     * regular file and is opened for writing, it will be truncated to length 0. -     * </ul> -     * -     * @param mode The string representation of the file mode. Can be "r", "w", -     *            "wt", "wa", "rw" or "rwt". +     * @param mode The string representation of the file mode. Can be "r", "w", "wt", "wa", "rw" +     *             or "rwt".       * @return A bitmask representing the given file mode. -     * @throws IllegalArgumentException if the given string does not match a -     *             known file mode. +     * @throws IllegalArgumentException if the given string does not match a known file mode.       */ -    public static @Mode int parseMode(String mode) { +    public static int parseMode(String mode) {          return FileUtils.translateModePosixToPfd(FileUtils.translateModeStringToPosix(mode));      } diff --git a/core/java/android/os/SystemBatteryConsumer.java b/core/java/android/os/SystemBatteryConsumer.java deleted file mode 100644 index 7618339260bd..000000000000 --- a/core/java/android/os/SystemBatteryConsumer.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - *      http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.util.Slog; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.ArrayList; -import java.util.List; - - -/** - * Contains power consumption data attributed to a system-wide drain type. - * - * {@hide} - */ -public class SystemBatteryConsumer extends BatteryConsumer implements Parcelable { -    private static final String TAG = "SystemBatteryConsumer"; - -    //                           **************** -    // This list must be kept current with atoms.proto (frameworks/base/cmds/statsd/src/atoms.proto) -    // so the constant values must never change. -    //                           **************** -    @IntDef(prefix = {"DRAIN_TYPE_"}, value = { -            DRAIN_TYPE_AMBIENT_DISPLAY, -            // Reserved: APP -            DRAIN_TYPE_BLUETOOTH, -            DRAIN_TYPE_CAMERA, -            DRAIN_TYPE_MOBILE_RADIO, -            DRAIN_TYPE_FLASHLIGHT, -            DRAIN_TYPE_IDLE, -            DRAIN_TYPE_MEMORY, -            // Reserved: OVERCOUNTED, -            DRAIN_TYPE_PHONE, -            DRAIN_TYPE_SCREEN, -            // Reserved: UNACCOUNTED, -            // Reserved: USER, -            DRAIN_TYPE_WIFI, -            DRAIN_TYPE_CUSTOM, -    }) -    @Retention(RetentionPolicy.SOURCE) -    public static @interface DrainType { -    } - -    public static final int DRAIN_TYPE_AMBIENT_DISPLAY = 0; -    public static final int DRAIN_TYPE_BLUETOOTH = 2; -    public static final int DRAIN_TYPE_CAMERA = 3; -    public static final int DRAIN_TYPE_MOBILE_RADIO = 4; -    public static final int DRAIN_TYPE_FLASHLIGHT = 5; -    public static final int DRAIN_TYPE_IDLE = 6; -    public static final int DRAIN_TYPE_MEMORY = 7; -    public static final int DRAIN_TYPE_PHONE = 9; -    public static final int DRAIN_TYPE_SCREEN = 10; -    public static final int DRAIN_TYPE_WIFI = 13; -    public static final int DRAIN_TYPE_CUSTOM = 14; - -    @DrainType -    private final int mDrainType; - -    private final double mPowerConsumedByAppsMah; - -    @DrainType -    public int getDrainType() { -        return mDrainType; -    } - -    private SystemBatteryConsumer(@NonNull SystemBatteryConsumer.Builder builder) { -        super(builder.mPowerComponentsBuilder.build()); -        mDrainType = builder.mDrainType; -        mPowerConsumedByAppsMah = builder.mPowerConsumedByAppsMah; -        if (mPowerConsumedByAppsMah > getConsumedPower()) { -            Slog.wtf(TAG, -                    "Power attributed to apps exceeds total: drain type = " + mDrainType -                            + " total consumed power = " + getConsumedPower() -                            + " power consumed by apps = " + mPowerConsumedByAppsMah); -        } -    } - -    private SystemBatteryConsumer(Parcel in) { -        super(new PowerComponents(in)); -        mDrainType = in.readInt(); -        mPowerConsumedByAppsMah = in.readDouble(); -    } - -    public double getPowerConsumedByApps() { -        return mPowerConsumedByAppsMah; -    } - -    /** -     * Returns the amount of time this consumer was operating. -     */ -    public long getUsageDurationMillis() { -        return mPowerComponents.getMaxComponentUsageDurationMillis(); -    } - -    /** -     * Writes the contents into a Parcel. -     */ -    @Override -    public void writeToParcel(@NonNull Parcel dest, int flags) { -        super.writeToParcel(dest, flags); -        dest.writeInt(mDrainType); -        dest.writeDouble(mPowerConsumedByAppsMah); -    } - -    public static final Creator<SystemBatteryConsumer> CREATOR = -            new Creator<SystemBatteryConsumer>() { -                @Override -                public SystemBatteryConsumer createFromParcel(Parcel in) { -                    return new SystemBatteryConsumer(in); -                } - -                @Override -                public SystemBatteryConsumer[] newArray(int size) { -                    return new SystemBatteryConsumer[size]; -                } -            }; - -    @Override -    public int describeContents() { -        return 0; -    } - -    /** -     * Builder for SystemBatteryConsumer. -     */ -    public static final class Builder extends BaseBuilder<Builder> { -        @DrainType -        private final int mDrainType; -        private double mPowerConsumedByAppsMah; -        private List<UidBatteryConsumer.Builder> mUidBatteryConsumers; - -        Builder(@NonNull String[] customPowerComponentNames, -                boolean includePowerModels, @DrainType int drainType) { -            super(customPowerComponentNames, includePowerModels); -            mDrainType = drainType; -        } - -        /** -         * Sets the amount of power used by this system component that is attributed to apps. -         * It should not exceed the total consumed power. -         */ -        public Builder setPowerConsumedByApps(double powerConsumedByAppsMah) { -            mPowerConsumedByAppsMah = powerConsumedByAppsMah; -            return this; -        } - -        /** -         * Add a UidBatteryConsumer to this SystemBatteryConsumer. For example, -         * the UidBatteryConsumer with the UID == {@link Process#BLUETOOTH_UID} should -         * be added to the SystemBatteryConsumer with the drain type == {@link -         * #DRAIN_TYPE_BLUETOOTH}. -         * <p> -         * Calculated power and duration components of the added battery consumers -         * are aggregated at the time the SystemBatteryConsumer is built by the {@link #build()} -         * method. -         * </p> -         */ -        public void addUidBatteryConsumer(UidBatteryConsumer.Builder uidBatteryConsumerBuilder) { -            if (mUidBatteryConsumers == null) { -                mUidBatteryConsumers = new ArrayList<>(); -            } -            mUidBatteryConsumers.add(uidBatteryConsumerBuilder); -        } - -        /** -         * Creates a read-only object out of the Builder values. -         */ -        @NonNull -        public SystemBatteryConsumer build() { -            if (mUidBatteryConsumers != null) { -                for (int i = mUidBatteryConsumers.size() - 1; i >= 0; i--) { -                    UidBatteryConsumer.Builder uidBatteryConsumer = mUidBatteryConsumers.get(i); -                    mPowerComponentsBuilder.addPowerAndDuration( -                            uidBatteryConsumer.mPowerComponentsBuilder); -                } -            } -            return new SystemBatteryConsumer(this); -        } -    } -} diff --git a/core/java/android/os/VintfObject.java b/core/java/android/os/VintfObject.java index 7af8f71aa4aa..bf0b655fe574 100644 --- a/core/java/android/os/VintfObject.java +++ b/core/java/android/os/VintfObject.java @@ -16,6 +16,7 @@  package android.os; +import android.annotation.NonNull;  import android.annotation.TestApi;  import android.util.Slog; @@ -112,6 +113,15 @@ public class VintfObject {      public static native String getSepolicyVersion();      /** +     * @return the PLATFORM_SEPOLICY_VERSION build flag available in framework +     * compatibility matrix. +     * +     * @hide +     */ +    @TestApi +    public static native @NonNull String getPlatformSepolicyVersion(); + +    /**       * @return a list of VNDK snapshots supported by the framework, as       * specified in framework manifest. For example,       * [("27", ["libjpeg.so", "libbase.so"]), diff --git a/core/java/android/os/incremental/IIncrementalService.aidl b/core/java/android/os/incremental/IIncrementalService.aidl index c68f878b3b74..8c9f2ddcd3d1 100644 --- a/core/java/android/os/incremental/IIncrementalService.aidl +++ b/core/java/android/os/incremental/IIncrementalService.aidl @@ -186,7 +186,30 @@ interface IIncrementalService {       * Metrics key for delay in milliseconds to retry data loader binding. The value is a long.       */      const @utf8InCpp String METRICS_DATA_LOADER_BIND_DELAY_MILLIS = "dataLoaderBindDelayMillis"; - +    /** +     * Metrics key for total count of delayed reads caused by pending reads. The value is an int. +     */ +    const @utf8InCpp String METRICS_TOTAL_DELAYED_READS = "totalDelayedReads"; +    /** +     * Metrics key for total count of delayed reads caused by pending reads. The value is an int. +     */ +    const @utf8InCpp String METRICS_TOTAL_DELAYED_READS_MILLIS = "totalDelayedReadsMillis"; +    /** +     * Metrics key for total count of failed reads. The value is an int. +     */ +    const @utf8InCpp String METRICS_TOTAL_FAILED_READS = "totalFailedReads"; +    /** +     * Metrics key for the uid of the last read error. The value is an int. +     */ +    const @utf8InCpp String METRICS_LAST_READ_ERROR_UID = "lastReadErrorUid"; +    /** +     * Metrics key for duration in milliseconds since the last read error. The value is a long. +     */ +    const @utf8InCpp String METRICS_MILLIS_SINCE_LAST_READ_ERROR = "millisSinceLastReadError"; +    /** +     * Metrics key for the error number of the last read error. The value is an int. +     */ +    const @utf8InCpp String METRICS_LAST_READ_ERROR_NUMBER = "lastReadErrorNo";      /**       * Return a bundle containing the requested metrics keys and their values.       */ diff --git a/core/java/android/os/incremental/IncrementalMetrics.java b/core/java/android/os/incremental/IncrementalMetrics.java index 98eb4312d7bf..c44b7d97b56f 100644 --- a/core/java/android/os/incremental/IncrementalMetrics.java +++ b/core/java/android/os/incremental/IncrementalMetrics.java @@ -71,4 +71,46 @@ public class IncrementalMetrics {      public long getDataLoaderBindDelayMillis() {          return mData.getLong(IIncrementalService.METRICS_DATA_LOADER_BIND_DELAY_MILLIS, -1);      } + +    /** +     * @return total count of delayed reads caused by pending reads +     */ +    public int getTotalDelayedReads() { +        return mData.getInt(IIncrementalService.METRICS_TOTAL_DELAYED_READS, -1); +    } + +    /** +     * @return total count of failed reads +     */ +    public int getTotalFailedReads() { +        return mData.getInt(IIncrementalService.METRICS_TOTAL_FAILED_READS, -1); +    } + +    /** +     * @return total duration in milliseconds of delayed reads +     */ +    public long getTotalDelayedReadsDurationMillis() { +        return mData.getInt(IIncrementalService.METRICS_TOTAL_DELAYED_READS_MILLIS, -1); +    } + +    /** +     * @return the uid of the last read error +     */ +    public int getLastReadErrorUid() { +        return mData.getInt(IIncrementalService.METRICS_LAST_READ_ERROR_UID, -1); +    } + +    /** +     * @return duration in milliseconds since the last read error +     */ +    public long getMillisSinceLastReadError() { +        return mData.getLong(IIncrementalService.METRICS_MILLIS_SINCE_LAST_READ_ERROR, -1); +    } + +    /** +     * @return the error number of the last read error +     */ +    public int getLastReadErrorNumber() { +        return mData.getInt(IIncrementalService.METRICS_LAST_READ_ERROR_NUMBER, -1); +    }  } diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java index 17c90d64ce6a..d490e7a7b454 100644 --- a/core/java/android/permission/PermissionManager.java +++ b/core/java/android/permission/PermissionManager.java @@ -195,7 +195,7 @@ public final class PermissionManager {       * @hide Pending API       */      @Nullable -    public List<PermissionInfo> queryPermissionsByGroup(@NonNull String groupName, +    public List<PermissionInfo> queryPermissionsByGroup(@Nullable String groupName,              @PackageManager.PermissionInfoFlags int flags) {          try {              final ParceledListSlice<PermissionInfo> parceledList = diff --git a/core/java/android/view/DragAndDropPermissions.java b/core/java/android/view/DragAndDropPermissions.java index 16204d852a3a..973836a24c25 100644 --- a/core/java/android/view/DragAndDropPermissions.java +++ b/core/java/android/view/DragAndDropPermissions.java @@ -19,7 +19,6 @@ package android.view;  import static java.lang.Integer.toHexString;  import android.app.Activity; -import android.os.Binder;  import android.os.IBinder;  import android.os.Parcel;  import android.os.Parcelable; @@ -62,24 +61,6 @@ public final class DragAndDropPermissions implements Parcelable {      private static final String TAG = "DragAndDrop";      private static final boolean DEBUG = false; -    /** -     * Permissions for a drop can be granted in one of two ways: -     * <ol> -     *     <li>An app can explicitly request permissions using -     *     {@link Activity#requestDragAndDropPermissions(DragEvent)}. In this case permissions are -     *     revoked automatically when then activity is destroyed. See {@link #take(IBinder)}. -     *     <li>The platform can request permissions on behalf of the app (e.g. in -     *     {@link android.widget.Editor}). In this case permissions are revoked automatically when -     *     the app process terminates. See {@link #takeTransient()}. -     * </ol> -     * -     * <p>In order to implement the second case above, we create a static token object here. This -     * ensures that the token stays alive for the lifetime of the app process, allowing us to -     * revoke permissions when the app process terminates using {@link IBinder#linkToDeath} in -     * {@code DragAndDropPermissionsHandler}. -     */ -    private static IBinder sAppToken; -      private final IDragAndDropPermissions mDragAndDropPermissions;      /** @@ -128,7 +109,9 @@ public final class DragAndDropPermissions implements Parcelable {      }      /** -     * Take permissions transiently. Permissions will be revoked when the app process terminates. +     * Take permissions transiently. Permissions will be tied to this object's lifecycle; if not +     * released explicitly, they will be released automatically when there are no more references +     * to this object and it's garbage collected.       *       * <p>Note: This API is not exposed to apps.       * @@ -138,14 +121,10 @@ public final class DragAndDropPermissions implements Parcelable {       */      public boolean takeTransient() {          try { -            if (sAppToken == null) { -                sAppToken = new Binder(); -            }              if (DEBUG) { -                Log.d(TAG, this + ": calling takeTransient() with process-bound token: " -                        + toHexString(sAppToken.hashCode())); +                Log.d(TAG, this + ": calling takeTransient()");              } -            mDragAndDropPermissions.takeTransient(sAppToken); +            mDragAndDropPermissions.takeTransient();          } catch (RemoteException e) {              Log.w(TAG, this + ": takeTransient() failed with a RemoteException", e);              return false; diff --git a/core/java/android/view/FrameMetrics.java b/core/java/android/view/FrameMetrics.java index f6d525c10cc9..3cffeb0578d4 100644 --- a/core/java/android/view/FrameMetrics.java +++ b/core/java/android/view/FrameMetrics.java @@ -16,6 +16,8 @@  package android.view; +import static android.graphics.FrameInfo.FLAG_WINDOW_VISIBILITY_CHANGED; +  import android.annotation.IntDef;  import android.compat.annotation.UnsupportedAppUsage;  import android.os.Build; @@ -172,8 +174,6 @@ public final class FrameMetrics {       **/      public static final int DEADLINE = 13; -    private static final int FRAME_INFO_FLAG_FIRST_DRAW = 1 << 0; -      /**       * Identifiers for metrics available for each frame.       * @@ -343,7 +343,7 @@ public final class FrameMetrics {          }          if (id == FIRST_DRAW_FRAME) { -            return (mTimingData[Index.FLAGS] & FRAME_INFO_FLAG_FIRST_DRAW) != 0 ? 1 : 0; +            return (mTimingData[Index.FLAGS] & FLAG_WINDOW_VISIBILITY_CHANGED) != 0 ? 1 : 0;          } else if (id == INTENDED_VSYNC_TIMESTAMP) {              return mTimingData[Index.INTENDED_VSYNC];          } else if (id == VSYNC_TIMESTAMP) { diff --git a/core/java/android/view/OnReceiveContentListener.java b/core/java/android/view/OnReceiveContentListener.java index 1e930e61c3bb..f90e01ca34b5 100644 --- a/core/java/android/view/OnReceiveContentListener.java +++ b/core/java/android/view/OnReceiveContentListener.java @@ -74,7 +74,7 @@ public interface OnReceiveContentListener {       * preserve the common behavior for inserting text. See the class javadoc for a sample       * implementation.       * -     * <p>Handling different content +     * <h3>Handling different content</h3>       * <ul>       *     <li>Text. If the {@link ContentInfo#getSource() source} is       *     {@link ContentInfo#SOURCE_AUTOFILL autofill}, the view's content should be fully @@ -86,6 +86,25 @@ public interface OnReceiveContentListener {       *     completely separate view).       * </ul>       * +     * <h3>URI permissions</h3> +     * <p>{@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION Read permissions} are +     * granted automatically by the platform for any +     * {@link android.content.ContentResolver#SCHEME_CONTENT content URIs} in the payload passed +     * to this listener. Permissions are transient and will be released automatically by the +     * platform. +     * <ul> +     *     <li>If the {@link ContentInfo#getSource() source} is the +     *     {@link ContentInfo#SOURCE_CLIPBOARD clipboard}, permissions are released whenever the +     *     next copy action is performed by the user. +     *     <li>If the source is {@link ContentInfo#SOURCE_AUTOFILL autofill}, permissions are tied +     *     to the target {@link android.app.Activity} lifecycle (released when the activity +     *     finishes). +     *     <li>For other sources, permissions are tied to the passed-in {@code payload} object +     *     (released automatically when there are no more references to it). To ensure that +     *     permissions are not released prematurely, implementations of this listener should pass +     *     along the {@code payload} object if processing is done on a background thread. +     * </ul> +     *       * @param view The view where the content insertion was requested.       * @param payload The content to insert and related metadata.       * diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index ac70dff4f03e..45c49352afff 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -146,8 +146,9 @@ public final class SurfaceControl implements Parcelable {      private static native void nativeSetBlurRegions(long transactionObj, long nativeObj,              float[][] regions, int length);      private static native void nativeSetStretchEffect(long transactionObj, long nativeObj, -            float left, float top, float right, float bottom, float vecX, float vecY, -            float maxStretchAmount); +            float width, float height, float vecX, float vecY, +            float maxStretchAmountX, float maxStretchAmountY, float childRelativeLeft, +            float childRelativeTop, float childRelativeRight, float childRelativeBottom);      private static native boolean nativeClearContentFrameStats(long nativeObject);      private static native boolean nativeGetContentFrameStats(long nativeObject, WindowContentFrameStats outStats); @@ -2468,7 +2469,7 @@ public final class SurfaceControl implements Parcelable {          if (Float.isNaN(sdrBrightness) || sdrBrightness > 1.0f                  || (sdrBrightness < 0.0f && sdrBrightness != -1.0f)) {              throw new IllegalArgumentException("sdrBrightness must be a number between 0.0f " -                    + "and 1.0f, or -1 to turn the backlight off: " + displayBrightness); +                    + "and 1.0f, or -1 to turn the backlight off: " + sdrBrightness);          }          return nativeSetDisplayBrightness(displayToken, sdrBrightness, sdrBrightnessNits,                  displayBrightness, displayBrightnessNits); @@ -3038,11 +3039,14 @@ public final class SurfaceControl implements Parcelable {          /**           * @hide           */ -        public Transaction setStretchEffect(SurfaceControl sc, float left, float top, float right, -                float bottom, float vecX, float vecY, float maxStretchAmount) { +        public Transaction setStretchEffect(SurfaceControl sc, float width, float height, +                float vecX, float vecY, float maxStretchAmountX, +                float maxStretchAmountY, float childRelativeLeft, float childRelativeTop, float childRelativeRight, +                float childRelativeBottom) {              checkPreconditions(sc); -            nativeSetStretchEffect(mNativeObject, sc.mNativeObject, left, top, right, bottom, -                    vecX, vecY, maxStretchAmount); +            nativeSetStretchEffect(mNativeObject, sc.mNativeObject, width, height, +                    vecX, vecY, maxStretchAmountX, maxStretchAmountY, childRelativeLeft, childRelativeTop, +                    childRelativeRight, childRelativeBottom);              return this;          } diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index 7bdf5cf879f3..2fce4348cbb0 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -1471,10 +1471,13 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall          }          @Override -        public void applyStretch(long frameNumber, float left, float top, float right, -                float bottom, float vecX, float vecY, float maxStretch) { -            mRtTransaction.setStretchEffect(mSurfaceControl, left, top, right, bottom, vecX, vecY, -                    maxStretch); +        public void applyStretch(long frameNumber, float width, float height, +                float vecX, float vecY, float maxStretchX, float maxStretchY, +                float childRelativeLeft, float childRelativeTop, float childRelativeRight, +                float childRelativeBottom) { +            mRtTransaction.setStretchEffect(mSurfaceControl, width, height, vecX, vecY, +                    maxStretchX, maxStretchY, childRelativeLeft, childRelativeTop, +                    childRelativeRight, childRelativeBottom);              applyOrMergeTransaction(mRtTransaction, frameNumber);          } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 0958f3fbd771..a06f193255b2 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -2764,7 +2764,9 @@ public final class ViewRootImpl implements ViewParent,                          // to resume them                          mDirty.set(0, 0, mWidth, mHeight);                      } -                    mViewFrameInfo.flags |= FrameInfo.FLAG_WINDOW_LAYOUT_CHANGED; +                } +                if (mFirst || viewVisibilityChanged) { +                    mViewFrameInfo.flags |= FrameInfo.FLAG_WINDOW_VISIBILITY_CHANGED;                  }                  relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);                  final boolean freeformResizing = (relayoutResult diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java index 1c15bbcc8b57..085eb81182f1 100644 --- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java +++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java @@ -178,6 +178,8 @@ public class AccessibilityNodeInfo implements Parcelable {      /**       * Action that long clicks on the node. +     * +     * <p>It does not support coordinate information for anchoring.</p>       */      public static final int ACTION_LONG_CLICK = 0x00000020; diff --git a/core/java/android/view/inputmethod/InputContentInfo.java b/core/java/android/view/inputmethod/InputContentInfo.java index 9aa410f8d17e..5ebd9c18d64b 100644 --- a/core/java/android/view/inputmethod/InputContentInfo.java +++ b/core/java/android/view/inputmethod/InputContentInfo.java @@ -199,7 +199,12 @@ public final class InputContentInfo implements Parcelable {      }      /** -     * Requests a temporary read-only access permission for content URI associated with this object. +     * Requests a temporary {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION read-only} +     * access permission for the content URI associated with this object. +     * +     * <p>The lifecycle of the permission granted here is tied to this object instance. If the +     * permission is not released explicitly via {@link #releasePermission()}, it will be +     * released automatically when there are no more references to this object.</p>       *       * <p>Does nothing if the temporary permission is already granted.</p>       */ diff --git a/core/java/android/view/translation/UiTranslationController.java b/core/java/android/view/translation/UiTranslationController.java index bdf217d644e2..8a2b629b53cd 100644 --- a/core/java/android/view/translation/UiTranslationController.java +++ b/core/java/android/view/translation/UiTranslationController.java @@ -105,6 +105,7 @@ public class UiTranslationController {                  || state == STATE_UI_TRANSLATION_RESUMED)) {              return;          } +          Log.i(TAG, "updateUiTranslationState state: " + stateToString(state)                  + (DEBUG ? ", views: " + views : ""));          synchronized (mLock) { @@ -235,7 +236,9 @@ public class UiTranslationController {      public void onTranslationCompleted(TranslationResponse response) {          if (response == null || response.getTranslationStatus()                  != TranslationResponse.TRANSLATION_STATUS_SUCCESS) { -            Log.w(TAG, "Fail result from TranslationService, response: " + response); +            Log.w(TAG, "Fail result from TranslationService, status=" + (response == null +                    ? "null" +                    : response.getTranslationStatus()));              return;          }          final SparseArray<ViewTranslationResponse> translatedResult = @@ -303,9 +306,8 @@ public class UiTranslationController {                  final LongSparseArray<ViewTranslationResponse> virtualChildResponse =                          translatedResult.valueAt(i);                  if (DEBUG) { -                    // TODO(b/182433547): remove before S release -                    Log.v(TAG, "onVirtualViewTranslationCompleted: receive " -                            + virtualChildResponse + " for AutofillId " + autofillId); +                    Log.v(TAG, "onVirtualViewTranslationCompleted: received response for " +                            + "AutofillId " + autofillId);                  }                  mActivity.runOnUiThread(() -> {                      if (view.getViewTranslationCallback() == null) { @@ -348,11 +350,12 @@ public class UiTranslationController {                  final ViewTranslationResponse response = translatedResult.valueAt(i);                  if (DEBUG) {                      // TODO(b/182433547): remove before S release -                    Log.v(TAG, "onTranslationCompleted: response= " + response); +                    Log.v(TAG, "onTranslationCompleted: " +                            + sanitizedViewTranslationResponse(response));                  }                  final AutofillId autofillId = response.getAutofillId();                  if (autofillId == null) { -                    Log.w(TAG, "No AutofillId is set in ViewTranslationResponse:" + response); +                    Log.w(TAG, "No AutofillId is set in ViewTranslationResponse");                      continue;                  }                  final View view = mViews.get(autofillId).get(); @@ -408,7 +411,13 @@ public class UiTranslationController {                  .setViewTranslationRequests(requests)                  .build();          if (DEBUG) { -            Log.d(TAG, "sendTranslationRequest: request= " + request); +            StringBuilder msg = new StringBuilder("sendTranslationRequest:{requests=["); +            for (ViewTranslationRequest viewRequest: requests) { +                msg.append("{request=") +                        .append(sanitizedViewTranslationRequest(viewRequest)) +                        .append("}, "); +            } +            Log.d(TAG, "sendTranslationRequest: " + msg.toString());          }          translator.requestUiTranslate(request, (r) -> r.run(), this::onTranslationCompleted);      } @@ -418,7 +427,7 @@ public class UiTranslationController {       */      private void onUiTranslationStarted(Translator translator, List<AutofillId> views) {          synchronized (mLock) { -            // Filter the request views's AutofillId +            // Filter the request views' AutofillId              SparseIntArray virtualViewChildCount = getRequestVirtualViewChildCount(views);              Map<AutofillId, long[]> viewIds = new ArrayMap<>();              Map<AutofillId, Integer> unusedIndices = null; @@ -547,7 +556,7 @@ public class UiTranslationController {                      }                      if (view == null || view.getViewTranslationCallback() == null) {                          if (DEBUG) { -                            Log.d(TAG, "View was gone or ViewTranslationCallback for autofillid " +                            Log.d(TAG, "View was gone or ViewTranslationCallback for autofillId "                                      + "= " + views.keyAt(i));                          }                          continue; @@ -603,4 +612,42 @@ public class UiTranslationController {                  return "Unknown state (" + state + ")";          }      } + +    // TODO(b/182433547): maybe remove below before S release + +    /** +     * Returns a sanitized string representation of {@link ViewTranslationRequest}; +     */ +    private static String sanitizedViewTranslationRequest(@NonNull ViewTranslationRequest request) { +        StringBuilder msg = new StringBuilder("ViewTranslationRequest:{values=["); +        for (String key: request.getKeys()) { +            final TranslationRequestValue value = request.getValue(key); +            msg.append("{text=").append(value.getText() == null +                    ? "null" +                    : "string[" + value.getText().length() + "]}, "); +        } +        return msg.toString(); +    } + +    /** +     * Returns a sanitized string representation of {@link ViewTranslationResponse}; +     */ +    private static String sanitizedViewTranslationResponse( +            @NonNull ViewTranslationResponse response) { +        StringBuilder msg = new StringBuilder("ViewTranslationResponse:{values=["); +        for (String key: response.getKeys()) { +            final TranslationResponseValue value = response.getValue(key); +            msg.append("{status=").append(value.getStatusCode()).append(", "); +            msg.append("text=").append(value.getText() == null +                    ? "null" +                    : "string[" + value.getText().length() + "], "); +            msg.append("dict=").append(value.getDictionaryDescription() == null +                    ? "null" +                    : "string[" + value.getDictionaryDescription().length() + "], "); +            msg.append("transliteration=").append(value.getTransliteration() == null +                    ? "null" +                    : "string[" + value.getTransliteration().length() + "]}, "); +        } +        return msg.toString(); +    }  } diff --git a/core/java/android/view/translation/UiTranslationManager.java b/core/java/android/view/translation/UiTranslationManager.java index 541b4941c62e..7726086a4787 100644 --- a/core/java/android/view/translation/UiTranslationManager.java +++ b/core/java/android/view/translation/UiTranslationManager.java @@ -315,6 +315,8 @@ public final class UiTranslationManager {      private static class UiTranslationStateRemoteCallback extends IRemoteCallback.Stub {          private final Executor mExecutor;          private final UiTranslationStateCallback mCallback; +        private ULocale mSourceLocale; +        private ULocale mTargetLocale;          UiTranslationStateRemoteCallback(Executor executor,                  UiTranslationStateCallback callback) { @@ -331,10 +333,12 @@ public final class UiTranslationManager {              int state = bundle.getInt(EXTRA_STATE);              switch (state) {                  case STATE_UI_TRANSLATION_STARTED: +                    mSourceLocale = (ULocale) bundle.getSerializable(EXTRA_SOURCE_LOCALE); +                    mTargetLocale = (ULocale) bundle.getSerializable(EXTRA_TARGET_LOCALE); +                    mCallback.onStarted(mSourceLocale, mTargetLocale); +                    break;                  case STATE_UI_TRANSLATION_RESUMED: -                    mCallback.onStarted( -                            (ULocale) bundle.getSerializable(EXTRA_SOURCE_LOCALE), -                            (ULocale) bundle.getSerializable(EXTRA_TARGET_LOCALE)); +                    mCallback.onStarted(mSourceLocale, mTargetLocale);                      break;                  case STATE_UI_TRANSLATION_PAUSED:                      mCallback.onPaused(); diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index eb16cef15248..b3f848b4cf22 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -6614,27 +6614,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te      }      /** -     * Returns the {@link EdgeEffect#getType()} for the edge effects. -     * @return the {@link EdgeEffect#getType()} for the edge effects. -     * @attr ref android.R.styleable#EdgeEffect_edgeEffectType -     */ -    @EdgeEffect.EdgeEffectType -    public int getEdgeEffectType() { -        return mEdgeGlowTop.getType(); -    } - -    /** -     * Sets the {@link EdgeEffect#setType(int)} for the edge effects. -     * @param type The edge effect type to use for the edge effects. -     * @attr ref android.R.styleable#EdgeEffect_edgeEffectType -     */ -    public void setEdgeEffectType(@EdgeEffect.EdgeEffectType int type) { -        mEdgeGlowTop.setType(type); -        mEdgeGlowBottom.setType(type); -        invalidate(); -    } - -    /**       * Sets the recycler listener to be notified whenever a View is set aside in       * the recycler for later reuse. This listener can be used to free resources       * associated to the View. diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java index 4d2d9e86f1a6..756e3ce91bf9 100644 --- a/core/java/android/widget/EdgeEffect.java +++ b/core/java/android/widget/EdgeEffect.java @@ -62,9 +62,7 @@ import java.lang.annotation.RetentionPolicy;   */  public class EdgeEffect {      /** -     * This sets the default value for {@link #setType(int)} to {@link #TYPE_STRETCH} instead -     * of {@link #TYPE_GLOW}. The type can still be overridden by the theme, view attribute, -     * or by calling {@link #setType(int)}. +     * This sets the edge effect to use stretch instead of glow.       *       * @hide       */ @@ -73,34 +71,19 @@ public class EdgeEffect {      public static final long USE_STRETCH_EDGE_EFFECT_BY_DEFAULT = 171228096L;      /** -     * This sets the default value for {@link #setType(int)} to {@link #TYPE_STRETCH} instead -     * of {@link #TYPE_GLOW} for views that instantiate with -     * {@link #EdgeEffect(Context, AttributeSet)}, indicating use of S+ EdgeEffect support. The -     * type can still be overridden by the theme, view attribute, or by calling -     * {@link #setType(int)}. -     * -     * @hide -     */ -    @ChangeId -    @EnabledSince(targetSdkVersion = Build.VERSION_CODES.S) -    public static final long USE_STRETCH_EDGE_EFFECT_FOR_SUPPORTED = 178807038L; - -    /**       * The default blend mode used by {@link EdgeEffect}.       */      public static final BlendMode DEFAULT_BLEND_MODE = BlendMode.SRC_ATOP;      /** -     * Use a color edge glow for the edge effect. From XML, use -     * <code>android:edgeEffectType="glow"</code>. +     * Use a color edge glow for the edge effect.       */ -    public static final int TYPE_GLOW = 0; +    private static final int TYPE_GLOW = 0;      /** -     * Use a stretch for the edge effect. From XML, use -     * <code>android:edgeEffectType="stretch"</code>. +     * Use a stretch for the edge effect.       */ -    public static final int TYPE_STRETCH = 1; +    private static final int TYPE_STRETCH = 1;      /**       * The velocity threshold before the spring animation is considered settled. @@ -221,7 +204,7 @@ public class EdgeEffect {       * @param context Context used to provide theming and resource information for the EdgeEffect       */      public EdgeEffect(Context context) { -        this(context, null, Compatibility.isChangeEnabled(USE_STRETCH_EDGE_EFFECT_BY_DEFAULT)); +        this(context, null);      }      /** @@ -230,20 +213,12 @@ public class EdgeEffect {       * @param attrs The attributes of the XML tag that is inflating the view       */      public EdgeEffect(@NonNull Context context, @Nullable AttributeSet attrs) { -        this(context, attrs, -                Compatibility.isChangeEnabled(USE_STRETCH_EDGE_EFFECT_BY_DEFAULT) -                        || Compatibility.isChangeEnabled(USE_STRETCH_EDGE_EFFECT_FOR_SUPPORTED)); -    } - -    private EdgeEffect(@NonNull Context context, @Nullable AttributeSet attrs, -            boolean defaultStretch) {          final TypedArray a = context.obtainStyledAttributes(                  attrs, com.android.internal.R.styleable.EdgeEffect);          final int themeColor = a.getColor(                  com.android.internal.R.styleable.EdgeEffect_colorEdgeEffect, 0xff666666); -        mEdgeEffectType = a.getInt( -                com.android.internal.R.styleable.EdgeEffect_edgeEffectType, -                defaultStretch ? TYPE_STRETCH : TYPE_GLOW); +        mEdgeEffectType = Compatibility.isChangeEnabled(USE_STRETCH_EDGE_EFFECT_BY_DEFAULT) +                ? TYPE_STRETCH : TYPE_GLOW;          a.recycle();          mPaint.setAntiAlias(true); @@ -467,7 +442,6 @@ public class EdgeEffect {          if (mEdgeEffectType == TYPE_STRETCH) {              mState = STATE_RECEDE;              mVelocity = velocity * ON_ABSORB_VELOCITY_ADJUSTMENT; -            mDistance = 0;              mStartTime = AnimationUtils.currentAnimationTimeMillis();          } else {              mState = STATE_ABSORB; @@ -506,17 +480,6 @@ public class EdgeEffect {      }      /** -     * Sets the edge effect type to use. The default without a theme attribute set is -     * {@link EdgeEffect#TYPE_GLOW}. -     * -     * @param type The edge effect type to use. -     * @attr ref android.R.styleable#EdgeEffect_edgeEffectType -     */ -    public void setType(@EdgeEffectType int type) { -        mEdgeEffectType = type; -    } - -    /**       * Set or clear the blend mode. A blend mode defines how source pixels       * (generated by a drawing command) are composited with the destination pixels       * (content of the render target). @@ -542,16 +505,6 @@ public class EdgeEffect {      }      /** -     * Return the edge effect type to use. -     * -     * @return The edge effect type to use. -     * @attr ref android.R.styleable#EdgeEffect_edgeEffectType -     */ -    public @EdgeEffectType int getType() { -        return mEdgeEffectType; -    } - -    /**       * Returns the blend mode. A blend mode defines how source pixels       * (generated by a drawing command) are composited with the destination pixels       * (content of the render target). @@ -568,7 +521,7 @@ public class EdgeEffect {       * Draw into the provided canvas. Assumes that the canvas has been rotated       * accordingly and the size has been set. The effect will be drawn the full       * width of X=0 to X=width, beginning from Y=0 and extending to some factor < -     * 1.f of height. The {@link #TYPE_STRETCH} effect will only be visible on a +     * 1.f of height. The effect will only be visible on a       * hardware canvas, e.g. {@link RenderNode#beginRecording()}.       *       * @param canvas Canvas to draw into @@ -641,14 +594,10 @@ public class EdgeEffect {              boolean hasValidVectors = Float.isFinite(vecX) && Float.isFinite(vecY);              if (right > left && bottom > top && mWidth > 0 && mHeight > 0 && hasValidVectors) {                  renderNode.stretch( -                        left, -                        top, -                        right, -                        bottom, -                        vecX, -                        vecY, -                        mWidth, -                        mHeight +                        vecX, // horizontal stretch intensity +                        vecY, // vertical stretch intensity +                        mWidth, // max horizontal stretch in pixels +                        mHeight // max vertical stretch in pixels                  );              }          } else { @@ -686,7 +635,7 @@ public class EdgeEffect {       * @return The maximum height of the edge effect       */      public int getMaxHeight() { -        return (int) (mBounds.height() * MAX_GLOW_SCALE + 0.5f); +        return (int) mHeight;      }      private void update() { diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index e06d5f00fb2c..444736160f0f 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -6684,13 +6684,13 @@ public class Editor {                      if (TextView.DEBUG_CURSOR) {                          logCursor("SelectionModifierCursorController: onTouchEvent", "ACTION_UP");                      } +                    if (mEndHandle != null) { +                        mEndHandle.dismissMagnifier(); +                    }                      if (!isDragAcceleratorActive()) {                          break;                      }                      updateSelection(event); -                    if (mEndHandle != null) { -                        mEndHandle.dismissMagnifier(); -                    }                      // No longer dragging to select text, let the parent intercept events.                      mTextView.getParent().requestDisallowInterceptTouchEvent(false); diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java index e41893e37103..018cba7f95e5 100644 --- a/core/java/android/widget/HorizontalScrollView.java +++ b/core/java/android/widget/HorizontalScrollView.java @@ -308,27 +308,6 @@ public class HorizontalScrollView extends FrameLayout {      }      /** -     * Returns the {@link EdgeEffect#getType()} for the edge effects. -     * @return the {@link EdgeEffect#getType()} for the edge effects. -     * @attr ref android.R.styleable#EdgeEffect_edgeEffectType -     */ -    @EdgeEffect.EdgeEffectType -    public int getEdgeEffectType() { -        return mEdgeGlowLeft.getType(); -    } - -    /** -     * Sets the {@link EdgeEffect#setType(int)} for the edge effects. -     * @param type The edge effect type to use for the edge effects. -     * @attr ref android.R.styleable#EdgeEffect_edgeEffectType -     */ -    public void setEdgeEffectType(@EdgeEffect.EdgeEffectType int type) { -        mEdgeGlowRight.setType(type); -        mEdgeGlowLeft.setType(type); -        invalidate(); -    } - -    /**       * @return The maximum amount this scroll view will scroll in response to       *   an arrow event.       */ diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java index 3610eb47edbc..693b13bbf224 100644 --- a/core/java/android/widget/ScrollView.java +++ b/core/java/android/widget/ScrollView.java @@ -340,27 +340,6 @@ public class ScrollView extends FrameLayout {      }      /** -     * Returns the {@link EdgeEffect#getType()} for the edge effects. -     * @return the {@link EdgeEffect#getType()} for the edge effects. -     * @attr ref android.R.styleable#EdgeEffect_edgeEffectType -     */ -    @EdgeEffect.EdgeEffectType -    public int getEdgeEffectType() { -        return mEdgeGlowTop.getType(); -    } - -    /** -     * Sets the {@link EdgeEffect#setType(int)} for the edge effects. -     * @param type The edge effect type to use for the edge effects. -     * @attr ref android.R.styleable#EdgeEffect_edgeEffectType -     */ -    public void setEdgeEffectType(@EdgeEffect.EdgeEffectType int type) { -        mEdgeGlowTop.setType(type); -        mEdgeGlowBottom.setType(type); -        invalidate(); -    } - -    /**       * @return The maximum amount this scroll view will scroll in response to       *   an arrow event.       */ @@ -368,7 +347,6 @@ public class ScrollView extends FrameLayout {          return (int) (MAX_SCROLL_FACTOR * (mBottom - mTop));      } -      private void initScrollView() {          mScroller = new OverScroller(getContext());          setFocusable(true); diff --git a/core/java/com/android/internal/annotations/CompositeRWLock.java b/core/java/com/android/internal/annotations/CompositeRWLock.java deleted file mode 100644 index b6ddfc4d2cc4..000000000000 --- a/core/java/com/android/internal/annotations/CompositeRWLock.java +++ /dev/null @@ -1,47 +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.internal.annotations; - -import static java.lang.annotation.ElementType.FIELD; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Specifies a list of locks which are required for read/write operations on a data field. - * - * <p> - * To annotate methods accessing the data field with the annotation {@link CompositeRWLock}, - * use {@link GuardedBy#value} to annotate method w/ write and/or read access to the data field, - * use {@link GuardedBy#anyOf} to annotate method w/ read only access to the data field. - * </p> - * - * <p> - * When its {@link #value()} consists of multiple locks: - * <ul> - *   <li>To write to the protected data, acquire <b>all</b> of the locks - *       in the order of the appearance in the {@link #value}.</li> - *   <li>To read from the protected data, acquire any of the locks in the {@link #value}.</li> - * </ul> - * </p> - */ -@Target({FIELD}) -@Retention(RetentionPolicy.CLASS) -public @interface CompositeRWLock { -    String[] value() default {}; -} diff --git a/core/java/com/android/internal/annotations/GuardedBy.java b/core/java/com/android/internal/annotations/GuardedBy.java deleted file mode 100644 index c05c4abd10e4..000000000000 --- a/core/java/com/android/internal/annotations/GuardedBy.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2012 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.annotations; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation type used to mark a method or field that can only be accessed when - * holding the referenced locks. - */ -@Target({FIELD, METHOD}) -@Retention(RetentionPolicy.CLASS) -public @interface GuardedBy { -    /** -     * Specifies a list of locks to be held in order to access the field/method -     * annotated with this; when used in conjunction with the {@link CompositeRWLock}, locks -     * should be acquired in the order of the appearance in the {@link #value} here. -     * -     * <p> -     * If specified, {@link #anyOf()} must be null. -     * </p> -     * -     * @see CompositeRWLock -     */ -    String[] value() default {}; - -    /** -     * Specifies a list of locks where at least one of them must be held in order to access -     * the field/method annotated with this; it should be <em>only</em> used in the conjunction -     * with the {@link CompositeRWLock}. -     * -     * <p> -     * If specified, {@link #allOf()} must be null. -     * </p> -     * -     * @see CompositeRWLock -     */ -    String[] anyOf() default {}; -} diff --git a/core/java/com/android/internal/annotations/Immutable.java b/core/java/com/android/internal/annotations/Immutable.java deleted file mode 100644 index b424275f7a86..000000000000 --- a/core/java/com/android/internal/annotations/Immutable.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2012 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.annotations; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation type used to mark a class which is immutable. - */ -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.CLASS) -public @interface Immutable { -} diff --git a/core/java/com/android/internal/annotations/VisibleForNative.java b/core/java/com/android/internal/annotations/VisibleForNative.java deleted file mode 100644 index e6a3fc67b7d3..000000000000 --- a/core/java/com/android/internal/annotations/VisibleForNative.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - *      http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.annotations; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Denotes that the class, method or field has its visibility relaxed so - * that native code can access it. - */ -@Retention(RetentionPolicy.CLASS) -public @interface VisibleForNative { -} diff --git a/core/java/com/android/internal/annotations/VisibleForTesting.java b/core/java/com/android/internal/annotations/VisibleForTesting.java deleted file mode 100644 index 99512ac68d5d..000000000000 --- a/core/java/com/android/internal/annotations/VisibleForTesting.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2012 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.annotations; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Denotes that the class, method or field has its visibility relaxed so - * that unit tests can access it. - * <p/> - * The <code>visibility</code> argument can be used to specific what the original - * visibility should have been if it had not been made public or package-private for testing. - * The default is to consider the element private. - */ -@Retention(RetentionPolicy.CLASS) -public @interface VisibleForTesting { -    /** -     * Intended visibility if the element had not been made public or package-private for -     * testing. -     */ -    enum Visibility { -        /** The element should be considered protected. */ -        PROTECTED, -        /** The element should be considered package-private. */ -        PACKAGE, -        /** The element should be considered private. */ -        PRIVATE -    } - -    /** -     * Intended visibility if the element had not been made public or package-private for testing. -     * If not specified, one should assume the element originally intended to be private. -     */ -    Visibility visibility() default Visibility.PRIVATE; -} diff --git a/core/java/com/android/internal/graphics/ColorUtils.java b/core/java/com/android/internal/graphics/ColorUtils.java index 8b2a2dc38e95..537e797c9bac 100644 --- a/core/java/com/android/internal/graphics/ColorUtils.java +++ b/core/java/com/android/internal/graphics/ColorUtils.java @@ -22,6 +22,8 @@ import android.annotation.IntRange;  import android.annotation.NonNull;  import android.graphics.Color; +import com.android.internal.graphics.cam.Cam; +  /**   * Copied from: frameworks/support/core-utils/java/android/support/v4/graphics/ColorUtils.java   * @@ -333,6 +335,35 @@ public final class ColorUtils {      }      /** +     * Convert the ARGB color to a color appearance model. +     * +     * The color appearance model is based on CAM16 hue and chroma, using L*a*b*'s L* as the +     * third dimension. +     * +     * @param color the ARGB color to convert. The alpha component is ignored. +     */ +    public static Cam colorToCAM(@ColorInt int color) { +        return Cam.fromInt(color); +    } + +    /** +     * Convert a color appearance model representation to an ARGB color. +     * +     * Note: the returned color may have a lower chroma than requested. Whether a chroma is +     * available depends on luminance. For example, there's no such thing as a high chroma light +     * red, due to the limitations of our eyes and/or physics. If the requested chroma is +     * unavailable, the highest possible chroma at the requested luminance is returned. +     * +     * @param hue hue, in degrees, in CAM coordinates +     * @param chroma chroma in CAM coordinates. +     * @param lstar perceptual luminance, L* in L*a*b* +     */ +    @ColorInt +    public static int CAMToColor(float hue, float chroma, float lstar) { +        return Cam.getInt(hue, chroma, lstar); +    } + +    /**       * Set the alpha component of {@code color} to be {@code alpha}.       */      @ColorInt diff --git a/core/java/com/android/internal/graphics/cam/Cam.java b/core/java/com/android/internal/graphics/cam/Cam.java new file mode 100644 index 000000000000..1ac5e5056c1e --- /dev/null +++ b/core/java/com/android/internal/graphics/cam/Cam.java @@ -0,0 +1,509 @@ +/* + * 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.graphics.cam; + +import android.annotation.NonNull; +import android.annotation.Nullable; + +import com.android.internal.graphics.ColorUtils; + +/** + * A color appearance model, based on CAM16, extended to use L* as the lightness dimension, and + * coupled to a gamut mapping algorithm. Creates a color system, enables a digital design system. + */ +public class Cam { +    // The maximum difference between the requested L* and the L* returned. +    private static final float DL_MAX = 0.2f; +    // The maximum color distance, in CAM16-UCS, between a requested color and the color returned. +    private static final float DE_MAX = 1.0f; +    // When the delta between the floor & ceiling of a binary search for chroma is less than this, +    // the binary search terminates. +    private static final float CHROMA_SEARCH_ENDPOINT = 0.4f; +    // When the delta between the floor & ceiling of a binary search for J, lightness in CAM16, +    // is less than this, the binary search terminates. +    private static final float LIGHTNESS_SEARCH_ENDPOINT = 0.01f; + +    // CAM16 color dimensions, see getters for documentation. +    private final float mHue; +    private final float mChroma; +    private final float mJ; +    private final float mQ; +    private final float mM; +    private final float mS; + +    // Coordinates in UCS space. Used to determine color distance, like delta E equations in L*a*b*. +    private final float mJstar; +    private final float mAstar; +    private final float mBstar; + +    /** Hue in CAM16 */ +    public float getHue() { +        return mHue; +    } + +    /** Chroma in CAM16 */ +    public float getChroma() { +        return mChroma; +    } + +    /** Lightness in CAM16 */ +    public float getJ() { +        return mJ; +    } + +    /** +     * Brightness in CAM16. +     * +     * <p>Prefer lightness, brightness is an absolute quantity. For example, a sheet of white paper +     * is much brighter viewed in sunlight than in indoor light, but it is the lightest object under +     * any lighting. +     */ +    public float getQ() { +        return mQ; +    } + +    /** +     * Colorfulness in CAM16. +     * +     * <p>Prefer chroma, colorfulness is an absolute quantity. For example, a yellow toy car is much +     * more colorful outside than inside, but it has the same chroma in both environments. +     */ +    public float getM() { +        return mM; +    } + +    /** +     * Saturation in CAM16. +     * +     * <p>Colorfulness in proportion to brightness. Prefer chroma, saturation measures colorfulness +     * relative to the color's own brightness, where chroma is colorfulness relative to white. +     */ +    public float getS() { +        return mS; +    } + +    /** Lightness coordinate in CAM16-UCS */ +    public float getJstar() { +        return mJstar; +    } + +    /** a* coordinate in CAM16-UCS */ +    public float getAstar() { +        return mAstar; +    } + +    /** b* coordinate in CAM16-UCS */ +    public float getBstar() { +        return mBstar; +    } + +    /** Construct a CAM16 color */ +    Cam(float hue, float chroma, float j, float q, float m, float s, float jstar, float astar, +            float bstar) { +        mHue = hue; +        mChroma = chroma; +        mJ = j; +        mQ = q; +        mM = m; +        mS = s; +        mJstar = jstar; +        mAstar = astar; +        mBstar = bstar; +    } + +    /** +     * Given a hue & chroma in CAM16, L* in L*a*b*, return an ARGB integer. The chroma of the color +     * returned may, and frequently will, be lower than requested. Assumes the color is viewed in +     * the +     * frame defined by the sRGB standard. +     */ +    public static int getInt(float hue, float chroma, float lstar) { +        return getInt(hue, chroma, lstar, Frame.DEFAULT); +    } + +    /** +     * Create a color appearance model from a ARGB integer representing a color. It is assumed the +     * color was viewed in the frame defined in the sRGB standard. +     */ +    @NonNull +    public static Cam fromInt(int argb) { +        return fromIntInFrame(argb, Frame.DEFAULT); +    } + +    /** +     * Create a color appearance model from a ARGB integer representing a color, specifying the +     * frame in which the color was viewed. Prefer Cam.fromInt. +     */ +    @NonNull +    public static Cam fromIntInFrame(int argb, @NonNull Frame frame) { +        // Transform ARGB int to XYZ +        float[] xyz = CamUtils.xyzFromInt(argb); + +        // Transform XYZ to 'cone'/'rgb' responses +        float[][] matrix = CamUtils.XYZ_TO_CAM16RGB; +        float rT = (xyz[0] * matrix[0][0]) + (xyz[1] * matrix[0][1]) + (xyz[2] * matrix[0][2]); +        float gT = (xyz[0] * matrix[1][0]) + (xyz[1] * matrix[1][1]) + (xyz[2] * matrix[1][2]); +        float bT = (xyz[0] * matrix[2][0]) + (xyz[1] * matrix[2][1]) + (xyz[2] * matrix[2][2]); + +        // Discount illuminant +        float rD = frame.getRgbD()[0] * rT; +        float gD = frame.getRgbD()[1] * gT; +        float bD = frame.getRgbD()[2] * bT; + +        // Chromatic adaptation +        float rAF = (float) Math.pow(frame.getFl() * Math.abs(rD) / 100.0, 0.42); +        float gAF = (float) Math.pow(frame.getFl() * Math.abs(gD) / 100.0, 0.42); +        float bAF = (float) Math.pow(frame.getFl() * Math.abs(bD) / 100.0, 0.42); +        float rA = Math.signum(rD) * 400.0f * rAF / (rAF + 27.13f); +        float gA = Math.signum(gD) * 400.0f * gAF / (gAF + 27.13f); +        float bA = Math.signum(bD) * 400.0f * bAF / (bAF + 27.13f); + +        // redness-greenness +        float a = (float) (11.0 * rA + -12.0 * gA + bA) / 11.0f; +        // yellowness-blueness +        float b = (float) (rA + gA - 2.0 * bA) / 9.0f; + +        // auxiliary components +        float u = (20.0f * rA + 20.0f * gA + 21.0f * bA) / 20.0f; +        float p2 = (40.0f * rA + 20.0f * gA + bA) / 20.0f; + +        // hue +        float atan2 = (float) Math.atan2(b, a); +        float atanDegrees = atan2 * 180.0f / (float) Math.PI; +        float hue = +                atanDegrees < 0 +                        ? atanDegrees + 360.0f +                        : atanDegrees >= 360 ? atanDegrees - 360.0f : atanDegrees; +        float hueRadians = hue * (float) Math.PI / 180.0f; + +        // achromatic response to color +        float ac = p2 * frame.getNbb(); + +        // CAM16 lightness and brightness +        float j = 100.0f * (float) Math.pow(ac / frame.getAw(), frame.getC() * frame.getZ()); +        float q = +                4.0f +                        / frame.getC() +                        * (float) Math.sqrt(j / 100.0f) +                        * (frame.getAw() + 4.0f) +                        * frame.getFlRoot(); + +        // CAM16 chroma, colorfulness, and saturation. +        float huePrime = (hue < 20.14) ? hue + 360 : hue; +        float eHue = 0.25f * (float) (Math.cos(huePrime * Math.PI / 180.0 + 2.0) + 3.8); +        float p1 = 50000.0f / 13.0f * eHue * frame.getNc() * frame.getNcb(); +        float t = p1 * (float) Math.sqrt(a * a + b * b) / (u + 0.305f); +        float alpha = +                (float) Math.pow(t, 0.9) * (float) Math.pow(1.64 - Math.pow(0.29, frame.getN()), +                        0.73); +        // CAM16 chroma, colorfulness, saturation +        float c = alpha * (float) Math.sqrt(j / 100.0); +        float m = c * frame.getFlRoot(); +        float s = 50.0f * (float) Math.sqrt((alpha * frame.getC()) / (frame.getAw() + 4.0f)); + +        // CAM16-UCS components +        float jstar = (1.0f + 100.0f * 0.007f) * j / (1.0f + 0.007f * j); +        float mstar = 1.0f / 0.0228f * (float) Math.log(1.0f + 0.0228f * m); +        float astar = mstar * (float) Math.cos(hueRadians); +        float bstar = mstar * (float) Math.sin(hueRadians); + +        return new Cam(hue, c, j, q, m, s, jstar, astar, bstar); +    } + +    /** +     * Create a CAM from lightness, chroma, and hue coordinates. It is assumed those coordinates +     * were measured in the sRGB standard frame. +     */ +    @NonNull +    private static Cam fromJch(float j, float c, float h) { +        return fromJchInFrame(j, c, h, Frame.DEFAULT); +    } + +    /** +     * Create a CAM from lightness, chroma, and hue coordinates, and also specify the frame in which +     * the color is being viewed. +     */ +    @NonNull +    private static Cam fromJchInFrame(float j, float c, float h, Frame frame) { +        float q = +                4.0f +                        / frame.getC() +                        * (float) Math.sqrt(j / 100.0) +                        * (frame.getAw() + 4.0f) +                        * frame.getFlRoot(); +        float m = c * frame.getFlRoot(); +        float alpha = c / (float) Math.sqrt(j / 100.0); +        float s = 50.0f * (float) Math.sqrt((alpha * frame.getC()) / (frame.getAw() + 4.0f)); + +        float hueRadians = h * (float) Math.PI / 180.0f; +        float jstar = (1.0f + 100.0f * 0.007f) * j / (1.0f + 0.007f * j); +        float mstar = 1.0f / 0.0228f * (float) Math.log(1.0 + 0.0228 * m); +        float astar = mstar * (float) Math.cos(hueRadians); +        float bstar = mstar * (float) Math.sin(hueRadians); +        return new Cam(h, c, j, q, m, s, jstar, astar, bstar); +    } + +    /** +     * Distance in CAM16-UCS space between two colors. +     * +     * <p>Much like L*a*b* was designed to measure distance between colors, the CAM16 standard +     * defined a color space called CAM16-UCS to measure distance between CAM16 colors. +     */ +    public float distance(@NonNull Cam other) { +        float dJ = getJstar() - other.getJstar(); +        float dA = getAstar() - other.getAstar(); +        float dB = getBstar() - other.getBstar(); +        double dEPrime = Math.sqrt(dJ * dJ + dA * dA + dB * dB); +        double dE = 1.41 * Math.pow(dEPrime, 0.63); +        return (float) dE; +    } + +    /** Returns perceived color as an ARGB integer, as viewed in standard sRGB frame. */ +    public int viewedInSrgb() { +        return viewed(Frame.DEFAULT); +    } + +    /** Returns color perceived in a frame as an ARGB integer. */ +    public int viewed(@NonNull Frame frame) { +        float alpha = +                (getChroma() == 0.0 || getJ() == 0.0) +                        ? 0.0f +                        : getChroma() / (float) Math.sqrt(getJ() / 100.0); + +        float t = +                (float) Math.pow(alpha / Math.pow(1.64 - Math.pow(0.29, frame.getN()), 0.73), +                        1.0 / 0.9); +        float hRad = getHue() * (float) Math.PI / 180.0f; + +        float eHue = 0.25f * (float) (Math.cos(hRad + 2.0) + 3.8); +        float ac = frame.getAw() * (float) Math.pow(getJ() / 100.0, +                1.0 / frame.getC() / frame.getZ()); +        float p1 = eHue * (50000.0f / 13.0f) * frame.getNc() * frame.getNcb(); +        float p2 = (ac / frame.getNbb()); + +        float hSin = (float) Math.sin(hRad); +        float hCos = (float) Math.cos(hRad); + +        float gamma = +                23.0f * (p2 + 0.305f) * t / (23.0f * p1 + 11.0f * t * hCos + 108.0f * t * hSin); +        float a = gamma * hCos; +        float b = gamma * hSin; +        float rA = (460.0f * p2 + 451.0f * a + 288.0f * b) / 1403.0f; +        float gA = (460.0f * p2 - 891.0f * a - 261.0f * b) / 1403.0f; +        float bA = (460.0f * p2 - 220.0f * a - 6300.0f * b) / 1403.0f; + +        float rCBase = (float) Math.max(0, (27.13 * Math.abs(rA)) / (400.0 - Math.abs(rA))); +        float rC = Math.signum(rA) * (100.0f / frame.getFl()) * (float) Math.pow(rCBase, +                1.0 / 0.42); +        float gCBase = (float) Math.max(0, (27.13 * Math.abs(gA)) / (400.0 - Math.abs(gA))); +        float gC = Math.signum(gA) * (100.0f / frame.getFl()) * (float) Math.pow(gCBase, +                1.0 / 0.42); +        float bCBase = (float) Math.max(0, (27.13 * Math.abs(bA)) / (400.0 - Math.abs(bA))); +        float bC = Math.signum(bA) * (100.0f / frame.getFl()) * (float) Math.pow(bCBase, +                1.0 / 0.42); +        float rF = rC / frame.getRgbD()[0]; +        float gF = gC / frame.getRgbD()[1]; +        float bF = bC / frame.getRgbD()[2]; + + +        float[][] matrix = CamUtils.CAM16RGB_TO_XYZ; +        float x = (rF * matrix[0][0]) + (gF * matrix[0][1]) + (bF * matrix[0][2]); +        float y = (rF * matrix[1][0]) + (gF * matrix[1][1]) + (bF * matrix[1][2]); +        float z = (rF * matrix[2][0]) + (gF * matrix[2][1]) + (bF * matrix[2][2]); + +        int argb = ColorUtils.XYZToColor(x, y, z); +        return argb; +    } + +    /** +     * Given a hue & chroma in CAM16, L* in L*a*b*, and the frame in which the color will be +     * viewed, +     * return an ARGB integer. +     * +     * <p>The chroma of the color returned may, and frequently will, be lower than requested. This +     * is +     * a fundamental property of color that cannot be worked around by engineering. For example, a +     * red +     * hue, with high chroma, and high L* does not exist: red hues have a maximum chroma below 10 +     * in +     * light shades, creating pink. +     */ +    public static int getInt(float hue, float chroma, float lstar, @NonNull Frame frame) { +        // This is a crucial routine for building a color system, CAM16 itself is not sufficient. +        // +        // * Why these dimensions? +        // Hue and chroma from CAM16 are used because they're the most accurate measures of those +        // quantities. L* from L*a*b* is used because it correlates with luminance, luminance is +        // used to measure contrast for a11y purposes, thus providing a key constraint on what +        // colors +        // can be used. +        // +        // * Why is this routine required to build a color system? +        // In all perceptually accurate color spaces (i.e. L*a*b* and later), `chroma` may be +        // impossible for a given `hue` and `lstar`. +        // For example, a high chroma light red does not exist - chroma is limited to below 10 at +        // light red shades, we call that pink. High chroma light green does exist, but not dark +        // Also, when converting from another color space to RGB, the color may not be able to be +        // represented in RGB. In those cases, the conversion process ends with RGB values +        // outside 0-255 +        // The vast majority of color libraries surveyed simply round to 0 to 255. That is not an +        // option for this library, as it distorts the expected luminance, and thus the expected +        // contrast needed for a11y +        // +        // * What does this routine do? +        // Dealing with colors in one color space not fitting inside RGB is, loosely referred to as +        // gamut mapping or tone mapping. These algorithms are traditionally idiosyncratic, there is +        // no universal answer. However, because the intent of this library is to build a system for +        // digital design, and digital design uses luminance to measure contrast/a11y, we have one +        // very important constraint that leads to an objective algorithm: the L* of the returned +        // color _must_ match the requested L*. +        // +        // Intuitively, if the color must be distorted to fit into the RGB gamut, and the L* +        // requested *must* be fulfilled, than the hue or chroma of the returned color will need +        // to be different from the requested hue/chroma. +        // +        // After exploring both options, it was more intuitive that if the requested chroma could +        // not be reached, it used the highest possible chroma. The alternative was finding the +        // closest hue where the requested chroma could be reached, but that is not nearly as +        // intuitive, as the requested hue is so fundamental to the color description. + +        // If the color doesn't have meaningful chroma, return a gray with the requested Lstar. +        // +        // Yellows are very chromatic at L = 100, and blues are very chromatic at L = 0. All the +        // other hues are white at L = 100, and black at L = 0. To preserve consistency for users of +        // this system, it is better to simply return white at L* > 99, and black and L* < 0. +        if (chroma < 1.0 || Math.round(lstar) <= 0.0 || Math.round(lstar) >= 100.0) { +            return CamUtils.intFromLstar(lstar); +        } + +        hue = hue < 0 ? 0 : Math.min(360, hue); + +        // The highest chroma possible. Updated as binary search proceeds. +        float high = chroma; + +        // The guess for the current binary search iteration. Starts off at the highest chroma, +        // thus, if a color is possible at the requested chroma, the search can stop after one try. +        float mid = chroma; +        float low = 0.0f; +        boolean isFirstLoop = true; + +        Cam answer = null; + +        while (Math.abs(low - high) >= CHROMA_SEARCH_ENDPOINT) { +            // Given the current chroma guess, mid, and the desired hue, find J, lightness in +            // CAM16 color space, that creates a color with L* = `lstar` in the L*a*b* color space. +            Cam possibleAnswer = findCamByJ(hue, mid, lstar); + +            if (isFirstLoop) { +                if (possibleAnswer != null) { +                    return possibleAnswer.viewed(frame); +                } else { +                    // If this binary search iteration was the first iteration, and this point +                    // has been reached, it means the requested chroma was not available at the +                    // requested hue and L*. +                    // Proceed to a traditional binary search that starts at the midpoint between +                    // the requested chroma and 0. +                    isFirstLoop = false; +                    mid = low + (high - low) / 2.0f; +                    continue; +                } +            } + +            if (possibleAnswer == null) { +                // There isn't a CAM16 J that creates a color with L* `lstar`. Try a lower chroma. +                high = mid; +            } else { +                answer = possibleAnswer; +                // It is possible to create a color. Try higher chroma. +                low = mid; +            } + +            mid = low + (high - low) / 2.0f; +        } + +        // There was no answer: meaning, for the desired hue, there was no chroma low enough to +        // generate a color with the desired L*. +        // All values of L* are possible when there is 0 chroma. Return a color with 0 chroma, i.e. +        // a shade of gray, with the desired L*. +        if (answer == null) { +            return CamUtils.intFromLstar(lstar); +        } + +        return answer.viewed(frame); +    } + +    // Find J, lightness in CAM16 color space, that creates a color with L* = `lstar` in the L*a*b* +    // color space. +    // +    // Returns null if no J could be found that generated a color with L* `lstar`. +    @Nullable +    private static Cam findCamByJ(float hue, float chroma, float lstar) { +        float low = 0.0f; +        float high = 100.0f; +        float mid = 0.0f; +        float bestdL = 1000.0f; +        float bestdE = 1000.0f; + +        Cam bestCam = null; +        while (Math.abs(low - high) > LIGHTNESS_SEARCH_ENDPOINT) { +            mid = low + (high - low) / 2; +            // Create the intended CAM color +            Cam camBeforeClip = Cam.fromJch(mid, chroma, hue); +            // Convert the CAM color to RGB. If the color didn't fit in RGB, during the conversion, +            // the initial RGB values will be outside 0 to 255. The final RGB values are clipped to +            // 0 to 255, distorting the intended color. +            int clipped = camBeforeClip.viewedInSrgb(); +            float clippedLstar = CamUtils.lstarFromInt(clipped); +            float dL = Math.abs(lstar - clippedLstar); + +            // If the clipped color's L* is within error margin... +            if (dL < DL_MAX) { +                // ...check if the CAM equivalent of the clipped color is far away from intended CAM +                // color. For the intended color, use lightness and chroma from the clipped color, +                // and the intended hue. Callers are wondering what the lightness is, they know +                // chroma may be distorted, so the only concern here is if the hue slipped too far. +                Cam camClipped = Cam.fromInt(clipped); +                float dE = camClipped.distance( +                        Cam.fromJch(camClipped.getJ(), camClipped.getChroma(), hue)); +                if (dE <= DE_MAX) { +                    bestdL = dL; +                    bestdE = dE; +                    bestCam = camClipped; +                } +            } + +            // If there's no error at all, there's no need to search more. +            // +            // Note: this happens much more frequently than expected, but this is a very delicate +            // property which relies on extremely precise sRGB <=> XYZ calculations, as well as fine +            // tuning of the constants that determine error margins and when the binary search can +            // terminate. +            if (bestdL == 0 && bestdE == 0) { +                break; +            } + +            if (clippedLstar < lstar) { +                low = mid; +            } else { +                high = mid; +            } +        } + +        return bestCam; +    } + +} diff --git a/core/java/com/android/internal/graphics/cam/CamUtils.java b/core/java/com/android/internal/graphics/cam/CamUtils.java new file mode 100644 index 000000000000..13dafdba71f4 --- /dev/null +++ b/core/java/com/android/internal/graphics/cam/CamUtils.java @@ -0,0 +1,165 @@ +/* + * 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.graphics.cam; + + +import android.annotation.NonNull; +import android.graphics.Color; + +import com.android.internal.graphics.ColorUtils; + +/** + * Collection of methods for transforming between color spaces. + * + * <p>Methods are named $xFrom$Y. For example, lstarFromInt() returns L* from an ARGB integer. + * + * <p>These methods, generally, convert colors between the L*a*b*, XYZ, and sRGB spaces. + * + * <p>L*a*b* is a perceptually accurate color space. This is particularly important in the L* + * dimension: it measures luminance and unlike lightness measures traditionally used in UI work via + * RGB or HSL, this luminance transitions smoothly, permitting creation of pleasing shades of a + * color, and more pleasing transitions between colors. + * + * <p>XYZ is commonly used as an intermediate color space for converting between one color space to + * another. For example, to convert RGB to L*a*b*, first RGB is converted to XYZ, then XYZ is + * convered to L*a*b*. + * + * <p>sRGB is a "specification originated from work in 1990s through cooperation by Hewlett-Packard + * and Microsoft, and it was designed to be a standard definition of RGB for the internet, which it + * indeed became...The standard is based on a sampling of computer monitors at the time...The whole + * idea of sRGB is that if everyone assumed that RGB meant the same thing, then the results would be + * consistent, and reasonably good. It worked." - Fairchild, Color Models and Systems: Handbook of + * Color Psychology, 2015 + */ +public final class CamUtils { +    private CamUtils() { +    } + +    // Transforms XYZ color space coordinates to 'cone'/'RGB' responses in CAM16. +    static final float[][] XYZ_TO_CAM16RGB = { +            {0.401288f, 0.650173f, -0.051461f}, +            {-0.250268f, 1.204414f, 0.045854f}, +            {-0.002079f, 0.048952f, 0.953127f} +    }; + +    // Transforms 'cone'/'RGB' responses in CAM16 to XYZ color space coordinates. +    static final float[][] CAM16RGB_TO_XYZ = { +            {1.86206786f, -1.01125463f, 0.14918677f}, +            {0.38752654f, 0.62144744f, -0.00897398f}, +            {-0.01584150f, -0.03412294f, 1.04996444f} +    }; + +    // Need this, XYZ coordinates in internal ColorUtils are private + +    // sRGB specification has D65 whitepoint - Stokes, Anderson, Chandrasekar, Motta - A Standard +    // Default Color Space for the Internet: sRGB, 1996 +    static final float[] WHITE_POINT_D65 = {95.047f, 100.0f, 108.883f}; + +    // This is a more precise sRGB to XYZ transformation matrix than traditionally +    // used. It was derived using Schlomer's technique of transforming the xyY +    // primaries to XYZ, then applying a correction to ensure mapping from sRGB +    // 1, 1, 1 to the reference white point, D65. +    static final float[][] SRGB_TO_XYZ = { +            {0.41233895f, 0.35762064f, 0.18051042f}, +            {0.2126f, 0.7152f, 0.0722f}, +            {0.01932141f, 0.11916382f, 0.95034478f} +    }; + +    static int intFromLstar(float lstar) { +        if (lstar < 1) { +            return 0xff000000; +        } else if (lstar > 99) { +            return 0xffffffff; +        } + +        // XYZ to LAB conversion routine, assume a and b are 0. +        float fy = (lstar + 16.0f) / 116.0f; + +        // fz = fx = fy because a and b are 0 +        float fz = fy; +        float fx = fy; + +        float kappa = 24389f / 27f; +        float epsilon = 216f / 24389f; +        boolean lExceedsEpsilonKappa = (lstar > 8.0f); +        float yT = lExceedsEpsilonKappa ? fy * fy * fy : lstar / kappa; +        boolean cubeExceedEpsilon = (fy * fy * fy) > epsilon; +        float xT = cubeExceedEpsilon ? fx * fx * fx : (116f * fx - 16f) / kappa; +        float zT = cubeExceedEpsilon ? fz * fz * fz : (116f * fx - 16f) / kappa; + +        return ColorUtils.XYZToColor(xT * CamUtils.WHITE_POINT_D65[0], +                yT * CamUtils.WHITE_POINT_D65[1], zT * CamUtils.WHITE_POINT_D65[2]); +    } + +    /** Returns L* from L*a*b*, perceptual luminance, from an ARGB integer (ColorInt). */ +    public static float lstarFromInt(int argb) { +        return lstarFromY(yFromInt(argb)); +    } + +    static float lstarFromY(float y) { +        y = y / 100.0f; +        final float e = 216.f / 24389.f; +        float yIntermediate; +        if (y <= e) { +            return ((24389.f / 27.f) * y); +        } else { +            yIntermediate = (float) Math.cbrt(y); +        } +        return 116.f * yIntermediate - 16.f; +    } + +    static float yFromInt(int argb) { +        final float r = linearized(Color.red(argb)); +        final float g = linearized(Color.green(argb)); +        final float b = linearized(Color.blue(argb)); +        float[][] matrix = SRGB_TO_XYZ; +        float y = (r * matrix[1][0]) + (g * matrix[1][1]) + (b * matrix[1][2]); +        return y; +    } + +    @NonNull +    static float[] xyzFromInt(int argb) { +        final float r = linearized(Color.red(argb)); +        final float g = linearized(Color.green(argb)); +        final float b = linearized(Color.blue(argb)); + +        float[][] matrix = SRGB_TO_XYZ; +        float x = (r * matrix[0][0]) + (g * matrix[0][1]) + (b * matrix[0][2]); +        float y = (r * matrix[1][0]) + (g * matrix[1][1]) + (b * matrix[1][2]); +        float z = (r * matrix[2][0]) + (g * matrix[2][1]) + (b * matrix[2][2]); +        return new float[]{x, y, z}; +    } + +    static float yFromLstar(float lstar) { +        float ke = 8.0f; +        if (lstar > ke) { +            return (float) Math.pow(((lstar + 16.0) / 116.0), 3) * 100f; +        } else { +            return lstar / (24389f / 27f) * 100f; +        } +    } + +    static float linearized(int rgbComponent) { +        float normalized = (float) rgbComponent / 255.0f; + +        if (normalized <= 0.04045f) { +            return (normalized / 12.92f) * 100.0f; +        } else { +            return (float) Math.pow(((normalized + 0.055f) / 1.055f), 2.4f) * 100.0f; +        } +    } +} diff --git a/core/java/com/android/internal/graphics/cam/Frame.java b/core/java/com/android/internal/graphics/cam/Frame.java new file mode 100644 index 000000000000..c422ad13c652 --- /dev/null +++ b/core/java/com/android/internal/graphics/cam/Frame.java @@ -0,0 +1,194 @@ +/* + * 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.graphics.cam; + +import android.annotation.NonNull; +import android.util.MathUtils; + +/** + * The frame, or viewing conditions, where a color was seen. Used, along with a color, to create a + * color appearance model representing the color. + * + * <p>To convert a traditional color to a color appearance model, it requires knowing what + * conditions the color was observed in. Our perception of color depends on, for example, the tone + * of the light illuminating the color, how bright that light was, etc. + * + * <p>This class is modelled separately from the color appearance model itself because there are a + * number of calculations during the color => CAM conversion process that depend only on the viewing + * conditions. Caching those calculations in a Frame instance saves a significant amount of time. + */ +public final class Frame { +    // Standard viewing conditions assumed in RGB specification - Stokes, Anderson, Chandrasekar, +    // Motta - A Standard Default Color Space for the Internet: sRGB, 1996. +    // +    // White point = D65 +    // Luminance of adapting field: 200 / Pi / 5, units are cd/m^2. +    //   sRGB ambient illuminance = 64 lux (per sRGB spec). However, the spec notes this is +    //     artificially low and based on monitors in 1990s. Use 200, the sRGB spec says this is the +    //     real average, and a survey of lux values on Wikipedia confirms this is a comfortable +    //     default: somewhere between a very dark overcast day and office lighting. +    //   Per CAM16 introduction paper (Li et al, 2017) Ew = pi * lw, and La = lw * Yb/Yw +    //   Ew = ambient environment luminance, in lux. +    //   Yb/Yw is taken to be midgray, ~20% relative luminance (XYZ Y 18.4, CIELAB L* 50). +    //   Therefore La = (Ew / pi) * .184 +    //   La = 200 / pi * .184 +    // Image surround to 10 degrees = ~20% relative luminance = CIELAB L* 50 +    // +    // Not from sRGB standard: +    // Surround = average, 2.0. +    // Discounting illuminant = false, doesn't occur for self-luminous displays +    public static final Frame DEFAULT = +            Frame.make( +                    CamUtils.WHITE_POINT_D65, +                    (float) (200.0f / Math.PI * CamUtils.yFromLstar(50.0f) / 100.f), 50.0f, 2.0f, +                    false); + +    private final float mAw; +    private final float mNbb; +    private final float mNcb; +    private final float mC; +    private final float mNc; +    private final float mN; +    private final float[] mRgbD; +    private final float mFl; +    private final float mFlRoot; +    private final float mZ; + +    float getAw() { +        return mAw; +    } + +    float getN() { +        return mN; +    } + +    float getNbb() { +        return mNbb; +    } + +    float getNcb() { +        return mNcb; +    } + +    float getC() { +        return mC; +    } + +    float getNc() { +        return mNc; +    } + +    @NonNull +    float[] getRgbD() { +        return mRgbD; +    } + +    float getFl() { +        return mFl; +    } + +    float getFlRoot() { +        return mFlRoot; +    } + +    float getZ() { +        return mZ; +    } + +    private Frame(float n, float aw, float nbb, float ncb, float c, float nc, float[] rgbD, +            float fl, float fLRoot, float z) { +        mN = n; +        mAw = aw; +        mNbb = nbb; +        mNcb = ncb; +        mC = c; +        mNc = nc; +        mRgbD = rgbD; +        mFl = fl; +        mFlRoot = fLRoot; +        mZ = z; +    } + +    /** Create a custom frame. */ +    @NonNull +    public static Frame make(@NonNull float[] whitepoint, float adaptingLuminance, +            float backgroundLstar, float surround, boolean discountingIlluminant) { +        // Transform white point XYZ to 'cone'/'rgb' responses +        float[][] matrix = CamUtils.XYZ_TO_CAM16RGB; +        float[] xyz = whitepoint; +        float rW = (xyz[0] * matrix[0][0]) + (xyz[1] * matrix[0][1]) + (xyz[2] * matrix[0][2]); +        float gW = (xyz[0] * matrix[1][0]) + (xyz[1] * matrix[1][1]) + (xyz[2] * matrix[1][2]); +        float bW = (xyz[0] * matrix[2][0]) + (xyz[1] * matrix[2][1]) + (xyz[2] * matrix[2][2]); + +        // Scale input surround, domain (0, 2), to CAM16 surround, domain (0.8, 1.0) +        float f = 0.8f + (surround / 10.0f); +        // "Exponential non-linearity" +        float c = (f >= 0.9) ? MathUtils.lerp(0.59f, 0.69f, ((f - 0.9f) * 10.0f)) : MathUtils.lerp( +                0.525f, 0.59f, ((f - 0.8f) * 10.0f)); +        // Calculate degree of adaptation to illuminant +        float d = discountingIlluminant ? 1.0f : f * (1.0f - ((1.0f / 3.6f) * (float) Math.exp( +                (-adaptingLuminance - 42.0f) / 92.0f))); +        // Per Li et al, if D is greater than 1 or less than 0, set it to 1 or 0. +        d = (d > 1.0) ? 1.0f : (d < 0.0) ? 0.0f : d; +        // Chromatic induction factor +        float nc = f; + +        // Cone responses to the whitepoint, adjusted for illuminant discounting. +        // +        // Why use 100.0 instead of the white point's relative luminance? +        // +        // Some papers and implementations, for both CAM02 and CAM16, use the Y +        // value of the reference white instead of 100. Fairchild's Color Appearance +        // Models (3rd edition) notes that this is in error: it was included in the +        // CIE 2004a report on CIECAM02, but, later parts of the conversion process +        // account for scaling of appearance relative to the white point relative +        // luminance. This part should simply use 100 as luminance. +        float[] rgbD = new float[]{d * (100.0f / rW) + 1.0f - d, d * (100.0f / gW) + 1.0f - d, +                d * (100.0f / bW) + 1.0f - d, }; +        // Luminance-level adaptation factor +        float k = 1.0f / (5.0f * adaptingLuminance + 1.0f); +        float k4 = k * k * k * k; +        float k4F = 1.0f - k4; +        float fl = (k4 * adaptingLuminance) + (0.1f * k4F * k4F * (float) Math.cbrt( +                5.0 * adaptingLuminance)); + +        // Intermediate factor, ratio of background relative luminance to white relative luminance +        float n = CamUtils.yFromLstar(backgroundLstar) / whitepoint[1]; + +        // Base exponential nonlinearity +        // note Schlomer 2018 has a typo and uses 1.58, the correct factor is 1.48 +        float z = 1.48f + (float) Math.sqrt(n); + +        // Luminance-level induction factors +        float nbb = 0.725f / (float) Math.pow(n, 0.2); +        float ncb = nbb; + +        // Discounted cone responses to the white point, adjusted for post-chromatic +        // adaptation perceptual nonlinearities. +        float[] rgbAFactors = new float[]{(float) Math.pow(fl * rgbD[0] * rW / 100.0, 0.42), +                (float) Math.pow(fl * rgbD[1] * gW / 100.0, 0.42), (float) Math.pow( +                fl * rgbD[2] * bW / 100.0, 0.42)}; + +        float[] rgbA = new float[]{(400.0f * rgbAFactors[0]) / (rgbAFactors[0] + 27.13f), +                (400.0f * rgbAFactors[1]) / (rgbAFactors[1] + 27.13f), +                (400.0f * rgbAFactors[2]) / (rgbAFactors[2] + 27.13f), }; + +        float aw = ((2.0f * rgbA[0]) + rgbA[1] + (0.05f * rgbA[2])) * nbb; + +        return new Frame(n, aw, nbb, ncb, c, nc, rgbD, fl, (float) Math.pow(fl, 0.25), z); +    } +} diff --git a/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java b/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java index 73d962effc00..0307268a28b5 100644 --- a/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java +++ b/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java @@ -20,7 +20,6 @@ import android.os.BatteryConsumer;  import android.os.BatteryStats;  import android.os.BatteryUsageStats;  import android.os.BatteryUsageStatsQuery; -import android.os.SystemBatteryConsumer;  import android.os.UserHandle;  import android.util.SparseArray; @@ -50,10 +49,11 @@ public class AmbientDisplayPowerCalculator extends PowerCalculator {                  BatteryStats.STATS_SINCE_CHARGED);          final double powerMah = getMeasuredOrEstimatedPower(powerModel,                  measuredEnergyUC, mPowerEstimator, durationMs); -        builder.getOrCreateSystemBatteryConsumerBuilder( -                        SystemBatteryConsumer.DRAIN_TYPE_AMBIENT_DISPLAY) -                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN, powerMah, powerModel) -                .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN, durationMs); +        builder.getAggregateBatteryConsumerBuilder( +                BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE) +                .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY, durationMs) +                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY, +                        powerMah, powerModel);      }      /** diff --git a/core/java/com/android/internal/os/AudioPowerCalculator.java b/core/java/com/android/internal/os/AudioPowerCalculator.java index 9da8191f3747..2eab506bbb6c 100644 --- a/core/java/com/android/internal/os/AudioPowerCalculator.java +++ b/core/java/com/android/internal/os/AudioPowerCalculator.java @@ -17,8 +17,10 @@ package com.android.internal.os;  import android.os.BatteryConsumer;  import android.os.BatteryStats; +import android.os.BatteryUsageStats;  import android.os.BatteryUsageStatsQuery;  import android.os.UidBatteryConsumer; +import android.util.SparseArray;  /**   * A {@link PowerCalculator} to calculate power consumed by audio hardware. @@ -31,18 +33,47 @@ public class AudioPowerCalculator extends PowerCalculator {      // TODO(b/175344313): improve the model by taking into account different audio routes      private final UsageBasedPowerEstimator mPowerEstimator; +    private static class PowerAndDuration { +        public long durationMs; +        public double powerMah; +    } +      public AudioPowerCalculator(PowerProfile powerProfile) {          mPowerEstimator = new UsageBasedPowerEstimator(                  powerProfile.getAveragePower(PowerProfile.POWER_AUDIO));      }      @Override -    protected void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u, +    public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,              long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) { +        final PowerAndDuration total = new PowerAndDuration(); + +        final SparseArray<UidBatteryConsumer.Builder> uidBatteryConsumerBuilders = +                builder.getUidBatteryConsumerBuilders(); +        for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) { +            final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i); +            calculateApp(app, total, app.getBatteryStatsUid(), rawRealtimeUs); +        } + +        builder.getAggregateBatteryConsumerBuilder( +                BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE) +                .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_AUDIO, total.durationMs) +                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_AUDIO, total.powerMah); + +        builder.getAggregateBatteryConsumerBuilder( +                BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS) +                .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_AUDIO, total.durationMs) +                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_AUDIO, total.powerMah); +    } + +    private void calculateApp(UidBatteryConsumer.Builder app, PowerAndDuration total, +            BatteryStats.Uid u, long rawRealtimeUs) {          final long durationMs = mPowerEstimator.calculateDuration(u.getAudioTurnedOnTimer(),                  rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED);          final double powerMah = mPowerEstimator.calculatePower(durationMs);          app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_AUDIO, durationMs)                  .setConsumedPower(BatteryConsumer.POWER_COMPONENT_AUDIO, powerMah); +        total.durationMs += durationMs; +        total.powerMah += powerMah;      }  } diff --git a/core/java/com/android/internal/os/BatteryChargeCalculator.java b/core/java/com/android/internal/os/BatteryChargeCalculator.java index dc72f3267390..16f92efb922c 100644 --- a/core/java/com/android/internal/os/BatteryChargeCalculator.java +++ b/core/java/com/android/internal/os/BatteryChargeCalculator.java @@ -28,20 +28,28 @@ import java.util.List;   * Estimates the battery discharge amounts.   */  public class BatteryChargeCalculator extends PowerCalculator { -    private final double mBatteryCapacity; - -    public BatteryChargeCalculator(PowerProfile powerProfile) { -        mBatteryCapacity = powerProfile.getBatteryCapacity(); -    }      @Override      public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,              long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {          builder.setDischargePercentage( -                        batteryStats.getDischargeAmount(BatteryStats.STATS_SINCE_CHARGED)) -                .setDischargedPowerRange( -                        batteryStats.getLowDischargeAmountSinceCharge() * mBatteryCapacity / 100, -                        batteryStats.getHighDischargeAmountSinceCharge() * mBatteryCapacity / 100); +                batteryStats.getDischargeAmount(BatteryStats.STATS_SINCE_CHARGED)); + +        int batteryCapacityMah = batteryStats.getLearnedBatteryCapacity() / 1000; +        if (batteryCapacityMah <= 0) { +            batteryCapacityMah = batteryStats.getMinLearnedBatteryCapacity() / 1000; +            if (batteryCapacityMah <= 0) { +                batteryCapacityMah = batteryStats.getEstimatedBatteryCapacity(); +            } +        } +        final double dischargedPowerLowerBoundMah = +                batteryStats.getLowDischargeAmountSinceCharge() * batteryCapacityMah / 100.0; +        final double dischargedPowerUpperBoundMah = +                batteryStats.getHighDischargeAmountSinceCharge() * batteryCapacityMah / 100.0; +        builder.setDischargePercentage( +                batteryStats.getDischargeAmount(BatteryStats.STATS_SINCE_CHARGED)) +                .setDischargedPowerRange(dischargedPowerLowerBoundMah, +                        dischargedPowerUpperBoundMah);          final long batteryTimeRemainingMs = batteryStats.computeBatteryTimeRemaining(rawRealtimeUs);          if (batteryTimeRemainingMs != -1) { @@ -52,6 +60,11 @@ public class BatteryChargeCalculator extends PowerCalculator {          if (chargeTimeRemainingMs != -1) {              builder.setChargeTimeRemainingMs(chargeTimeRemainingMs / 1000);          } + +        builder.getAggregateBatteryConsumerBuilder( +                BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE) +                .setConsumedPower( +                        (dischargedPowerLowerBoundMah + dischargedPowerUpperBoundMah) / 2);      }      @Override diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 02a290850b6f..db67bab25e78 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -161,7 +161,7 @@ public class BatteryStatsImpl extends BatteryStats {      private static final int MAGIC = 0xBA757475; // 'BATSTATS'      // Current on-disk Parcel version -    static final int VERSION = 198; +    static final int VERSION = 199;      // The maximum number of names wakelocks we will keep track of      // per uid; once the limit is reached, we batch the remaining wakelocks @@ -1056,6 +1056,7 @@ public class BatteryStatsImpl extends BatteryStats {      private int mBatteryVoltageMv = -1;      private int mEstimatedBatteryCapacityMah = -1; +    private int mLastLearnedBatteryCapacityUah = -1;      private int mMinLearnedBatteryCapacityUah = -1;      private int mMaxLearnedBatteryCapacityUah = -1; @@ -1142,6 +1143,11 @@ public class BatteryStatsImpl extends BatteryStats {      }      @Override +    public int getLearnedBatteryCapacity() { +        return mLastLearnedBatteryCapacityUah; +    } + +    @Override      public int getMinLearnedBatteryCapacity() {          return mMinLearnedBatteryCapacityUah;      } @@ -11199,6 +11205,7 @@ public class BatteryStatsImpl extends BatteryStats {          } else {              mEstimatedBatteryCapacityMah = -1;          } +        mLastLearnedBatteryCapacityUah = -1;          mMinLearnedBatteryCapacityUah = -1;          mMaxLearnedBatteryCapacityUah = -1;          mInteractiveTimer.reset(false, elapsedRealtimeUs); @@ -13799,6 +13806,7 @@ public class BatteryStatsImpl extends BatteryStats {              mRecordingHistory = DEBUG;          } +        mLastLearnedBatteryCapacityUah = chargeFullUah;          if (mMinLearnedBatteryCapacityUah == -1) {              mMinLearnedBatteryCapacityUah = chargeFullUah;          } else { @@ -15066,6 +15074,7 @@ public class BatteryStatsImpl extends BatteryStats {          mDischargeCurrentLevel = in.readInt();          mCurrentBatteryLevel = in.readInt();          mEstimatedBatteryCapacityMah = in.readInt(); +        mLastLearnedBatteryCapacityUah = in.readInt();          mMinLearnedBatteryCapacityUah = in.readInt();          mMaxLearnedBatteryCapacityUah = in.readInt();          mLowDischargeAmountSinceCharge = in.readInt(); @@ -15570,6 +15579,7 @@ public class BatteryStatsImpl extends BatteryStats {          out.writeInt(mDischargeCurrentLevel);          out.writeInt(mCurrentBatteryLevel);          out.writeInt(mEstimatedBatteryCapacityMah); +        out.writeInt(mLastLearnedBatteryCapacityUah);          out.writeInt(mMinLearnedBatteryCapacityUah);          out.writeInt(mMaxLearnedBatteryCapacityUah);          out.writeInt(getLowDischargeAmountSinceCharge()); @@ -16071,6 +16081,7 @@ public class BatteryStatsImpl extends BatteryStats {          mRealtimeStartUs = in.readLong();          mOnBattery = in.readInt() != 0;          mEstimatedBatteryCapacityMah = in.readInt(); +        mLastLearnedBatteryCapacityUah = in.readInt();          mMinLearnedBatteryCapacityUah = in.readInt();          mMaxLearnedBatteryCapacityUah = in.readInt();          mOnBatteryInternal = false; // we are no longer really running. @@ -16310,6 +16321,7 @@ public class BatteryStatsImpl extends BatteryStats {          out.writeLong(mRealtimeStartUs);          out.writeInt(mOnBattery ? 1 : 0);          out.writeInt(mEstimatedBatteryCapacityMah); +        out.writeInt(mLastLearnedBatteryCapacityUah);          out.writeInt(mMinLearnedBatteryCapacityUah);          out.writeInt(mMaxLearnedBatteryCapacityUah);          mOnBatteryTimeBase.writeToParcel(out, uSecUptime, uSecRealtime); diff --git a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java index babcea14d0ea..498955983ef2 100644 --- a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java +++ b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java @@ -54,7 +54,7 @@ public class BatteryUsageStatsProvider {                  mPowerCalculators = new ArrayList<>();                  // Power calculators are applied in the order of registration -                mPowerCalculators.add(new BatteryChargeCalculator(mPowerProfile)); +                mPowerCalculators.add(new BatteryChargeCalculator());                  mPowerCalculators.add(new CpuPowerCalculator(mPowerProfile));                  mPowerCalculators.add(new MemoryPowerCalculator(mPowerProfile));                  mPowerCalculators.add(new WakelockPowerCalculator(mPowerProfile)); diff --git a/core/java/com/android/internal/os/BluetoothPowerCalculator.java b/core/java/com/android/internal/os/BluetoothPowerCalculator.java index 2c32e48c9685..6e99bbbf2331 100644 --- a/core/java/com/android/internal/os/BluetoothPowerCalculator.java +++ b/core/java/com/android/internal/os/BluetoothPowerCalculator.java @@ -21,7 +21,6 @@ import android.os.BatteryStats.ControllerActivityCounter;  import android.os.BatteryUsageStats;  import android.os.BatteryUsageStatsQuery;  import android.os.Process; -import android.os.SystemBatteryConsumer;  import android.os.UidBatteryConsumer;  import android.os.UserHandle;  import android.util.Log; @@ -58,19 +57,11 @@ public class BluetoothPowerCalculator extends PowerCalculator {          final PowerAndDuration total = new PowerAndDuration(); -        SystemBatteryConsumer.Builder systemBatteryConsumerBuilder = -                builder.getOrCreateSystemBatteryConsumerBuilder( -                        SystemBatteryConsumer.DRAIN_TYPE_BLUETOOTH); -          final SparseArray<UidBatteryConsumer.Builder> uidBatteryConsumerBuilders =                  builder.getUidBatteryConsumerBuilders();          for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) {              final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i);              calculateApp(app, total, query); -            if (app.getUid() == Process.BLUETOOTH_UID) { -                app.excludeFromBatteryUsageStats(); -                systemBatteryConsumerBuilder.addUidBatteryConsumer(app); -            }          }          final long measuredChargeUC = batteryStats.getBluetoothMeasuredBatteryConsumptionUC(); @@ -87,12 +78,18 @@ public class BluetoothPowerCalculator extends PowerCalculator {              Log.d(TAG, "Bluetooth active: time=" + (systemComponentDurationMs)                      + " power=" + formatCharge(systemPowerMah));          } -        systemBatteryConsumerBuilder -                .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_BLUETOOTH, -                        systemComponentDurationMs) + +        builder.getAggregateBatteryConsumerBuilder( +                BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE) +                .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_BLUETOOTH, systemDurationMs)                  .setConsumedPower(BatteryConsumer.POWER_COMPONENT_BLUETOOTH, -                        Math.max(systemPowerMah, total.powerMah), powerModel) -                .setPowerConsumedByApps(total.powerMah); +                        Math.max(systemPowerMah, total.powerMah), powerModel); + +        builder.getAggregateBatteryConsumerBuilder( +                BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS) +                .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_BLUETOOTH, total.durationMs) +                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_BLUETOOTH, total.powerMah, +                        powerModel);      }      private void calculateApp(UidBatteryConsumer.Builder app, PowerAndDuration total, diff --git a/core/java/com/android/internal/os/CameraPowerCalculator.java b/core/java/com/android/internal/os/CameraPowerCalculator.java index e56e7beddecb..ddcabe869b32 100644 --- a/core/java/com/android/internal/os/CameraPowerCalculator.java +++ b/core/java/com/android/internal/os/CameraPowerCalculator.java @@ -17,6 +17,7 @@ package com.android.internal.os;  import android.os.BatteryConsumer;  import android.os.BatteryStats; +import android.os.BatteryUsageStats;  import android.os.BatteryUsageStatsQuery;  import android.os.UidBatteryConsumer; @@ -36,6 +37,24 @@ public class CameraPowerCalculator extends PowerCalculator {      }      @Override +    public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats, +            long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) { +        super.calculate(builder, batteryStats, rawRealtimeUs, rawUptimeUs, query); + +        final long durationMs = batteryStats.getCameraOnTime(rawRealtimeUs, +                BatteryStats.STATS_SINCE_CHARGED) / 1000; +        final double powerMah = mPowerEstimator.calculatePower(durationMs); +        builder.getAggregateBatteryConsumerBuilder( +                BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE) +                .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CAMERA, durationMs) +                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA, powerMah); +        builder.getAggregateBatteryConsumerBuilder( +                BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS) +                .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CAMERA, durationMs) +                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA, powerMah); +    } + +    @Override      protected void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u,              long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {          final long durationMs = diff --git a/core/java/com/android/internal/os/CpuPowerCalculator.java b/core/java/com/android/internal/os/CpuPowerCalculator.java index 2a55aa9daf6c..0d041c4440d2 100644 --- a/core/java/com/android/internal/os/CpuPowerCalculator.java +++ b/core/java/com/android/internal/os/CpuPowerCalculator.java @@ -80,13 +80,28 @@ public class CpuPowerCalculator extends PowerCalculator {      @Override      public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,              long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) { +        double totalPowerMah = 0; +          Result result = new Result();          final SparseArray<UidBatteryConsumer.Builder> uidBatteryConsumerBuilders =                  builder.getUidBatteryConsumerBuilders();          for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) {              final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i);              calculateApp(app, app.getBatteryStatsUid(), query, result); +            totalPowerMah += result.powerMah;          } + +        final long consumptionUC = batteryStats.getCpuMeasuredBatteryConsumptionUC(); +        final int powerModel = getPowerModel(consumptionUC, query); + +        builder.getAggregateBatteryConsumerBuilder( +                BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS) +                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU, totalPowerMah); +        builder.getAggregateBatteryConsumerBuilder( +                BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE) +                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU, +                        powerModel == BatteryConsumer.POWER_MODEL_MEASURED_ENERGY +                                ? uCtoMah(consumptionUC) : totalPowerMah, powerModel);      }      private void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u, diff --git a/core/java/com/android/internal/os/CustomMeasuredPowerCalculator.java b/core/java/com/android/internal/os/CustomMeasuredPowerCalculator.java index 9941e30f5d1c..9b51a8ef6410 100644 --- a/core/java/com/android/internal/os/CustomMeasuredPowerCalculator.java +++ b/core/java/com/android/internal/os/CustomMeasuredPowerCalculator.java @@ -15,12 +15,13 @@   */  package com.android.internal.os; +import android.os.AggregateBatteryConsumer;  import android.os.BatteryConsumer;  import android.os.BatteryStats;  import android.os.BatteryUsageStats;  import android.os.BatteryUsageStatsQuery; -import android.os.SystemBatteryConsumer;  import android.os.UidBatteryConsumer; +import android.util.SparseArray;  /**   * Calculates the amount of power consumed by custom energy consumers (i.e. consumers of type @@ -33,33 +34,62 @@ public class CustomMeasuredPowerCalculator extends PowerCalculator {      @Override      public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,              long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) { -        super.calculate(builder, batteryStats, rawRealtimeUs, rawUptimeUs, query); +        double[] totalAppPowerMah = null; + +        final SparseArray<UidBatteryConsumer.Builder> uidBatteryConsumerBuilders = +                builder.getUidBatteryConsumerBuilders(); +        for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) { +            final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i); +            totalAppPowerMah = calculateApp(app, app.getBatteryStatsUid(), totalAppPowerMah); +        } +          final double[] customMeasuredPowerMah = calculateMeasuredEnergiesMah(                  batteryStats.getCustomConsumerMeasuredBatteryConsumptionUC());          if (customMeasuredPowerMah != null) { -            final SystemBatteryConsumer.Builder systemBatteryConsumerBuilder = -                    builder.getOrCreateSystemBatteryConsumerBuilder( -                            SystemBatteryConsumer.DRAIN_TYPE_CUSTOM); +            final AggregateBatteryConsumer.Builder deviceBatteryConsumerBuilder = +                    builder.getAggregateBatteryConsumerBuilder( +                            BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE);              for (int i = 0; i < customMeasuredPowerMah.length; i++) { -                systemBatteryConsumerBuilder.setConsumedPowerForCustomComponent( +                deviceBatteryConsumerBuilder.setConsumedPowerForCustomComponent(                          BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID + i,                          customMeasuredPowerMah[i]);              }          } +        if (totalAppPowerMah != null) { +            final AggregateBatteryConsumer.Builder appsBatteryConsumerBuilder = +                    builder.getAggregateBatteryConsumerBuilder( +                            BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS); +            for (int i = 0; i < totalAppPowerMah.length; i++) { +                appsBatteryConsumerBuilder.setConsumedPowerForCustomComponent( +                        BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID + i, +                        totalAppPowerMah[i]); +            } +        }      } -    @Override -    protected void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u, -            long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) { +    private double[] calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u, +            double[] totalPowerMah) { +        double[] newTotalPowerMah = null;          final double[] customMeasuredPowerMah = calculateMeasuredEnergiesMah(                  u.getCustomConsumerMeasuredBatteryConsumptionUC());          if (customMeasuredPowerMah != null) { +            if (totalPowerMah == null) { +                newTotalPowerMah = new double[customMeasuredPowerMah.length]; +            } else if (totalPowerMah.length != customMeasuredPowerMah.length) { +                newTotalPowerMah = new double[customMeasuredPowerMah.length]; +                System.arraycopy(totalPowerMah, 0, newTotalPowerMah, 0, +                        customMeasuredPowerMah.length); +            } else { +                newTotalPowerMah = totalPowerMah; +            }              for (int i = 0; i < customMeasuredPowerMah.length; i++) {                  app.setConsumedPowerForCustomComponent(                          BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID + i,                          customMeasuredPowerMah[i]); +                newTotalPowerMah[i] += customMeasuredPowerMah[i];              }          } +        return newTotalPowerMah;      }      @Override diff --git a/core/java/com/android/internal/os/FlashlightPowerCalculator.java b/core/java/com/android/internal/os/FlashlightPowerCalculator.java index cbe0cde2f5b7..32df17c51aac 100644 --- a/core/java/com/android/internal/os/FlashlightPowerCalculator.java +++ b/core/java/com/android/internal/os/FlashlightPowerCalculator.java @@ -17,6 +17,7 @@ package com.android.internal.os;  import android.os.BatteryConsumer;  import android.os.BatteryStats; +import android.os.BatteryUsageStats;  import android.os.BatteryUsageStatsQuery;  import android.os.UidBatteryConsumer; @@ -34,6 +35,24 @@ public class FlashlightPowerCalculator extends PowerCalculator {      }      @Override +    public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats, +            long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) { +        super.calculate(builder, batteryStats, rawRealtimeUs, rawUptimeUs, query); + +        final long durationMs = batteryStats.getFlashlightOnTime(rawRealtimeUs, +                BatteryStats.STATS_SINCE_CHARGED) / 1000; +        final double powerMah = mPowerEstimator.calculatePower(durationMs); +        builder.getAggregateBatteryConsumerBuilder( +                BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE) +                .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT, durationMs) +                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT, powerMah); +        builder.getAggregateBatteryConsumerBuilder( +                BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS) +                .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT, durationMs) +                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT, powerMah); +    } + +    @Override      protected void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u,              long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {          final long durationMs = mPowerEstimator.calculateDuration(u.getFlashlightTurnedOnTimer(), diff --git a/core/java/com/android/internal/os/GnssPowerCalculator.java b/core/java/com/android/internal/os/GnssPowerCalculator.java index 7eb4b4a9bb1c..a508e039fe71 100644 --- a/core/java/com/android/internal/os/GnssPowerCalculator.java +++ b/core/java/com/android/internal/os/GnssPowerCalculator.java @@ -46,6 +46,7 @@ public class GnssPowerCalculator extends PowerCalculator {      @Override      public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,              long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) { +        double appsPowerMah = 0;          final double averageGnssPowerMa = getAverageGnssPower(batteryStats, rawRealtimeUs,                  BatteryStats.STATS_SINCE_CHARGED);          final SparseArray<UidBatteryConsumer.Builder> uidBatteryConsumerBuilders = @@ -55,12 +56,27 @@ public class GnssPowerCalculator extends PowerCalculator {              final long consumptionUC =                      app.getBatteryStatsUid().getGnssMeasuredBatteryConsumptionUC();              final int powerModel = getPowerModel(consumptionUC, query); -            calculateApp(app, app.getBatteryStatsUid(), powerModel, rawRealtimeUs, -                    averageGnssPowerMa, consumptionUC); +            appsPowerMah += calculateApp(app, app.getBatteryStatsUid(), powerModel, +                    rawRealtimeUs, averageGnssPowerMa, consumptionUC);          } + +        final long consumptionUC = batteryStats.getGnssMeasuredBatteryConsumptionUC(); +        final int powerModel = getPowerModel(consumptionUC, query); +        double powerMah; +        if (powerModel == BatteryConsumer.POWER_MODEL_MEASURED_ENERGY) { +            powerMah = uCtoMah(consumptionUC); +        } else { +            powerMah = appsPowerMah; +        } +        builder.getAggregateBatteryConsumerBuilder( +                BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE) +                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_GNSS, powerMah, powerModel); +        builder.getAggregateBatteryConsumerBuilder( +                BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS) +                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_GNSS, appsPowerMah, powerModel);      } -    private void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u, +    private double calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u,              @BatteryConsumer.PowerModel int powerModel, long rawRealtimeUs,              double averageGnssPowerMa, long measuredChargeUC) {          final long durationMs = computeDuration(u, rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED); @@ -76,6 +92,7 @@ public class GnssPowerCalculator extends PowerCalculator {          app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_GNSS, durationMs)                  .setConsumedPower(BatteryConsumer.POWER_COMPONENT_GNSS, powerMah, powerModel); +        return powerMah;      }      @Override diff --git a/core/java/com/android/internal/os/IdlePowerCalculator.java b/core/java/com/android/internal/os/IdlePowerCalculator.java index 0c80deb49259..d33a88deb9d7 100644 --- a/core/java/com/android/internal/os/IdlePowerCalculator.java +++ b/core/java/com/android/internal/os/IdlePowerCalculator.java @@ -20,7 +20,6 @@ import android.os.BatteryConsumer;  import android.os.BatteryStats;  import android.os.BatteryUsageStats;  import android.os.BatteryUsageStatsQuery; -import android.os.SystemBatteryConsumer;  import android.os.UserHandle;  import android.util.Log;  import android.util.SparseArray; @@ -53,7 +52,8 @@ public class IdlePowerCalculator extends PowerCalculator {          calculatePowerAndDuration(batteryStats, rawRealtimeUs, rawUptimeUs,                  BatteryStats.STATS_SINCE_CHARGED);          if (mPowerMah != 0) { -            builder.getOrCreateSystemBatteryConsumerBuilder(SystemBatteryConsumer.DRAIN_TYPE_IDLE) +            builder.getAggregateBatteryConsumerBuilder( +                    BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE)                      .setConsumedPower(BatteryConsumer.POWER_COMPONENT_IDLE, mPowerMah)                      .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_IDLE, mDurationMs);          } diff --git a/core/java/com/android/internal/os/KernelCpuUidTimeReader.java b/core/java/com/android/internal/os/KernelCpuUidTimeReader.java index 64c68ce0c83b..e670178d05ae 100644 --- a/core/java/com/android/internal/os/KernelCpuUidTimeReader.java +++ b/core/java/com/android/internal/os/KernelCpuUidTimeReader.java @@ -482,7 +482,8 @@ public abstract class KernelCpuUidTimeReader<T> {                  // Unit is 10ms.                  mDeltaTimes[i] = mCurTimes[i] - lastTimes[i];                  if (mDeltaTimes[i] < 0) { -                    Slog.e(mTag, "Negative delta from freq time proc: " + mDeltaTimes[i]); +                    Slog.e(mTag, "Negative delta from freq time for uid: " + uid +                            + ", delta: " + mDeltaTimes[i]);                      valid = false;                  }                  notify |= mDeltaTimes[i] > 0; @@ -648,7 +649,8 @@ public abstract class KernelCpuUidTimeReader<T> {                          cb.onUidCpuTime(uid, delta);                      }                  } else if (delta < 0) { -                    Slog.e(mTag, "Negative delta from active time proc: " + delta); +                    Slog.e(mTag, "Negative delta from active time for uid: " + uid +                            + ", delta: " + delta);                  }              }          } @@ -822,7 +824,8 @@ public abstract class KernelCpuUidTimeReader<T> {              for (int i = 0; i < mNumClusters; i++) {                  mDeltaTime[i] = mCurTime[i] - lastTimes[i];                  if (mDeltaTime[i] < 0) { -                    Slog.e(mTag, "Negative delta from cluster time proc: " + mDeltaTime[i]); +                    Slog.e(mTag, "Negative delta from cluster time for uid: " + uid +                            + ", delta: " + mDeltaTime[i]);                      valid = false;                  }                  notify |= mDeltaTime[i] > 0; diff --git a/core/java/com/android/internal/os/MemoryPowerCalculator.java b/core/java/com/android/internal/os/MemoryPowerCalculator.java index 5d5c1558f716..09fd85e42225 100644 --- a/core/java/com/android/internal/os/MemoryPowerCalculator.java +++ b/core/java/com/android/internal/os/MemoryPowerCalculator.java @@ -4,7 +4,6 @@ import android.os.BatteryConsumer;  import android.os.BatteryStats;  import android.os.BatteryUsageStats;  import android.os.BatteryUsageStatsQuery; -import android.os.SystemBatteryConsumer;  import android.os.UserHandle;  import android.util.LongSparseArray;  import android.util.SparseArray; @@ -31,7 +30,8 @@ public class MemoryPowerCalculator extends PowerCalculator {                  BatteryStats.STATS_SINCE_CHARGED);          final double powerMah = calculatePower(batteryStats, rawRealtimeUs,                  BatteryStats.STATS_SINCE_CHARGED); -        builder.getOrCreateSystemBatteryConsumerBuilder(SystemBatteryConsumer.DRAIN_TYPE_MEMORY) +        builder.getAggregateBatteryConsumerBuilder( +                BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE)                  .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_MEMORY, durationMs)                  .setConsumedPower(BatteryConsumer.POWER_COMPONENT_MEMORY, powerMah);      } diff --git a/core/java/com/android/internal/os/MobileRadioPowerCalculator.java b/core/java/com/android/internal/os/MobileRadioPowerCalculator.java index 4db15a44231e..eb5993dc2d61 100644 --- a/core/java/com/android/internal/os/MobileRadioPowerCalculator.java +++ b/core/java/com/android/internal/os/MobileRadioPowerCalculator.java @@ -19,7 +19,6 @@ import android.os.BatteryConsumer;  import android.os.BatteryStats;  import android.os.BatteryUsageStats;  import android.os.BatteryUsageStatsQuery; -import android.os.SystemBatteryConsumer;  import android.os.UidBatteryConsumer;  import android.os.UserHandle;  import android.telephony.CellSignalStrength; @@ -105,14 +104,19 @@ public class MobileRadioPowerCalculator extends PowerCalculator {          calculateRemaining(total, powerModel, batteryStats, rawRealtimeUs, consumptionUC);          if (total.remainingPowerMah != 0 || total.totalAppPowerMah != 0) { -            builder.getOrCreateSystemBatteryConsumerBuilder( -                        SystemBatteryConsumer.DRAIN_TYPE_MOBILE_RADIO) +            builder.getAggregateBatteryConsumerBuilder( +                    BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE)                      .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO,                              total.durationMs)                      .setConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO, -                            total.remainingPowerMah + total.totalAppPowerMah, -                            powerModel) -                    .setPowerConsumedByApps(total.totalAppPowerMah); +                            total.remainingPowerMah + total.totalAppPowerMah, powerModel); + +            builder.getAggregateBatteryConsumerBuilder( +                    BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS) +                    .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO, +                            total.durationMs) +                    .setConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO, +                            total.totalAppPowerMah, powerModel);          }      } diff --git a/core/java/com/android/internal/os/PhonePowerCalculator.java b/core/java/com/android/internal/os/PhonePowerCalculator.java index 2e3bff32cc38..8dd463c0d5e1 100644 --- a/core/java/com/android/internal/os/PhonePowerCalculator.java +++ b/core/java/com/android/internal/os/PhonePowerCalculator.java @@ -20,7 +20,6 @@ import android.os.BatteryConsumer;  import android.os.BatteryStats;  import android.os.BatteryUsageStats;  import android.os.BatteryUsageStatsQuery; -import android.os.SystemBatteryConsumer;  import android.os.UserHandle;  import android.util.SparseArray; @@ -44,7 +43,8 @@ public class PhonePowerCalculator extends PowerCalculator {                  BatteryStats.STATS_SINCE_CHARGED) / 1000;          final double phoneOnPower = mPowerEstimator.calculatePower(phoneOnTimeMs);          if (phoneOnPower != 0) { -            builder.getOrCreateSystemBatteryConsumerBuilder(SystemBatteryConsumer.DRAIN_TYPE_PHONE) +            builder.getAggregateBatteryConsumerBuilder( +                    BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE)                      .setConsumedPower(BatteryConsumer.POWER_COMPONENT_PHONE, phoneOnPower)                      .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_PHONE, phoneOnTimeMs);          } diff --git a/core/java/com/android/internal/os/ScreenPowerCalculator.java b/core/java/com/android/internal/os/ScreenPowerCalculator.java index dc0f719c042b..1b3bc234fc0f 100644 --- a/core/java/com/android/internal/os/ScreenPowerCalculator.java +++ b/core/java/com/android/internal/os/ScreenPowerCalculator.java @@ -20,7 +20,6 @@ import android.os.BatteryConsumer;  import android.os.BatteryStats;  import android.os.BatteryUsageStats;  import android.os.BatteryUsageStatsQuery; -import android.os.SystemBatteryConsumer;  import android.os.UidBatteryConsumer;  import android.os.UserHandle;  import android.text.format.DateUtils; @@ -68,6 +67,7 @@ public class ScreenPowerCalculator extends PowerCalculator {                  rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED, consumptionUC);          double totalAppPower = 0; +        long totalAppDuration = 0;          // Now deal with each app's UidBatteryConsumer. The results are stored in the          // BatteryConsumer.POWER_COMPONENT_SCREEN power component, which is considered smeared, @@ -86,6 +86,7 @@ public class ScreenPowerCalculator extends PowerCalculator {                              .setConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN,                                      appPowerAndDuration.powerMah, powerModel);                      totalAppPower += appPowerAndDuration.powerMah; +                    totalAppDuration += appPowerAndDuration.durationMs;                  }                  break;              case BatteryConsumer.POWER_MODEL_POWER_PROFILE: @@ -93,14 +94,20 @@ public class ScreenPowerCalculator extends PowerCalculator {                  smearScreenBatteryDrain(uidBatteryConsumerBuilders, totalPowerAndDuration,                          rawRealtimeUs);                  totalAppPower = totalPowerAndDuration.powerMah; +                totalAppDuration = totalPowerAndDuration.durationMs;          } -        builder.getOrCreateSystemBatteryConsumerBuilder(SystemBatteryConsumer.DRAIN_TYPE_SCREEN) -                .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN, -                        totalPowerAndDuration.durationMs) +        builder.getAggregateBatteryConsumerBuilder( +                BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE)                  .setConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN,                          Math.max(totalPowerAndDuration.powerMah, totalAppPower), powerModel) -                .setPowerConsumedByApps(totalAppPower); +                .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN, +                        totalPowerAndDuration.durationMs); + +        builder.getAggregateBatteryConsumerBuilder( +                BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS) +                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN, totalAppPower, powerModel) +                .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN, totalAppDuration);      }      /** diff --git a/core/java/com/android/internal/os/SensorPowerCalculator.java b/core/java/com/android/internal/os/SensorPowerCalculator.java index d18b7b1f69c2..83e5b5702b6c 100644 --- a/core/java/com/android/internal/os/SensorPowerCalculator.java +++ b/core/java/com/android/internal/os/SensorPowerCalculator.java @@ -19,6 +19,7 @@ import android.hardware.Sensor;  import android.hardware.SensorManager;  import android.os.BatteryConsumer;  import android.os.BatteryStats; +import android.os.BatteryUsageStats;  import android.os.BatteryUsageStatsQuery;  import android.os.UidBatteryConsumer;  import android.util.SparseArray; @@ -38,12 +39,32 @@ public class SensorPowerCalculator extends PowerCalculator {      }      @Override -    protected void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u, +    public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,              long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) { +        double appsPowerMah = 0; +        final SparseArray<UidBatteryConsumer.Builder> uidBatteryConsumerBuilders = +                builder.getUidBatteryConsumerBuilders(); +        for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) { +            final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i); +            appsPowerMah += calculateApp(app, app.getBatteryStatsUid(), rawRealtimeUs); +        } + +        builder.getAggregateBatteryConsumerBuilder( +                BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE) +                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_SENSORS, appsPowerMah); +        builder.getAggregateBatteryConsumerBuilder( +                BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS) +                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_SENSORS, appsPowerMah); +    } + +    private double calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u, +            long rawRealtimeUs) { +        final double powerMah = calculatePowerMah(u, rawRealtimeUs, +                BatteryStats.STATS_SINCE_CHARGED);          app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SENSORS,                          calculateDuration(u, rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED)) -                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_SENSORS, -                        calculatePowerMah(u, rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED)); +                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_SENSORS, powerMah); +        return powerMah;      }      @Override diff --git a/core/java/com/android/internal/os/SystemServicePowerCalculator.java b/core/java/com/android/internal/os/SystemServicePowerCalculator.java index b4d5f97a14e7..a26abc2ffab0 100644 --- a/core/java/com/android/internal/os/SystemServicePowerCalculator.java +++ b/core/java/com/android/internal/os/SystemServicePowerCalculator.java @@ -87,6 +87,15 @@ public class SystemServicePowerCalculator extends PowerCalculator {                          systemServicePowerMah * uid.getProportionalSystemServiceUsage());              }          } + +        builder.getAggregateBatteryConsumerBuilder( +                BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE) +                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_SYSTEM_SERVICES, +                        systemServicePowerMah); +        builder.getAggregateBatteryConsumerBuilder( +                BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS) +                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_SYSTEM_SERVICES, +                        systemServicePowerMah);      }      @Override diff --git a/core/java/com/android/internal/os/VideoPowerCalculator.java b/core/java/com/android/internal/os/VideoPowerCalculator.java index 0cad9a72ceec..47916a6b0914 100644 --- a/core/java/com/android/internal/os/VideoPowerCalculator.java +++ b/core/java/com/android/internal/os/VideoPowerCalculator.java @@ -17,8 +17,10 @@ package com.android.internal.os;  import android.os.BatteryConsumer;  import android.os.BatteryStats; +import android.os.BatteryUsageStats;  import android.os.BatteryUsageStatsQuery;  import android.os.UidBatteryConsumer; +import android.util.SparseArray;  /**   * A {@link PowerCalculator} to calculate power consumed by video hardware. @@ -28,18 +30,47 @@ import android.os.UidBatteryConsumer;  public class VideoPowerCalculator extends PowerCalculator {      private final UsageBasedPowerEstimator mPowerEstimator; +    private static class PowerAndDuration { +        public long durationMs; +        public double powerMah; +    } +      public VideoPowerCalculator(PowerProfile powerProfile) {          mPowerEstimator = new UsageBasedPowerEstimator(                  powerProfile.getAveragePower(PowerProfile.POWER_VIDEO));      }      @Override -    protected void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u, +    public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,              long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) { +        final PowerAndDuration total = new PowerAndDuration(); + +        final SparseArray<UidBatteryConsumer.Builder> uidBatteryConsumerBuilders = +                builder.getUidBatteryConsumerBuilders(); +        for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) { +            final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i); +            calculateApp(app, total, app.getBatteryStatsUid(), rawRealtimeUs); +        } + +        builder.getAggregateBatteryConsumerBuilder( +                BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE) +                .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_VIDEO, total.durationMs) +                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_VIDEO, total.powerMah); + +        builder.getAggregateBatteryConsumerBuilder( +                BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS) +                .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_VIDEO, total.durationMs) +                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_VIDEO, total.powerMah); +    } + +    private void calculateApp(UidBatteryConsumer.Builder app, PowerAndDuration total, +            BatteryStats.Uid u, long rawRealtimeUs) {          final long durationMs = mPowerEstimator.calculateDuration(u.getVideoTurnedOnTimer(),                  rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED);          final double powerMah = mPowerEstimator.calculatePower(durationMs);          app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_VIDEO, durationMs)                  .setConsumedPower(BatteryConsumer.POWER_COMPONENT_VIDEO, powerMah); +        total.durationMs += durationMs; +        total.powerMah += powerMah;      }  } diff --git a/core/java/com/android/internal/os/WakelockPowerCalculator.java b/core/java/com/android/internal/os/WakelockPowerCalculator.java index 194b6b82cd53..d5941072acf9 100644 --- a/core/java/com/android/internal/os/WakelockPowerCalculator.java +++ b/core/java/com/android/internal/os/WakelockPowerCalculator.java @@ -51,6 +51,7 @@ public class WakelockPowerCalculator extends PowerCalculator {          double osPowerMah = 0;          long osDurationMs = 0;          long totalAppDurationMs = 0; +        double appPowerMah = 0;          final SparseArray<UidBatteryConsumer.Builder> uidBatteryConsumerBuilders =                  builder.getUidBatteryConsumerBuilders();          for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) { @@ -60,6 +61,7 @@ public class WakelockPowerCalculator extends PowerCalculator {              app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WAKELOCK, result.durationMs)                      .setConsumedPower(BatteryConsumer.POWER_COMPONENT_WAKELOCK, result.powerMah);              totalAppDurationMs += result.durationMs; +            appPowerMah += result.powerMah;              if (app.getUid() == Process.ROOT_UID) {                  osBatteryConsumer = app; @@ -71,13 +73,24 @@ public class WakelockPowerCalculator extends PowerCalculator {          // The device has probably been awake for longer than the screen on          // time and application wake lock time would account for.  Assign          // this remainder to the OS, if possible. +        calculateRemaining(result, batteryStats, rawRealtimeUs, rawUptimeUs, +                BatteryStats.STATS_SINCE_CHARGED, osPowerMah, osDurationMs, totalAppDurationMs);          if (osBatteryConsumer != null) { -            calculateRemaining(result, batteryStats, rawRealtimeUs, rawUptimeUs, -                    BatteryStats.STATS_SINCE_CHARGED, osPowerMah, osDurationMs, totalAppDurationMs);              osBatteryConsumer.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WAKELOCK,                      result.durationMs)                      .setConsumedPower(BatteryConsumer.POWER_COMPONENT_WAKELOCK, result.powerMah);          } + +        final long wakeTimeMillis = +                calculateWakeTimeMillis(batteryStats, rawRealtimeUs, rawUptimeUs); +        final double powerMah = mPowerEstimator.calculatePower(wakeTimeMillis); +        builder.getAggregateBatteryConsumerBuilder( +                BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE) +                .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WAKELOCK, wakeTimeMillis) +                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_WAKELOCK, powerMah); +        builder.getAggregateBatteryConsumerBuilder( +                BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS) +                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_WAKELOCK, appPowerMah);      }      @Override @@ -145,8 +158,7 @@ public class WakelockPowerCalculator extends PowerCalculator {      private void calculateRemaining(PowerAndDuration result, BatteryStats stats, long rawRealtimeUs,              long rawUptimeUs, int statsType, double osPowerMah, long osDurationMs,              long totalAppDurationMs) { -        final long wakeTimeMillis = stats.getBatteryUptime(rawUptimeUs) / 1000 -                - stats.getScreenOnTime(rawRealtimeUs, statsType) / 1000 +        final long wakeTimeMillis = calculateWakeTimeMillis(stats, rawRealtimeUs, rawUptimeUs)                  - totalAppDurationMs;          if (wakeTimeMillis > 0) {              final double power = mPowerEstimator.calculatePower(wakeTimeMillis); @@ -157,4 +169,12 @@ public class WakelockPowerCalculator extends PowerCalculator {              result.powerMah = osPowerMah + power;          }      } + +    private long calculateWakeTimeMillis(BatteryStats batteryStats, long rawRealtimeUs, +            long rawUptimeUs) { +        final long batteryUptimeUs = batteryStats.getBatteryUptime(rawUptimeUs); +        final long screenOnTimeUs = +                batteryStats.getScreenOnTime(rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED); +        return (batteryUptimeUs - screenOnTimeUs) / 1000; +    }  } diff --git a/core/java/com/android/internal/os/WifiPowerCalculator.java b/core/java/com/android/internal/os/WifiPowerCalculator.java index ef5b147e00e4..776a70545df4 100644 --- a/core/java/com/android/internal/os/WifiPowerCalculator.java +++ b/core/java/com/android/internal/os/WifiPowerCalculator.java @@ -20,7 +20,6 @@ import android.os.BatteryStats;  import android.os.BatteryUsageStats;  import android.os.BatteryUsageStatsQuery;  import android.os.Process; -import android.os.SystemBatteryConsumer;  import android.os.UidBatteryConsumer;  import android.os.UserHandle;  import android.util.Log; @@ -79,10 +78,6 @@ public class WifiPowerCalculator extends PowerCalculator {      public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,              long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) { -        final SystemBatteryConsumer.Builder systemBatteryConsumerBuilder = -                builder.getOrCreateSystemBatteryConsumerBuilder( -                        SystemBatteryConsumer.DRAIN_TYPE_WIFI); -          long totalAppDurationMs = 0;          double totalAppPowerMah = 0;          final PowerDurationAndTraffic powerDurationAndTraffic = new PowerDurationAndTraffic(); @@ -104,11 +99,6 @@ public class WifiPowerCalculator extends PowerCalculator {                      powerDurationAndTraffic.durationMs);              app.setConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI,                      powerDurationAndTraffic.powerMah, powerModel); - -            if (app.getUid() == Process.WIFI_UID) { -                systemBatteryConsumerBuilder.addUidBatteryConsumer(app); -                app.excludeFromBatteryUsageStats(); -            }          }          final long consumptionUC = batteryStats.getWifiMeasuredBatteryConsumptionUC(); @@ -117,12 +107,16 @@ public class WifiPowerCalculator extends PowerCalculator {                  BatteryStats.STATS_SINCE_CHARGED, batteryStats.hasWifiActivityReporting(),                  totalAppDurationMs, totalAppPowerMah, consumptionUC); -        systemBatteryConsumerBuilder +        builder.getAggregateBatteryConsumerBuilder( +                BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE)                  .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WIFI,                          powerDurationAndTraffic.durationMs)                  .setConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI, -                        totalAppPowerMah + powerDurationAndTraffic.powerMah, powerModel) -                .setPowerConsumedByApps(totalAppPowerMah); +                        totalAppPowerMah + powerDurationAndTraffic.powerMah, powerModel); +        builder.getAggregateBatteryConsumerBuilder( +                BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS) +                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI, +                        totalAppPowerMah, powerModel);      }      /** diff --git a/core/java/com/android/internal/view/IDragAndDropPermissions.aidl b/core/java/com/android/internal/view/IDragAndDropPermissions.aidl index edb759a8f824..4834d22c73bf 100644 --- a/core/java/com/android/internal/view/IDragAndDropPermissions.aidl +++ b/core/java/com/android/internal/view/IDragAndDropPermissions.aidl @@ -24,6 +24,6 @@ import android.os.IBinder;   */  interface IDragAndDropPermissions {      void take(IBinder activityToken); -    void takeTransient(IBinder transientToken); +    void takeTransient();      void release();  } diff --git a/core/java/com/android/internal/widget/RecyclerView.java b/core/java/com/android/internal/widget/RecyclerView.java index 9ed5eb1d144e..be15a9bba107 100644 --- a/core/java/com/android/internal/widget/RecyclerView.java +++ b/core/java/com/android/internal/widget/RecyclerView.java @@ -16,16 +16,10 @@  package com.android.internal.widget; -import static android.widget.EdgeEffect.TYPE_GLOW; -import static android.widget.EdgeEffect.TYPE_STRETCH; -import static android.widget.EdgeEffect.USE_STRETCH_EDGE_EFFECT_BY_DEFAULT; -import static android.widget.EdgeEffect.USE_STRETCH_EDGE_EFFECT_FOR_SUPPORTED; -  import android.annotation.CallSuper;  import android.annotation.IntDef;  import android.annotation.NonNull;  import android.annotation.Nullable; -import android.compat.Compatibility;  import android.compat.annotation.UnsupportedAppUsage;  import android.content.Context;  import android.content.res.TypedArray; @@ -466,8 +460,6 @@ public class RecyclerView extends ViewGroup implements ScrollingView, NestedScro      private final int[] mScrollConsumed = new int[2];      private final int[] mNestedOffsets = new int[2]; -    private int mEdgeEffectType; -      /**       * These are views that had their a11y importance changed during a layout. We defer these events       * until the end of the layout because a11y service may make sync calls back to the RV while @@ -595,12 +587,8 @@ public class RecyclerView extends ViewGroup implements ScrollingView, NestedScro              setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);          } -        boolean defaultToStretch = Compatibility.isChangeEnabled(USE_STRETCH_EDGE_EFFECT_BY_DEFAULT) -                || Compatibility.isChangeEnabled(USE_STRETCH_EDGE_EFFECT_FOR_SUPPORTED);          TypedArray a = context.obtainStyledAttributes(attrs,                  com.android.internal.R.styleable.EdgeEffect); -        mEdgeEffectType = a.getInt(com.android.internal.R.styleable.EdgeEffect_edgeEffectType, -                defaultToStretch ? TYPE_STRETCH : TYPE_GLOW);          a.recycle();          // Re-set whether nested scrolling is enabled so that it is set on all API levels @@ -626,28 +614,6 @@ public class RecyclerView extends ViewGroup implements ScrollingView, NestedScro      }      /** -     * Returns the {@link EdgeEffect#getType()} used for all EdgeEffects. -     * -     * @return @link EdgeEffect#getType()} used for all EdgeEffects. -     */ -    @EdgeEffect.EdgeEffectType -    public int getEdgeEffectType() { -        return mEdgeEffectType; -    } - -    /** -     * Sets the {@link EdgeEffect#getType()} used in all EdgeEffects. -     * Any existing over-scroll effects are cleared and new effects are created as needed. -     * -     * @param type the {@link EdgeEffect#getType()} used in all EdgeEffects. -     */ -    public void setEdgeEffectType(@EdgeEffect.EdgeEffectType int type) { -        mEdgeEffectType = type; -        invalidateGlows(); -        invalidate(); -    } - -    /**       * Instantiate and set a LayoutManager, if specified in the attributes.       */      private void createLayoutManager(Context context, String className, AttributeSet attrs, @@ -2223,7 +2189,6 @@ public class RecyclerView extends ViewGroup implements ScrollingView, NestedScro              return;          }          mLeftGlow = new EdgeEffect(getContext()); -        mLeftGlow.setType(mEdgeEffectType);          if (mClipToPadding) {              mLeftGlow.setSize(getMeasuredHeight() - getPaddingTop() - getPaddingBottom(),                      getMeasuredWidth() - getPaddingLeft() - getPaddingRight()); @@ -2237,7 +2202,6 @@ public class RecyclerView extends ViewGroup implements ScrollingView, NestedScro              return;          }          mRightGlow = new EdgeEffect(getContext()); -        mRightGlow.setType(mEdgeEffectType);          if (mClipToPadding) {              mRightGlow.setSize(getMeasuredHeight() - getPaddingTop() - getPaddingBottom(),                      getMeasuredWidth() - getPaddingLeft() - getPaddingRight()); @@ -2251,7 +2215,6 @@ public class RecyclerView extends ViewGroup implements ScrollingView, NestedScro              return;          }          mTopGlow = new EdgeEffect(getContext()); -        mTopGlow.setType(mEdgeEffectType);          if (mClipToPadding) {              mTopGlow.setSize(getMeasuredWidth() - getPaddingLeft() - getPaddingRight(),                      getMeasuredHeight() - getPaddingTop() - getPaddingBottom()); @@ -2266,7 +2229,6 @@ public class RecyclerView extends ViewGroup implements ScrollingView, NestedScro              return;          }          mBottomGlow = new EdgeEffect(getContext()); -        mBottomGlow.setType(mEdgeEffectType);          if (mClipToPadding) {              mBottomGlow.setSize(getMeasuredWidth() - getPaddingLeft() - getPaddingRight(),                      getMeasuredHeight() - getPaddingTop() - getPaddingBottom()); diff --git a/core/java/com/android/internal/widget/ViewPager.java b/core/java/com/android/internal/widget/ViewPager.java index 93cde3ddb72d..1174db5b2cf7 100644 --- a/core/java/com/android/internal/widget/ViewPager.java +++ b/core/java/com/android/internal/widget/ViewPager.java @@ -387,28 +387,6 @@ public class ViewPager extends ViewGroup {      }      /** -     * Returns the {@link EdgeEffect#getType()} for the edge effects. -     * @return the {@link EdgeEffect#getType()} for the edge effects. -     * @attr ref android.R.styleable#EdgeEffect_edgeEffectType -     */ -    @EdgeEffect.EdgeEffectType -    public int getEdgeEffectType() { -        // Both left and right edge have the same edge effect type -        return mLeftEdge.getType(); -    } - -    /** -     * Sets the {@link EdgeEffect#setType(int)} for the edge effects. -     * @param type The edge effect type to use for the edge effects. -     * @attr ref android.R.styleable#EdgeEffect_edgeEffectType -     */ -    public void setEdgeEffectType(@EdgeEffect.EdgeEffectType int type) { -        mLeftEdge.setType(type); -        mRightEdge.setType(type); -        invalidate(); -    } - -    /**       * Set a PagerAdapter that will supply views for this pager as needed.       *       * @param adapter Adapter to use diff --git a/core/jni/android_media_AudioAttributes.cpp b/core/jni/android_media_AudioAttributes.cpp index b616ffc111a3..f1ae268f4c16 100644 --- a/core/jni/android_media_AudioAttributes.cpp +++ b/core/jni/android_media_AudioAttributes.cpp @@ -171,10 +171,6 @@ jint JNIAudioAttributeHelper::getJavaArray(  /*   * JNI registration.   */ -static const JNINativeMethod gMethods[] = { -    // n/a -}; -  int register_android_media_AudioAttributes(JNIEnv *env)  {      jclass audioAttributesClass = FindClassOrDie(env, kClassPathName); @@ -218,5 +214,5 @@ int register_android_media_AudioAttributes(JNIEnv *env)      env->DeleteLocalRef(audioAttributesClass); -    return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods)); +    return 0;  } diff --git a/core/jni/android_os_VintfObject.cpp b/core/jni/android_os_VintfObject.cpp index 4bd33a9cbd3b..1baea2aecc3c 100644 --- a/core/jni/android_os_VintfObject.cpp +++ b/core/jni/android_os_VintfObject.cpp @@ -37,11 +37,13 @@ static jmethodID gLongValueOf;  namespace android { +using vintf::CompatibilityMatrix;  using vintf::HalManifest;  using vintf::Level;  using vintf::SchemaType;  using vintf::to_string;  using vintf::toXml; +using vintf::Version;  using vintf::VintfObject;  using vintf::Vndk; @@ -119,6 +121,28 @@ static jstring android_os_VintfObject_getSepolicyVersion(JNIEnv* env, jclass) {      return env->NewStringUTF(cString.c_str());  } +static jstring android_os_VintfObject_getPlatformSepolicyVersion(JNIEnv* env, jclass) { +    std::shared_ptr<const CompatibilityMatrix> matrix = +            VintfObject::GetFrameworkCompatibilityMatrix(); +    if (matrix == nullptr || matrix->type() != SchemaType::FRAMEWORK) { +        jniThrowRuntimeException(env, "Cannot get framework compatibility matrix"); +        return nullptr; +    } + +    auto versions = matrix->getSepolicyVersions(); +    if (versions.empty()) { +        jniThrowRuntimeException(env, +                                 "sepolicy_version in framework compatibility matrix is empty"); +        return nullptr; +    } + +    Version latest; +    for (const auto& range : versions) { +        latest = std::max(latest, range.maxVer()); +    } +    return env->NewStringUTF(to_string(latest).c_str()); +} +  static jobject android_os_VintfObject_getVndkSnapshots(JNIEnv* env, jclass) {      std::shared_ptr<const HalManifest> manifest = VintfObject::GetFrameworkHalManifest();      if (manifest == nullptr || manifest->type() != SchemaType::FRAMEWORK) { @@ -145,12 +169,17 @@ static jobject android_os_VintfObject_getTargetFrameworkCompatibilityMatrixVersi  // ----------------------------------------------------------------------------  static const JNINativeMethod gVintfObjectMethods[] = { -    {"report", "()[Ljava/lang/String;", (void*)android_os_VintfObject_report}, -    {"verifyWithoutAvb", "()I", (void*)android_os_VintfObject_verifyWithoutAvb}, -    {"getHalNamesAndVersions", "()[Ljava/lang/String;", (void*)android_os_VintfObject_getHalNamesAndVersions}, -    {"getSepolicyVersion", "()Ljava/lang/String;", (void*)android_os_VintfObject_getSepolicyVersion}, -    {"getVndkSnapshots", "()Ljava/util/Map;", (void*)android_os_VintfObject_getVndkSnapshots}, -    {"getTargetFrameworkCompatibilityMatrixVersion", "()Ljava/lang/Long;", (void*)android_os_VintfObject_getTargetFrameworkCompatibilityMatrixVersion}, +        {"report", "()[Ljava/lang/String;", (void*)android_os_VintfObject_report}, +        {"verifyWithoutAvb", "()I", (void*)android_os_VintfObject_verifyWithoutAvb}, +        {"getHalNamesAndVersions", "()[Ljava/lang/String;", +         (void*)android_os_VintfObject_getHalNamesAndVersions}, +        {"getSepolicyVersion", "()Ljava/lang/String;", +         (void*)android_os_VintfObject_getSepolicyVersion}, +        {"getPlatformSepolicyVersion", "()Ljava/lang/String;", +         (void*)android_os_VintfObject_getPlatformSepolicyVersion}, +        {"getVndkSnapshots", "()Ljava/util/Map;", (void*)android_os_VintfObject_getVndkSnapshots}, +        {"getTargetFrameworkCompatibilityMatrixVersion", "()Ljava/lang/Long;", +         (void*)android_os_VintfObject_getTargetFrameworkCompatibilityMatrixVersion},  };  const char* const kVintfObjectPathName = "android/os/VintfObject"; diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index 27f82f1b52dd..d528428a0e83 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -626,12 +626,24 @@ static void nativeSetBlurRegions(JNIEnv* env, jclass clazz, jlong transactionObj  }  static void nativeSetStretchEffect(JNIEnv* env, jclass clazz, jlong transactionObj, -                                   jlong nativeObject, jfloat left, jfloat top, jfloat right, -                                   jfloat bottom, jfloat vecX, jfloat vecY, -                                   jfloat maxStretchAmount) { +                                   jlong nativeObject, jfloat width, jfloat height, +                                   jfloat vecX, jfloat vecY, +                                   jfloat maxStretchAmountX, jfloat maxStretchAmountY, +                                   jfloat childRelativeLeft, jfloat childRelativeTop, +                                   jfloat childRelativeRight, jfloat childRelativeBottom) {      auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj); -    SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl*>(nativeObject); -    transaction->setStretchEffect(ctrl, left, top, right, bottom, vecX, vecY, maxStretchAmount); +    auto* const ctrl = reinterpret_cast<SurfaceControl*>(nativeObject); +    auto stretch = StretchEffect{ +      .width = width, +      .height = height, +      .vectorX = vecX, +      .vectorY = vecY, +      .maxAmountX = maxStretchAmountX, +      .maxAmountY = maxStretchAmountY, +      .mappedChildBounds = FloatRect( +          childRelativeLeft, childRelativeTop, childRelativeRight, childRelativeBottom) +    }; +    transaction->setStretchEffect(ctrl, stretch);  }  static void nativeSetSize(JNIEnv* env, jclass clazz, jlong transactionObj, @@ -1829,7 +1841,7 @@ static const JNINativeMethod sSurfaceControlMethods[] = {              (void*)nativeSetLayerStack },      {"nativeSetBlurRegions", "(JJ[[FI)V",              (void*)nativeSetBlurRegions }, -    {"nativeSetStretchEffect", "(JJFFFFFFF)V", +    {"nativeSetStretchEffect", "(JJFFFFFFFFFF)V",              (void*) nativeSetStretchEffect },      {"nativeSetShadowRadius", "(JJF)V",              (void*)nativeSetShadowRadius }, diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 4dc4bef10475..4b828ba4cb02 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -3947,11 +3947,11 @@      <!-- This permission is required among systems services when accessing           tuner resource management related APIs or information. -         <p>Protection level: signature|privileged -         <p>Not for use by third-party applications. +         <p>Protection level: signature|privileged|vendorPrivileged +         <p>This should only be used by the OEM TvInputService.           @hide -->      <permission android:name="android.permission.TUNER_RESOURCE_ACCESS" -         android:protectionLevel="signature|privileged" /> +         android:protectionLevel="signature|privileged|vendorPrivileged" />      <!-- This permission is required by Media Resource Manager Service when           accessing its overridePid Api. diff --git a/core/res/remote_color_resources_res/values/colors.xml b/core/res/remote_color_resources_res/values/colors.xml index e4bcae43a0e5..aff3a9592645 100644 --- a/core/res/remote_color_resources_res/values/colors.xml +++ b/core/res/remote_color_resources_res/values/colors.xml @@ -2,6 +2,7 @@  <resources>    <!-- Note: the values of the colors doesn't really matter (they will always be overwritten before used), but they help a lot debugging, to find out which color is where in the ARSC file. -->    <color name="system_accent1_0">#ffffff</color> +  <color name="system_accent1_10">#91fff4</color>    <color name="system_accent1_50">#91fff4</color>    <color name="system_accent1_100">#83f6e5</color>    <color name="system_accent1_200">#65d9c9</color> @@ -14,6 +15,7 @@    <color name="system_accent1_900">#00271e</color>    <color name="system_accent1_1000">#000000</color>    <color name="system_accent2_0">#ffffff</color> +  <color name="system_accent2_10">#ffffff</color>    <color name="system_accent2_50">#91fff4</color>    <color name="system_accent2_100">#83f6e5</color>    <color name="system_accent2_200">#65d9c9</color> @@ -26,6 +28,7 @@    <color name="system_accent2_900">#00271e</color>    <color name="system_accent2_1000">#000000</color>    <color name="system_accent3_0">#ffffff</color> +  <color name="system_accent3_10">#91fff4</color>    <color name="system_accent3_50">#91fff4</color>    <color name="system_accent3_100">#83f6e5</color>    <color name="system_accent3_200">#65d9c9</color> @@ -38,6 +41,7 @@    <color name="system_accent3_900">#00271e</color>    <color name="system_accent3_1000">#000000</color>    <color name="system_neutral1_0">#ffffff</color> +  <color name="system_neutral1_10">#f0f0f0</color>    <color name="system_neutral1_50">#f0f0f0</color>    <color name="system_neutral1_100">#e2e2e2</color>    <color name="system_neutral1_200">#c6c6c6</color> @@ -50,6 +54,7 @@    <color name="system_neutral1_900">#1b1b1b</color>    <color name="system_neutral1_1000">#000000</color>    <color name="system_neutral2_0">#ffffff</color> +  <color name="system_neutral2_10">#f0f0f0</color>    <color name="system_neutral2_50">#f0f0f0</color>    <color name="system_neutral2_100">#e2e2e2</color>    <color name="system_neutral2_200">#c6c6c6</color> diff --git a/core/res/remote_color_resources_res/values/public.xml b/core/res/remote_color_resources_res/values/public.xml index 9616628ac693..4b0a89202ad1 100644 --- a/core/res/remote_color_resources_res/values/public.xml +++ b/core/res/remote_color_resources_res/values/public.xml @@ -2,6 +2,7 @@  <resources>    <public-group type="color" first-id="0x0106001d">      <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" /> @@ -14,6 +15,7 @@      <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" /> @@ -26,6 +28,7 @@      <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" /> @@ -38,6 +41,7 @@      <public name="system_accent3_900" />      <public name="system_accent3_1000" />      <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" /> @@ -50,6 +54,7 @@      <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" /> diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml index 182fddce11b0..ff07d9b7ad7b 100644 --- a/core/res/res/values-as/strings.xml +++ b/core/res/res/values-as/strings.xml @@ -2287,8 +2287,6 @@      <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"এপ্লিকেশ্বনৰ ব্ৰেণ্ডৰ প্ৰতিচ্ছবি"</string>      <string name="view_and_control_notification_title" msgid="4300765399209912240">"এক্সেছৰ ছেটিং পৰীক্ষা কৰক"</string>      <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g>এ আপোনাৰ স্ক্ৰীনখন চাব আৰু পৰিচালনা কৰিব পাৰে। পৰ্যালোচনা কৰিবলৈ টিপক।"</string> -    <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> -    <skip /> -    <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> -    <skip /> +    <string name="ui_translation_accessibility_translated_text" msgid="3197547218178944544">"<xliff:g id="MESSAGE">%1$s</xliff:g> অনুবাদ কৰা হ’ল।"</string> +    <string name="ui_translation_accessibility_translation_finished" msgid="3057830947610088465">"বাৰ্তাটো <xliff:g id="FROM_LANGUAGE">%1$s</xliff:g>ৰ পৰা <xliff:g id="TO_LANGUAGE">%2$s</xliff:g>লৈ অনুবাদ কৰা হ’ল।"</string>  </resources> diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml index a265821e5b09..a065f19e0b44 100644 --- a/core/res/res/values-bn/strings.xml +++ b/core/res/res/values-bn/strings.xml @@ -2287,8 +2287,6 @@      <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"অ্যাপের ব্র্যান্ড ছবি"</string>      <string name="view_and_control_notification_title" msgid="4300765399209912240">"অ্যাক্সেস করার সেটিংস চেক করুন"</string>      <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> আপনার স্ক্রিন দেখতে ও কন্ট্রোল করতে পারবে। পর্যালোচনা করতে ট্যাপ করুন।"</string> -    <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> -    <skip /> -    <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> -    <skip /> +    <string name="ui_translation_accessibility_translated_text" msgid="3197547218178944544">"<xliff:g id="MESSAGE">%1$s</xliff:g> অনুবাদ করা হয়েছে।"</string> +    <string name="ui_translation_accessibility_translation_finished" msgid="3057830947610088465">"মেসেজ <xliff:g id="FROM_LANGUAGE">%1$s</xliff:g> থেকে <xliff:g id="TO_LANGUAGE">%2$s</xliff:g> ভাষাতে অনুবাদ করা হয়েছে।"</string>  </resources> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index 6a33a0a52f53..d277a80fe440 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -2287,8 +2287,6 @@      <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"App-Branding-Hintergrundbild"</string>      <string name="view_and_control_notification_title" msgid="4300765399209912240">"Zugriffseinstellungen prüfen"</string>      <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> kann deinen Bildschirm sehen und steuern. Zum Prüfen tippen."</string> -    <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> -    <skip /> -    <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> -    <skip /> +    <string name="ui_translation_accessibility_translated_text" msgid="3197547218178944544">"„<xliff:g id="MESSAGE">%1$s</xliff:g>“ wurde übersetzt."</string> +    <string name="ui_translation_accessibility_translation_finished" msgid="3057830947610088465">"Nachricht wurde von <xliff:g id="FROM_LANGUAGE">%1$s</xliff:g> auf <xliff:g id="TO_LANGUAGE">%2$s</xliff:g> übersetzt."</string>  </resources> diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml index 17cff18dcd23..b7ecc0eb4676 100644 --- a/core/res/res/values-gu/strings.xml +++ b/core/res/res/values-gu/strings.xml @@ -2287,8 +2287,6 @@      <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"ઍપ્લિકેશનની બ્રાંડિંગ છબી"</string>      <string name="view_and_control_notification_title" msgid="4300765399209912240">"ઍક્સેસના સેટિંગ ચેક કરો"</string>      <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> તમારી સ્ક્રીન જોઈ અને નિયંત્રિત કરી શકે છે. રિવ્યૂ કરવા માટે ટૅપ કરો."</string> -    <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> -    <skip /> -    <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> -    <skip /> +    <string name="ui_translation_accessibility_translated_text" msgid="3197547218178944544">"<xliff:g id="MESSAGE">%1$s</xliff:g>નો અનુવાદ કર્યો."</string> +    <string name="ui_translation_accessibility_translation_finished" msgid="3057830947610088465">"<xliff:g id="FROM_LANGUAGE">%1$s</xliff:g>થી <xliff:g id="TO_LANGUAGE">%2$s</xliff:g>માં સંદેશનો અનુવાદ કરવામાં આવ્યો."</string>  </resources> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index aecd79bd6527..dd96815dc551 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -2355,8 +2355,6 @@      <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"תדמית המותג של האפליקציה"</string>      <string name="view_and_control_notification_title" msgid="4300765399209912240">"בדיקה של הגדרות הגישה"</string>      <string name="view_and_control_notification_content" msgid="8003766498562604034">"לשירות <xliff:g id="SERVICE_NAME">%s</xliff:g> יש הרשאה להצגת המסך ושליטה בו. אפשר להקיש כדי לבדוק."</string> -    <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> -    <skip /> -    <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> -    <skip /> +    <string name="ui_translation_accessibility_translated_text" msgid="3197547218178944544">"ההודעה <xliff:g id="MESSAGE">%1$s</xliff:g> תורגמה."</string> +    <string name="ui_translation_accessibility_translation_finished" msgid="3057830947610088465">"ההודעה תורגמה מ<xliff:g id="FROM_LANGUAGE">%1$s</xliff:g> ל<xliff:g id="TO_LANGUAGE">%2$s</xliff:g>."</string>  </resources> diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml index 3a2a2b569f27..330147d6a131 100644 --- a/core/res/res/values-ne/strings.xml +++ b/core/res/res/values-ne/strings.xml @@ -2285,7 +2285,7 @@      <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"सेन्सरसम्बन्धी गोपनीयता"</string>      <string name="splash_screen_view_icon_description" msgid="180638751260598187">"एप जनाउने आइकन"</string>      <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"एपको ब्रान्डिङ फोटो"</string> -    <string name="view_and_control_notification_title" msgid="4300765399209912240">"हेराइ र नियन्त्रणसम्बन्धी सेटिङ जाँच्नुहोस्"</string> +    <string name="view_and_control_notification_title" msgid="4300765399209912240">"भ्यु र नियन्त्रणसम्बन्धी सेटिङ जाँच्नुहोस्"</string>      <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> तपाईंको स्क्रिन हेर्न र नियन्त्रण गर्न सक्छ। सेटिङ मिलाउन ट्याप गर्नुहोस्।"</string>      <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) -->      <skip /> diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml index 5aa16e7e22de..cdd9f52aa322 100644 --- a/core/res/res/values-or/strings.xml +++ b/core/res/res/values-or/strings.xml @@ -2287,8 +2287,6 @@      <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"ଆପ୍ଲିକେସନ୍ ବ୍ରାଣ୍ଡିଂ ଛବି"</string>      <string name="view_and_control_notification_title" msgid="4300765399209912240">"ଆକ୍ସେସ୍ ସେଟିଂସକୁ ଯାଞ୍ଚ କରନ୍ତୁ"</string>      <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> ଆପଣଙ୍କ ସ୍କ୍ରିନକୁ ଦେଖିପାରିବ ଏବଂ ନିୟନ୍ତ୍ରଣ କରିପାରିବ। ସମୀକ୍ଷା କରିବାକୁ ଟାପ୍ କରନ୍ତୁ।"</string> -    <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> -    <skip /> -    <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> -    <skip /> +    <string name="ui_translation_accessibility_translated_text" msgid="3197547218178944544">"<xliff:g id="MESSAGE">%1$s</xliff:g> ଅନୁବାଦ କରାଯାଇଛି।"</string> +    <string name="ui_translation_accessibility_translation_finished" msgid="3057830947610088465">"ମେସେଜ୍, <xliff:g id="FROM_LANGUAGE">%1$s</xliff:g>ରୁ <xliff:g id="TO_LANGUAGE">%2$s</xliff:g>କୁ ଅନୁବାଦ କରାଯାଇଛି।"</string>  </resources> diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml index 6cc4f1998183..afd9c0c12496 100644 --- a/core/res/res/values-pa/strings.xml +++ b/core/res/res/values-pa/strings.xml @@ -2287,8 +2287,6 @@      <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"ਐਪਲੀਕੇਸ਼ਨ ਦਾ ਬ੍ਰਾਂਡ ਵਾਲਾ ਚਿੱਤਰ"</string>      <string name="view_and_control_notification_title" msgid="4300765399209912240">"ਪਹੁੰਚ ਸੈਟਿੰਗਾਂ ਦੀ ਜਾਂਚ ਕਰੋ"</string>      <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> ਸੇਵਾ ਤੁਹਾਡੀ ਸਕ੍ਰੀਨ ਨੂੰ ਦੇਖ ਅਤੇ ਕੰਟਰੋਲ ਕਰ ਸਕਦੀ ਹੈ। ਸਮੀਖਿਆ ਲਈ ਟੈਪ ਕਰੋ।"</string> -    <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> -    <skip /> -    <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> -    <skip /> +    <string name="ui_translation_accessibility_translated_text" msgid="3197547218178944544">"<xliff:g id="MESSAGE">%1$s</xliff:g> ਦਾ ਅਨੁਵਾਦ ਕੀਤਾ ਗਿਆ।"</string> +    <string name="ui_translation_accessibility_translation_finished" msgid="3057830947610088465">"ਸੁਨੇਹੇ ਦਾ <xliff:g id="FROM_LANGUAGE">%1$s</xliff:g> ਤੋਂ <xliff:g id="TO_LANGUAGE">%2$s</xliff:g> ਵਿੱਚ ਅਨੁਵਾਦ ਕੀਤਾ ਗਿਆ।"</string>  </resources> diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml index 49ea3638a160..e1998ddf0dfe 100644 --- a/core/res/res/values-te/strings.xml +++ b/core/res/res/values-te/strings.xml @@ -2287,8 +2287,6 @@      <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"యాప్ బ్రాండింగ్ ఇమేజ్"</string>      <string name="view_and_control_notification_title" msgid="4300765399209912240">"యాక్సెస్ సెట్టింగ్లను చెక్ చేయండి"</string>      <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> మీ స్క్రీన్ను చూడవచ్చు, కంట్రోల్ చేయవచ్చు. రివ్యూ చేయడానికి ట్యాప్ చేయండి."</string> -    <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> -    <skip /> -    <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> -    <skip /> +    <string name="ui_translation_accessibility_translated_text" msgid="3197547218178944544">"<xliff:g id="MESSAGE">%1$s</xliff:g> అనువదించబడింది."</string> +    <string name="ui_translation_accessibility_translation_finished" msgid="3057830947610088465">"మెసేజ్ <xliff:g id="FROM_LANGUAGE">%1$s</xliff:g> నుండి <xliff:g id="TO_LANGUAGE">%2$s</xliff:g>కు అనువదించబడింది."</string>  </resources> diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml index 48208ac677cc..6d99dfb4563c 100644 --- a/core/res/res/values-ur/strings.xml +++ b/core/res/res/values-ur/strings.xml @@ -2287,8 +2287,6 @@      <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"ایپلیکیشن کی برانڈنگ تصویر"</string>      <string name="view_and_control_notification_title" msgid="4300765399209912240">"رسائی کی ترتیبات چیک کریں"</string>      <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> آپ کی اسکرین کو دیکھ اور کنٹرول کر سکتی ہیں۔ جائزے کے لیے تھپتھپائیں۔"</string> -    <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> -    <skip /> -    <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> -    <skip /> +    <string name="ui_translation_accessibility_translated_text" msgid="3197547218178944544">"<xliff:g id="MESSAGE">%1$s</xliff:g> کا ترجمہ کیا گیا۔"</string> +    <string name="ui_translation_accessibility_translation_finished" msgid="3057830947610088465">"پیغام کا ترجمہ <xliff:g id="FROM_LANGUAGE">%1$s</xliff:g> سے<xliff:g id="TO_LANGUAGE">%2$s</xliff:g> میں کیا گیا۔"</string>  </resources> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 480b47835100..f0c43ff18d36 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -1179,15 +1179,6 @@          <!-- Color applied to effects. -->          <attr name="effectColor" format="color" /> -        <!-- The type of the edge effect. The default is glow. --> -        <attr name="edgeEffectType"> -            <!-- Use a colored glow at the edge. --> -            <enum name="glow" value="0" /> - -            <!-- Stretch the content. --> -            <enum name="stretch" value="1" /> -        </attr> -          <!-- =================== -->          <!-- Lighting properties -->          <!-- =================== --> @@ -9257,7 +9248,6 @@      <!-- Used as a filter array on the theme to pull out only the EdgeEffect-relevant bits. -->      <declare-styleable name="EdgeEffect">          <attr name="colorEdgeEffect" /> -        <attr name="edgeEffectType" />      </declare-styleable>      <!-- Use <code>tv-input</code> as the root tag of the XML resource that describes a diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml index 36168e7bd937..f71088f417a4 100644 --- a/core/res/res/values/colors.xml +++ b/core/res/res/values/colors.xml @@ -246,6 +246,9 @@      <!-- Lightest shade of the accent color used by the system. White.       This value can be overlaid at runtime by OverlayManager RROs. -->      <color name="system_accent1_0">#ffffff</color> +    <!-- Shade of the accent system color at 99% lightness. +     This value can be overlaid at runtime by OverlayManager RROs. --> +    <color name="system_accent1_10">#F1FFFC</color>      <!-- Shade of the accent system color at 95% lightness.       This value can be overlaid at runtime by OverlayManager RROs. -->      <color name="system_accent1_50">#9CFFF2</color> @@ -283,6 +286,9 @@      <!-- Lightest shade of the secondary accent color used by the system. White.       This value can be overlaid at runtime by OverlayManager RROs. -->      <color name="system_accent2_0">#ffffff</color> +    <!-- Shade of the secondary accent system color at 99% lightness. +     This value can be overlaid at runtime by OverlayManager RROs. --> +    <color name="system_accent2_10">#F0FFFC</color>      <!-- Shade of the secondary accent system color at 95% lightness.       This value can be overlaid at runtime by OverlayManager RROs. -->      <color name="system_accent2_50">#CDFAF1</color> @@ -320,6 +326,9 @@      <!-- Lightest shade of the tertiary accent color used by the system. White.       This value can be overlaid at runtime by OverlayManager RROs. -->      <color name="system_accent3_0">#ffffff</color> +    <!-- Shade of the tertiary accent system color at 99% lightness. +     This value can be overlaid at runtime by OverlayManager RROs. --> +    <color name="system_accent3_10">#FFFBFF</color>      <!-- Shade of the tertiary accent system color at 95% lightness.       This value can be overlaid at runtime by OverlayManager RROs. -->      <color name="system_accent3_50">#F9EAFF</color> @@ -357,6 +366,9 @@      <!-- Lightest shade of the neutral color used by the system. White.       This value can be overlaid at runtime by OverlayManager RROs. -->      <color name="system_neutral1_0">#ffffff</color> +    <!-- Shade of the neutral system color at 99% lightness. +     This value can be overlaid at runtime by OverlayManager RROs. --> +    <color name="system_neutral1_10">#fbfbfb</color>      <!-- Shade of the neutral system color at 95% lightness.       This value can be overlaid at runtime by OverlayManager RROs. -->      <color name="system_neutral1_50">#f0f0f0</color> @@ -394,6 +406,9 @@      <!-- Lightest shade of the secondary neutral color used by the system. White.       This value can be overlaid at runtime by OverlayManager RROs. -->      <color name="system_neutral2_0">#ffffff</color> +    <!-- Shade of the secondary neutral system color at 99% lightness. +     This value can be overlaid at runtime by OverlayManager RROs. --> +    <color name="system_neutral2_10">#fbfbfb</color>      <!-- Shade of the secondary neutral system color at 95% lightness.       This value can be overlaid at runtime by OverlayManager RROs. -->      <color name="system_neutral2_50">#f0f0f0</color> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 0e9526ab4e6c..03701c3ceee6 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -3064,7 +3064,6 @@      <public name="hotwordDetectionService" />      <public name="previewLayout" />      <public name="clipToOutline" /> -    <public name="edgeEffectType" />      <public name="knownCerts" />      <public name="windowBackgroundBlurRadius"/>      <public name="windowSplashScreenBackground"/> @@ -3112,6 +3111,7 @@      <!-- 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" /> @@ -3124,6 +3124,7 @@      <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" /> @@ -3137,6 +3138,7 @@      <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" /> @@ -3149,6 +3151,7 @@      <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" /> @@ -3161,6 +3164,7 @@      <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" /> diff --git a/core/tests/batterystatstests/BatteryStatsViewer/res/drawable/gm_device_24.xml b/core/tests/batterystatstests/BatteryStatsViewer/res/drawable/gm_device_24.xml new file mode 100644 index 000000000000..223cdf45b166 --- /dev/null +++ b/core/tests/batterystatstests/BatteryStatsViewer/res/drawable/gm_device_24.xml @@ -0,0 +1,10 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" +    android:width="24dp" +    android:height="24dp" +    android:viewportWidth="24" +    android:viewportHeight="24" +    android:tint="#3ddc84"> +  <path +      android:fillColor="@android:color/white" +      android:pathData="M17,1L7,1c-1.1,0 -2,0.9 -2,2v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2L19,3c0,-1.1 -0.9,-2 -2,-2zM7,6h10v10L7,16L7,6zM17,21L7,21v-3h10v3zM7,4L7,3h10v1L7,4zM10,19h4v1h-4z"/> +</vector> diff --git a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java index a15a8d8b3f47..24b164bcb8c0 100644 --- a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java +++ b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java @@ -19,7 +19,6 @@ package com.android.frameworks.core.batterystatsviewer;  import android.content.Context;  import android.os.BatteryConsumer;  import android.os.BatteryUsageStats; -import android.os.SystemBatteryConsumer;  import android.os.UidBatteryConsumer;  import android.os.UserHandle;  import android.util.DebugUtils; @@ -63,7 +62,7 @@ public class BatteryConsumerData {          }          mBatteryConsumerInfo = BatteryConsumerInfoHelper.makeBatteryConsumerInfo( -                context.getPackageManager(), requestedBatteryConsumer); +                requestedBatteryConsumer, batteryConsumerId, context.getPackageManager());          double[] totalPowerByComponentMah = new double[BatteryConsumer.POWER_COMPONENT_COUNT];          double[] totalModeledPowerByComponentMah = @@ -119,16 +118,20 @@ public class BatteryConsumerData {      private BatteryConsumer getRequestedBatteryConsumer(BatteryUsageStats batteryUsageStats,              String batteryConsumerId) { -        for (BatteryConsumer consumer : batteryUsageStats.getUidBatteryConsumers()) { -            if (batteryConsumerId(consumer).equals(batteryConsumerId)) { -                return consumer; +        for (int scope = 0; +                scope < BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_COUNT; +                scope++) { +            if (batteryConsumerId(scope).equals(batteryConsumerId)) { +                return batteryUsageStats.getAggregateBatteryConsumer(scope);              }          } -        for (BatteryConsumer consumer : batteryUsageStats.getSystemBatteryConsumers()) { + +        for (BatteryConsumer consumer : batteryUsageStats.getUidBatteryConsumers()) {              if (batteryConsumerId(consumer).equals(batteryConsumerId)) {                  return consumer;              }          } +          return null;      } @@ -148,11 +151,25 @@ public class BatteryConsumerData {      private void computeTotalPower(BatteryUsageStats batteryUsageStats,              double[] powerByComponentMah) { -        for (BatteryConsumer consumer : batteryUsageStats.getUidBatteryConsumers()) { -            for (int component = 0; component < BatteryConsumer.POWER_COMPONENT_COUNT; -                    component++) { -                powerByComponentMah[component] += consumer.getConsumedPower(component); -            } +        final BatteryConsumer consumer = +                batteryUsageStats.getAggregateBatteryConsumer( +                        BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE); +        for (int component = 0; component < BatteryConsumer.POWER_COMPONENT_COUNT; component++) { +            powerByComponentMah[component] += consumer.getConsumedPower(component); +        } +    } + +    private void computeTotalPowerForCustomComponent( +            BatteryUsageStats batteryUsageStats, double[] powerByComponentMah) { +        final BatteryConsumer consumer = +                batteryUsageStats.getAggregateBatteryConsumer( +                        BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE); +        final int customComponentCount = consumer.getCustomPowerComponentCount(); +        for (int component = 0; +                component < Math.min(customComponentCount, powerByComponentMah.length); +                component++) { +            powerByComponentMah[component] += consumer.getConsumedPowerForCustomComponent( +                    BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID + component);          }      } @@ -166,19 +183,6 @@ public class BatteryConsumerData {          }      } -    private void computeTotalPowerForCustomComponent( -            BatteryUsageStats batteryUsageStats, double[] powerByComponentMah) { -        for (BatteryConsumer consumer : batteryUsageStats.getUidBatteryConsumers()) { -            final int customComponentCount = consumer.getCustomPowerComponentCount(); -            for (int component = 0; -                    component < Math.min(customComponentCount, powerByComponentMah.length); -                    component++) { -                powerByComponentMah[component] += consumer.getConsumedPowerForCustomComponent( -                        BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID + component); -            } -        } -    } -      private void addEntry(String title, EntryType entryType, double amount, double totalAmount,              boolean isSystemBatteryConsumer) {          Entry entry = new Entry(); @@ -203,10 +207,13 @@ public class BatteryConsumerData {              return "APP|"                      + UserHandle.getUserId(((UidBatteryConsumer) consumer).getUid()) + "|"                      + ((UidBatteryConsumer) consumer).getUid(); -        } else if (consumer instanceof SystemBatteryConsumer) { -            return ((SystemBatteryConsumer) consumer).getDrainType() + "|0|0";          } else {              return "";          }      } -} + +    public static String batteryConsumerId( +            @BatteryUsageStats.AggregateBatteryConsumerScope int scope) { +        return "SYS|" + scope; +    } +}
\ No newline at end of file diff --git a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerInfoHelper.java b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerInfoHelper.java index 6288e0b886d1..f2d6bca28136 100644 --- a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerInfoHelper.java +++ b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerInfoHelper.java @@ -16,11 +16,13 @@  package com.android.frameworks.core.batterystatsviewer; +import static com.android.frameworks.core.batterystatsviewer.BatteryConsumerData.batteryConsumerId; +  import android.content.pm.ApplicationInfo;  import android.content.pm.PackageManager;  import android.os.BatteryConsumer; +import android.os.BatteryUsageStats;  import android.os.Process; -import android.os.SystemBatteryConsumer;  import android.os.UidBatteryConsumer;  import android.util.DebugUtils; @@ -41,10 +43,11 @@ class BatteryConsumerInfoHelper {      }      @NonNull -    public static BatteryConsumerInfo makeBatteryConsumerInfo(PackageManager packageManager, -            @NonNull BatteryConsumer batteryConsumer) { +    public static BatteryConsumerInfo makeBatteryConsumerInfo( +            @NonNull BatteryConsumer batteryConsumer, String batteryConsumerId, +            PackageManager packageManager) {          BatteryConsumerInfo info = new BatteryConsumerInfo(); -        info.id = BatteryConsumerData.batteryConsumerId(batteryConsumer); +        info.id = batteryConsumerId;          info.powerMah = batteryConsumer.getConsumedPower();          if (batteryConsumer instanceof UidBatteryConsumer) { @@ -100,25 +103,29 @@ class BatteryConsumerInfoHelper {                      info.packages = sb;                  }              } -        } else if (batteryConsumer instanceof SystemBatteryConsumer) { -            final SystemBatteryConsumer systemBatteryConsumer = -                    (SystemBatteryConsumer) batteryConsumer; -            final int drainType = systemBatteryConsumer.getDrainType(); -            String name = DebugUtils.constantToString(SystemBatteryConsumer.class, "DRAIN_TYPE_", -                    drainType); -            info.label = name.charAt(0) + name.substring(1).toLowerCase().replace('_', ' '); -            info.isSystemBatteryConsumer = true; -        } - -        // Default the app icon to System Server. This includes root, dex2oat and other UIDs. -        if (info.iconInfo == null) { -            try { -                info.iconInfo = -                        packageManager.getApplicationInfo(SYSTEM_SERVER_PACKAGE_NAME, 0); -            } catch (PackageManager.NameNotFoundException nameNotFoundException) { -                // Won't happen +            // Default the app icon to System Server. This includes root, dex2oat and other UIDs. +            if (info.iconInfo == null) { +                try { +                    info.iconInfo = +                            packageManager.getApplicationInfo(SYSTEM_SERVER_PACKAGE_NAME, 0); +                } catch (PackageManager.NameNotFoundException nameNotFoundException) { +                    // Won't happen +                } +            } +        } else { +            for (int scope = 0; +                    scope < BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_COUNT; +                    scope++) { +                if (batteryConsumerId(scope).equals(batteryConsumerId)) { +                    final String name = DebugUtils.constantToString(BatteryUsageStats.class, +                            "AGGREGATE_BATTERY_CONSUMER_SCOPE_", scope) +                            .replace('_', ' '); +                    info.label = name; +                    break; +                }              }          } +          return info;      }  } diff --git a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerPickerActivity.java b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerPickerActivity.java index 63a15d6c63b4..9e63a350df41 100644 --- a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerPickerActivity.java +++ b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerPickerActivity.java @@ -18,68 +18,60 @@ package com.android.frameworks.core.batterystatsviewer;  import android.content.Context;  import android.content.Intent; +import android.content.pm.PackageManager; +import android.os.BatteryStatsManager; +import android.os.BatteryUsageStats;  import android.os.Bundle; +import android.os.UidBatteryConsumer; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; +import androidx.activity.ComponentActivity;  import androidx.annotation.NonNull; -import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentActivity; -import androidx.fragment.app.FragmentStatePagerAdapter; -import androidx.viewpager.widget.ViewPager; +import androidx.loader.app.LoaderManager; +import androidx.loader.content.Loader; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; -import com.google.android.material.tabs.TabLayout; +import com.android.settingslib.utils.AsyncLoaderCompat; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Locale;  /**   * Picker, showing a sorted lists of applications and other types of entities consuming power.   * Opens BatteryStatsViewerActivity upon item selection.   */ -public class BatteryConsumerPickerActivity extends FragmentActivity { +public class BatteryConsumerPickerActivity extends ComponentActivity {      private static final String PREF_SELECTED_BATTERY_CONSUMER = "batteryConsumerId"; +    private static final int BATTERY_STATS_REFRESH_RATE_MILLIS = 60 * 1000; +    private BatteryConsumerListAdapter mBatteryConsumerListAdapter; +    private RecyclerView mAppList; +    private View mLoadingView; +    private final Runnable mBatteryStatsRefresh = this::loadBatteryStats; + +    private interface OnBatteryConsumerSelectedListener { +        void onBatteryConsumerSelected(String batteryConsumerId); +    }      @Override      protected void onCreate(Bundle icicle) {          super.onCreate(icicle); -        setContentView(R.layout.battery_consumer_picker_activity_layout); - -        ViewPager viewPager = findViewById(R.id.pager); - -        FragmentStatePagerAdapter adapter = new FragmentStatePagerAdapter( -                getSupportFragmentManager()) { - -            @Override -            public int getCount() { -                return 2; -            } - -            @NonNull -            @Override -            public Fragment getItem(int position) { -                switch (position) { -                    case 0: -                        return new BatteryConsumerPickerFragment( -                                BatteryConsumerPickerFragment.PICKER_TYPE_APP); -                    case 1: -                    default: -                        return new BatteryConsumerPickerFragment( -                                BatteryConsumerPickerFragment.PICKER_TYPE_DRAIN); -                } -            } +        setContentView(R.layout.battery_consumer_picker_layout); +        mLoadingView = findViewById(R.id.loading_view); -            @Override -            public CharSequence getPageTitle(int position) { -                switch (position) { -                    case 0: -                        return "Apps"; -                    case 1: -                        return "Drains"; -                } -                return null; -            } -        }; +        mAppList = findViewById(R.id.list_view); +        mAppList.setLayoutManager(new LinearLayoutManager(this)); +        mBatteryConsumerListAdapter = +                new BatteryConsumerListAdapter((this::setSelectedBatteryConsumer)); +        mAppList.setAdapter(mBatteryConsumerListAdapter); -        viewPager.setAdapter(adapter); -        TabLayout tabLayout = findViewById(R.id.tab_layout); -        tabLayout.setupWithViewPager(viewPager);          if (icicle == null) {              final String batteryConsumerId = getPreferences(Context.MODE_PRIVATE)                      .getString(PREF_SELECTED_BATTERY_CONSUMER, null); @@ -101,4 +93,183 @@ public class BatteryConsumerPickerActivity extends FragmentActivity {                  .putExtra(BatteryStatsViewerActivity.EXTRA_BATTERY_CONSUMER, batteryConsumerId);          startActivity(intent);      } + +    @Override +    protected void onResume() { +        super.onResume(); +        loadBatteryStats(); +    } + +    @Override +    protected void onPause() { +        super.onPause(); +        getMainThreadHandler().removeCallbacks(mBatteryStatsRefresh); +    } + +    private void loadBatteryStats() { +        LoaderManager.getInstance(this).restartLoader(0, null, +                new BatteryConsumerListLoaderCallbacks()); +        getMainThreadHandler().postDelayed(mBatteryStatsRefresh, BATTERY_STATS_REFRESH_RATE_MILLIS); +    } + +    private static class BatteryConsumerListLoader extends +            AsyncLoaderCompat<List<BatteryConsumerInfoHelper.BatteryConsumerInfo>> { +        private final BatteryStatsManager mBatteryStatsManager; +        private final PackageManager mPackageManager; + +        BatteryConsumerListLoader(Context context) { +            super(context); +            mBatteryStatsManager = context.getSystemService(BatteryStatsManager.class); +            mPackageManager = context.getPackageManager(); +        } + +        @Override +        public List<BatteryConsumerInfoHelper.BatteryConsumerInfo> loadInBackground() { +            final BatteryUsageStats batteryUsageStats = mBatteryStatsManager.getBatteryUsageStats(); +            List<BatteryConsumerInfoHelper.BatteryConsumerInfo> batteryConsumerList = +                    new ArrayList<>(); + +            for (int scope = 0; +                    scope < BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_COUNT; +                    scope++) { +                batteryConsumerList.add( +                        BatteryConsumerInfoHelper.makeBatteryConsumerInfo( +                                batteryUsageStats.getAggregateBatteryConsumer(scope), +                                BatteryConsumerData.batteryConsumerId(scope), +                                mPackageManager)); +            } + +            for (UidBatteryConsumer consumer : batteryUsageStats.getUidBatteryConsumers()) { +                batteryConsumerList.add( +                        BatteryConsumerInfoHelper.makeBatteryConsumerInfo(consumer, +                                BatteryConsumerData.batteryConsumerId(consumer), +                                mPackageManager)); +            } + +            batteryConsumerList.sort( +                    Comparator.comparing( +                            (BatteryConsumerInfoHelper.BatteryConsumerInfo a) -> a.powerMah) +                            .reversed()); + +            return batteryConsumerList; +        } + +        @Override +        protected void onDiscardResult(List<BatteryConsumerInfoHelper.BatteryConsumerInfo> result) { +        } +    } + +    private class BatteryConsumerListLoaderCallbacks implements +            LoaderManager.LoaderCallbacks<List<BatteryConsumerInfoHelper.BatteryConsumerInfo>> { + +        @NonNull +        @Override +        public Loader<List<BatteryConsumerInfoHelper.BatteryConsumerInfo>> onCreateLoader(int id, +                Bundle args) { +            return new BatteryConsumerListLoader(BatteryConsumerPickerActivity.this); +        } + +        @Override +        public void onLoadFinished( +                @NonNull Loader<List<BatteryConsumerInfoHelper.BatteryConsumerInfo>> loader, +                List<BatteryConsumerInfoHelper.BatteryConsumerInfo> batteryConsumerList) { +            mBatteryConsumerListAdapter.setBatteryConsumerList(batteryConsumerList); +            mAppList.setVisibility(View.VISIBLE); +            mLoadingView.setVisibility(View.GONE); +        } + +        @Override +        public void onLoaderReset( +                @NonNull Loader<List<BatteryConsumerInfoHelper.BatteryConsumerInfo>> loader) { +        } +    } + +    public class BatteryConsumerListAdapter +            extends RecyclerView.Adapter<BatteryConsumerViewHolder> { +        private final OnBatteryConsumerSelectedListener mListener; +        private List<BatteryConsumerInfoHelper.BatteryConsumerInfo> mBatteryConsumerList; + +        public BatteryConsumerListAdapter(OnBatteryConsumerSelectedListener listener) { +            mListener = listener; +        } + +        void setBatteryConsumerList( +                List<BatteryConsumerInfoHelper.BatteryConsumerInfo> batteryConsumerList) { +            mBatteryConsumerList = batteryConsumerList; +            notifyDataSetChanged(); +        } + +        @Override +        public int getItemCount() { +            return mBatteryConsumerList.size(); +        } + +        @NonNull +        @Override +        public BatteryConsumerViewHolder onCreateViewHolder( +                @NonNull ViewGroup viewGroup, +                int position) { +            LayoutInflater layoutInflater = LayoutInflater.from(viewGroup.getContext()); +            View view = layoutInflater.inflate(R.layout.battery_consumer_info_layout, viewGroup, +                    false); +            return new BatteryConsumerViewHolder(view, mListener); +        } + +        @Override +        public void onBindViewHolder(@NonNull BatteryConsumerViewHolder viewHolder, int position) { +            BatteryConsumerInfoHelper.BatteryConsumerInfo item = mBatteryConsumerList.get(position); +            viewHolder.id = item.id; +            viewHolder.titleView.setText(item.label); +            if (item.details != null) { +                viewHolder.detailsView.setText(item.details); +                viewHolder.detailsView.setVisibility(View.VISIBLE); +            } else { +                viewHolder.detailsView.setVisibility(View.GONE); +            } +            viewHolder.powerView.setText( +                    String.format(Locale.getDefault(), "%.1f mAh", item.powerMah)); +            if (item.iconInfo != null) { +                viewHolder.iconView.setImageDrawable( +                        item.iconInfo.loadIcon(getPackageManager())); +            } else { +                viewHolder.iconView.setImageResource(R.drawable.gm_device_24); +            } +            if (item.packages != null) { +                viewHolder.packagesView.setText(item.packages); +                viewHolder.packagesView.setVisibility(View.VISIBLE); +            } else { +                viewHolder.packagesView.setVisibility(View.GONE); +            } +        } +    } + +    // View Holder used when displaying apps +    public static class BatteryConsumerViewHolder extends RecyclerView.ViewHolder +            implements View.OnClickListener { +        private final OnBatteryConsumerSelectedListener mListener; + +        public String id; +        public TextView titleView; +        public TextView detailsView; +        public ImageView iconView; +        public TextView packagesView; +        public TextView powerView; + +        BatteryConsumerViewHolder(View view, OnBatteryConsumerSelectedListener listener) { +            super(view); +            mListener = listener; +            view.setOnClickListener(this); +            titleView = view.findViewById(android.R.id.title); +            detailsView = view.findViewById(R.id.details); +            iconView = view.findViewById(android.R.id.icon); +            packagesView = view.findViewById(R.id.packages); +            powerView = view.findViewById(R.id.power_mah); +            powerView.setVisibility(View.VISIBLE); +        } + +        @Override +        public void onClick(View v) { +            mListener.onBatteryConsumerSelected(id); +        } +    }  } diff --git a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerPickerFragment.java b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerPickerFragment.java deleted file mode 100644 index 49220877d31e..000000000000 --- a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerPickerFragment.java +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Copyright (C) 2008 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.frameworks.core.batterystatsviewer; - -import android.content.Context; -import android.content.pm.PackageManager; -import android.os.BatteryStatsManager; -import android.os.BatteryUsageStats; -import android.os.Bundle; -import android.os.SystemBatteryConsumer; -import android.os.UidBatteryConsumer; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.fragment.app.Fragment; -import androidx.loader.app.LoaderManager; -import androidx.loader.content.Loader; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - -import com.android.frameworks.core.batterystatsviewer.BatteryConsumerInfoHelper.BatteryConsumerInfo; -import com.android.settingslib.utils.AsyncLoaderCompat; - -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; -import java.util.Locale; - -/** - * Picker, showing a sorted lists of applications or other types of entities consuming power. - * Returns the selected entity ID or null. - */ -public class BatteryConsumerPickerFragment extends Fragment { -    private static final String TAG = "AppPicker"; - -    public static final String PICKER_TYPE = "pickertype"; - -    public static final int PICKER_TYPE_APP = 0; -    public static final int PICKER_TYPE_DRAIN = 1; - -    private BatteryConsumerListAdapter mBatteryConsumerListAdapter; -    private RecyclerView mAppList; -    private View mLoadingView; - -    private interface OnBatteryConsumerSelectedListener { -        void onBatteryConsumerSelected(String batteryConsumerId); -    } - -    public BatteryConsumerPickerFragment(int pickerType) { -        Bundle args = new Bundle(); -        args.putInt(PICKER_TYPE, pickerType); -        setArguments(args); -    } - -    public BatteryConsumerPickerFragment() { -    } - -    @Nullable -    @Override -    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, -            @Nullable Bundle savedInstanceState) { -        View view = inflater.inflate(R.layout.battery_consumer_picker_layout, container, false); -        mLoadingView = view.findViewById(R.id.loading_view); - -        mAppList = view.findViewById(R.id.list_view); -        mAppList.setLayoutManager(new LinearLayoutManager(getContext())); -        mBatteryConsumerListAdapter = new BatteryConsumerListAdapter( -                BatteryConsumerPickerFragment.this::setSelectedBatteryConsumer); -        mAppList.setAdapter(mBatteryConsumerListAdapter); - -        LoaderManager.getInstance(this).initLoader(0, getArguments(), -                new BatteryConsumerListLoaderCallbacks()); -        return view; -    } - -    public void setSelectedBatteryConsumer(String id) { -        ((BatteryConsumerPickerActivity) getActivity()).setSelectedBatteryConsumer(id); -    } - -    private static class BatteryConsumerListLoader extends -            AsyncLoaderCompat<List<BatteryConsumerInfo>> { -        private final int mPickerType; -        private final BatteryStatsManager mBatteryStatsManager; -        private final PackageManager mPackageManager; - -        BatteryConsumerListLoader(Context context, int pickerType) { -            super(context); -            mBatteryStatsManager = context.getSystemService(BatteryStatsManager.class); -            mPickerType = pickerType; -            mPackageManager = context.getPackageManager(); -        } - -        @Override -        public List<BatteryConsumerInfo> loadInBackground() { -            final BatteryUsageStats batteryUsageStats = mBatteryStatsManager.getBatteryUsageStats(); - -            List<BatteryConsumerInfo> batteryConsumerList = new ArrayList<>(); -            switch (mPickerType) { -                case PICKER_TYPE_APP: -                    for (UidBatteryConsumer consumer : batteryUsageStats.getUidBatteryConsumers()) { -                        batteryConsumerList.add( -                                BatteryConsumerInfoHelper.makeBatteryConsumerInfo(mPackageManager, -                                        consumer)); -                    } -                    break; -                case PICKER_TYPE_DRAIN: -                default: -                    for (SystemBatteryConsumer consumer : -                            batteryUsageStats.getSystemBatteryConsumers()) { -                        batteryConsumerList.add( -                                BatteryConsumerInfoHelper.makeBatteryConsumerInfo(mPackageManager, -                                        consumer)); -                    } -                    break; -            } - -            batteryConsumerList.sort( -                    Comparator.comparing((BatteryConsumerInfo a) -> a.powerMah).reversed()); -            return batteryConsumerList; -        } - -        @Override -        protected void onDiscardResult(List<BatteryConsumerInfo> result) { -        } -    } - -    private class BatteryConsumerListLoaderCallbacks implements -            LoaderManager.LoaderCallbacks<List<BatteryConsumerInfo>> { - -        @NonNull -        @Override -        public Loader<List<BatteryConsumerInfo>> onCreateLoader(int id, Bundle args) { -            return new BatteryConsumerListLoader(getContext(), args.getInt(PICKER_TYPE)); -        } - -        @Override -        public void onLoadFinished(@NonNull Loader<List<BatteryConsumerInfo>> loader, -                List<BatteryConsumerInfo> batteryConsumerList) { -            mBatteryConsumerListAdapter.setBatteryConsumerList(batteryConsumerList); -            mAppList.setVisibility(View.VISIBLE); -            mLoadingView.setVisibility(View.GONE); -        } - -        @Override -        public void onLoaderReset( -                @NonNull Loader<List<BatteryConsumerInfo>> loader) { -        } -    } - -    public class BatteryConsumerListAdapter extends -            RecyclerView.Adapter<BatteryConsumerViewHolder> { -        private final OnBatteryConsumerSelectedListener mListener; -        private List<BatteryConsumerInfo> mBatteryConsumerList; - -        public BatteryConsumerListAdapter(OnBatteryConsumerSelectedListener listener) { -            mListener = listener; -        } - -        void setBatteryConsumerList(List<BatteryConsumerInfo> batteryConsumerList) { -            mBatteryConsumerList = batteryConsumerList; -            notifyDataSetChanged(); -        } - -        @Override -        public int getItemCount() { -            return mBatteryConsumerList.size(); -        } - -        @NonNull -        @Override -        public BatteryConsumerViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, -                int position) { -            LayoutInflater layoutInflater = LayoutInflater.from(viewGroup.getContext()); -            View view = layoutInflater.inflate(R.layout.battery_consumer_info_layout, viewGroup, -                    false); -            return new BatteryConsumerViewHolder(view, mListener); -        } - -        @Override -        public void onBindViewHolder(@NonNull BatteryConsumerViewHolder viewHolder, int position) { -            BatteryConsumerInfo item = mBatteryConsumerList.get(position); -            viewHolder.id = item.id; -            viewHolder.titleView.setText(item.label); -            if (item.details != null) { -                viewHolder.detailsView.setText(item.details); -                viewHolder.detailsView.setVisibility(View.VISIBLE); -            } else { -                viewHolder.detailsView.setVisibility(View.GONE); -            } -            viewHolder.powerView.setText( -                    String.format(Locale.getDefault(), "%.1f mAh", item.powerMah)); -            viewHolder.iconView.setImageDrawable( -                    item.iconInfo.loadIcon(getContext().getPackageManager())); -            if (item.packages != null) { -                viewHolder.packagesView.setText(item.packages); -                viewHolder.packagesView.setVisibility(View.VISIBLE); -            } else { -                viewHolder.packagesView.setVisibility(View.GONE); -            } -        } -    } - -    // View Holder used when displaying apps -    public static class BatteryConsumerViewHolder extends RecyclerView.ViewHolder -            implements View.OnClickListener { -        private final OnBatteryConsumerSelectedListener mListener; - -        public String id; -        public TextView titleView; -        public TextView detailsView; -        public ImageView iconView; -        public TextView packagesView; -        public TextView powerView; - -        BatteryConsumerViewHolder(View view, OnBatteryConsumerSelectedListener listener) { -            super(view); -            mListener = listener; -            view.setOnClickListener(this); -            titleView = view.findViewById(android.R.id.title); -            detailsView = view.findViewById(R.id.details); -            iconView = view.findViewById(android.R.id.icon); -            packagesView = view.findViewById(R.id.packages); -            powerView = view.findViewById(R.id.power_mah); -            powerView.setVisibility(View.VISIBLE); -        } - -        @Override -        public void onClick(View v) { -            mListener.onBatteryConsumerSelected(id); -        } -    } -} diff --git a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryStatsViewerActivity.java b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryStatsViewerActivity.java index 03dde04519ce..bb75be4f5ba8 100644 --- a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryStatsViewerActivity.java +++ b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryStatsViewerActivity.java @@ -51,7 +51,7 @@ public class BatteryStatsViewerActivity extends ComponentActivity {      private static final int LOADER_BATTERY_USAGE_STATS = 1;      private BatteryStatsDataAdapter mBatteryStatsDataAdapter; -    private final Runnable mBatteryStatsRefresh = this::periodicBatteryStatsRefresh; +    private final Runnable mBatteryStatsRefresh = this::loadBatteryStats;      private String mBatteryConsumerId;      private TextView mTitleView;      private TextView mDetailsView; @@ -85,13 +85,15 @@ public class BatteryStatsViewerActivity extends ComponentActivity {          mLoadingView = findViewById(R.id.loading_view);          mEmptyView = findViewById(R.id.empty_view); -        loadBatteryStats(); +        LoaderManager loaderManager = LoaderManager.getInstance(this); +        loaderManager.restartLoader(LOADER_BATTERY_USAGE_STATS, null, +                new BatteryUsageStatsLoaderCallbacks());      }      @Override      protected void onResume() {          super.onResume(); -        periodicBatteryStatsRefresh(); +        loadBatteryStats();      }      @Override @@ -100,15 +102,11 @@ public class BatteryStatsViewerActivity extends ComponentActivity {          getMainThreadHandler().removeCallbacks(mBatteryStatsRefresh);      } -    private void periodicBatteryStatsRefresh() { -        loadBatteryStats(); -        getMainThreadHandler().postDelayed(mBatteryStatsRefresh, BATTERY_STATS_REFRESH_RATE_MILLIS); -    } -      private void loadBatteryStats() {          LoaderManager loaderManager = LoaderManager.getInstance(this);          loaderManager.restartLoader(LOADER_BATTERY_USAGE_STATS, null,                  new BatteryUsageStatsLoaderCallbacks()); +        getMainThreadHandler().postDelayed(mBatteryStatsRefresh, BATTERY_STATS_REFRESH_RATE_MILLIS);      }      private static class BatteryUsageStatsLoader extends @@ -183,9 +181,12 @@ public class BatteryStatsViewerActivity extends ComponentActivity {              } else {                  mDetailsView.setVisibility(View.GONE);              } -            mIconView.setImageDrawable( -                    batteryConsumerInfo.iconInfo.loadIcon(getPackageManager())); - +            if (batteryConsumerInfo.iconInfo != null) { +                mIconView.setImageDrawable( +                        batteryConsumerInfo.iconInfo.loadIcon(getPackageManager())); +            } else { +                mIconView.setImageResource(R.drawable.gm_device_24); +            }              if (batteryConsumerInfo.packages != null) {                  mPackagesView.setText(batteryConsumerInfo.packages);                  mPackagesView.setVisibility(View.VISIBLE); diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java index 2e2e6bd07539..6f17ea994699 100644 --- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java +++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java @@ -185,15 +185,6 @@ public class ActivityThreadTest {      }      @Test -    public void testHandleActivity_assetsChanged() { -        relaunchActivityAndAssertPreserveWindow(activity -> { -            // Relaunches all activities. -            activity.getActivityThread().handleApplicationInfoChanged( -                    activity.getApplicationInfo()); -        }); -    } - -    @Test      public void testRecreateActivity() {          relaunchActivityAndAssertPreserveWindow(Activity::recreate);      } diff --git a/core/tests/coretests/src/android/app/people/PeopleSpaceTileTest.java b/core/tests/coretests/src/android/app/people/PeopleSpaceTileTest.java index 3e2c4e98e21a..5cee2c1389e4 100644 --- a/core/tests/coretests/src/android/app/people/PeopleSpaceTileTest.java +++ b/core/tests/coretests/src/android/app/people/PeopleSpaceTileTest.java @@ -16,6 +16,9 @@  package android.app.people; +import static android.app.people.PeopleSpaceTile.SHOW_CONVERSATIONS; +import static android.app.people.PeopleSpaceTile.SHOW_IMPORTANT_CONVERSATIONS; +  import static com.google.common.truth.Truth.assertThat;  import static junit.framework.Assert.assertFalse; @@ -178,6 +181,71 @@ public class PeopleSpaceTileTest {      }      @Test +    public void testUserQuieted() { +        PeopleSpaceTile tile = new PeopleSpaceTile.Builder( +                new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps).build(); +        assertFalse(tile.isUserQuieted()); + +        tile = new PeopleSpaceTile +                .Builder(new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps) +                .setIsUserQuieted(true) +                .build(); +        assertTrue(tile.isUserQuieted()); +    } + +    @Test +    public void testCanBypassDnd() { +        PeopleSpaceTile tile = new PeopleSpaceTile.Builder( +                new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps).build(); +        assertFalse(tile.canBypassDnd()); + +        tile = new PeopleSpaceTile +                .Builder(new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps) +                .setCanBypassDnd(true) +                .build(); +        assertTrue(tile.canBypassDnd()); +    } + +    @Test +    public void testNotificationPolicyState() { +        PeopleSpaceTile tile = new PeopleSpaceTile.Builder( +                new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps).build(); +        assertThat(tile.getNotificationPolicyState()).isEqualTo(SHOW_CONVERSATIONS); + +        tile = new PeopleSpaceTile +                .Builder(new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps) +                .setNotificationPolicyState(SHOW_IMPORTANT_CONVERSATIONS) +                .build(); +        assertThat(tile.getNotificationPolicyState()).isEqualTo(SHOW_IMPORTANT_CONVERSATIONS); +    } + +    @Test +    public void testPackageSuspended() { +        PeopleSpaceTile tile = new PeopleSpaceTile.Builder( +                new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps).build(); +        assertFalse(tile.isPackageSuspended()); + +        tile = new PeopleSpaceTile +                .Builder(new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps) +                .setIsPackageSuspended(true) +                .build(); +        assertTrue(tile.isPackageSuspended()); +    } + +    @Test +    public void testContactAffinity() { +        PeopleSpaceTile tile = new PeopleSpaceTile.Builder( +                new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps).build(); +        assertThat(tile.getContactAffinity()).isEqualTo(0f); + +        tile = new PeopleSpaceTile +                .Builder(new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps) +                .setContactAffinity(1f) +                .build(); +        assertThat(tile.getContactAffinity()).isEqualTo(1f); +    } + +    @Test      public void testStatuses() {          PeopleSpaceTile tile = new PeopleSpaceTile.Builder(                  new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps).build(); @@ -238,6 +306,11 @@ public class PeopleSpaceTileTest {                  .setNotificationDataUri(Uri.parse("data"))                  .setMessagesCount(2)                  .setIntent(new Intent()) +                .setIsUserQuieted(true) +                .setCanBypassDnd(false) +                .setNotificationPolicyState(SHOW_IMPORTANT_CONVERSATIONS) +                .setIsPackageSuspended(true) +                .setContactAffinity(1f)                  .build();          Parcel parcel = Parcel.obtain(); @@ -261,6 +334,12 @@ public class PeopleSpaceTileTest {          assertThat(readTile.getNotificationDataUri()).isEqualTo(tile.getNotificationDataUri());          assertThat(readTile.getMessagesCount()).isEqualTo(tile.getMessagesCount());          assertThat(readTile.getIntent().toString()).isEqualTo(tile.getIntent().toString()); +        assertThat(readTile.isUserQuieted()).isEqualTo(tile.isUserQuieted()); +        assertThat(readTile.canBypassDnd()).isEqualTo(tile.canBypassDnd()); +        assertThat(readTile.getNotificationPolicyState()).isEqualTo( +                tile.getNotificationPolicyState()); +        assertThat(readTile.isPackageSuspended()).isEqualTo(tile.isPackageSuspended()); +        assertThat(readTile.getContactAffinity()).isEqualTo(tile.getContactAffinity());      }      @Test diff --git a/core/tests/coretests/src/android/colormodel/CamTest.java b/core/tests/coretests/src/android/colormodel/CamTest.java new file mode 100644 index 000000000000..a70ecd720dde --- /dev/null +++ b/core/tests/coretests/src/android/colormodel/CamTest.java @@ -0,0 +1,196 @@ +/* + * 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.graphics.cam; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public final class CamTest { +    static final int BLACK = 0xff000000; +    static final int WHITE = 0xffffffff; +    static final int MIDGRAY = 0xff777777; + +    static final int RED = 0xffff0000; +    static final int GREEN = 0xff00ff00; +    static final int BLUE = 0xff0000ff; + +    @Test +    public void camFromIntToInt() { +        Cam cam = Cam.fromInt(RED); +        int color = cam.viewed(Frame.DEFAULT); +        assertEquals(color, RED); +    } + +    @Test +    public void yFromMidgray() { +        assertEquals(18.418f, CamUtils.yFromLstar(50.0f), 0.001); +    } + +    @Test +    public void yFromBlack() { +        assertEquals(0.0f, CamUtils.yFromLstar(0.0f), 0.001); +    } + +    @Test +    public void yFromWhite() { +        assertEquals(100.0f, CamUtils.yFromLstar(100.0f), 0.001); +    } + +    @Test +    public void camFromRed() { +        Cam cam = Cam.fromInt(RED); +        assertEquals(46.445f, cam.getJ(), 0.001f); +        assertEquals(113.357f, cam.getChroma(), 0.001f); +        assertEquals(27.408f, cam.getHue(), 0.001f); +        assertEquals(89.494f, cam.getM(), 0.001f); +        assertEquals(91.889f, cam.getS(), 0.001f); +        assertEquals(105.988f, cam.getQ(), 0.001f); +    } + +    @Test +    public void camFromGreen() { +        Cam cam = Cam.fromInt(GREEN); +        assertEquals(79.331f, cam.getJ(), 0.001f); +        assertEquals(108.409f, cam.getChroma(), 0.001f); +        assertEquals(142.139f, cam.getHue(), 0.001f); +        assertEquals(85.587f, cam.getM(), 0.001f); +        assertEquals(78.604f, cam.getS(), 0.001f); +        assertEquals(138.520, cam.getQ(), 0.001f); +    } + +    @Test +    public void camFromBlue() { +        Cam cam = Cam.fromInt(BLUE); +        assertEquals(25.465f, cam.getJ(), 0.001f); +        assertEquals(87.230f, cam.getChroma(), 0.001f); +        assertEquals(282.788f, cam.getHue(), 0.001f); +        assertEquals(68.867f, cam.getM(), 0.001f); +        assertEquals(93.674f, cam.getS(), 0.001f); +        assertEquals(78.481f, cam.getQ(), 0.001f); +    } + +    @Test +    public void camFromBlack() { +        Cam cam = Cam.fromInt(BLACK); +        assertEquals(0.0f, cam.getJ(), 0.001f); +        assertEquals(0.0f, cam.getChroma(), 0.001f); +        assertEquals(0.0f, cam.getHue(), 0.001f); +        assertEquals(0.0f, cam.getM(), 0.001f); +        assertEquals(0.0f, cam.getS(), 0.001f); +        assertEquals(0.0f, cam.getQ(), 0.001f); +    } + +    @Test +    public void camFromWhite() { +        Cam cam = Cam.fromInt(WHITE); +        assertEquals(100.0f, cam.getJ(), 0.001f); +        assertEquals(2.869f, cam.getChroma(), 0.001f); +        assertEquals(209.492f, cam.getHue(), 0.001f); +        assertEquals(2.265f, cam.getM(), 0.001f); +        assertEquals(12.068f, cam.getS(), 0.001f); +        assertEquals(155.521, cam.getQ(), 0.001f); +    } + +    @Test +    public void getRedFromGamutMap() { +        int colorToTest = RED; +        Cam cam = Cam.fromInt(colorToTest); +        int color = Cam.getInt(cam.getHue(), cam.getChroma(), CamUtils.lstarFromInt(colorToTest)); +        assertEquals(colorToTest, color); +    } + +    @Test +    public void getGreenFromGamutMap() { +        int colorToTest = GREEN; +        Cam cam = Cam.fromInt(colorToTest); +        int color = Cam.getInt(cam.getHue(), cam.getChroma(), CamUtils.lstarFromInt(colorToTest)); +        assertEquals(colorToTest, color); +    } + +    @Test +    public void getBlueFromGamutMap() { +        int colorToTest = BLUE; +        Cam cam = Cam.fromInt(colorToTest); +        int color = Cam.getInt(cam.getHue(), cam.getChroma(), CamUtils.lstarFromInt(colorToTest)); +        assertEquals(colorToTest, color); +    } + +    @Test +    public void getWhiteFromGamutMap() { +        int colorToTest = WHITE; +        Cam cam = Cam.fromInt(colorToTest); +        int color = Cam.getInt(cam.getHue(), cam.getChroma(), CamUtils.lstarFromInt(colorToTest)); +        assertEquals(colorToTest, color); +    } + +    @Test +    public void getBlackFromGamutMap() { +        int colorToTest = BLACK; +        Cam cam = Cam.fromInt(colorToTest); +        int color = Cam.getInt(cam.getHue(), cam.getChroma(), CamUtils.lstarFromInt(colorToTest)); +        assertEquals(colorToTest, color); +    } + +    @Test +    public void getMidgrayFromGamutMap() { +        int colorToTest = MIDGRAY; +        Cam cam = Cam.fromInt(colorToTest); +        int color = Cam.getInt(cam.getHue(), cam.getChroma(), CamUtils.lstarFromInt(colorToTest)); +        assertEquals(colorToTest, color); +    } + +    @Test +    public void getRandomGreenFromGamutMap() { +        int colorToTest = 0xff009200; +        Cam cam = Cam.fromInt(colorToTest); +        int color = Cam.getInt(cam.getHue(), cam.getChroma(), CamUtils.lstarFromInt(colorToTest)); +        assertEquals(colorToTest, color); +    } + +    @Test +    public void gamutMapArbitraryHCL() { +        int color = Cam.getInt(309.0f, 40.0f, 70.0f); +        Cam cam = Cam.fromInt(color); + +        assertEquals(308.759f, cam.getHue(), 0.001); +        assertEquals(40.148f, cam.getChroma(), 0.001); +        assertEquals(70.029f, CamUtils.lstarFromInt(color), 0.001f); +    } + +    @Test +    public void ucsCoordinates() { +        Cam cam = Cam.fromInt(RED); + +        assertEquals(59.584f, cam.getJstar(), 0.001f); +        assertEquals(43.297f, cam.getAstar(), 0.001f); +        assertEquals(22.451f, cam.getBstar(), 0.001f); +    } + +    @Test +    public void deltaEWhiteToBlack() { +        assertEquals(25.661f, Cam.fromInt(WHITE).distance(Cam.fromInt(BLACK)), 0.001f); +    } + +    @Test +    public void deltaERedToBlue() { +        assertEquals(21.415f, Cam.fromInt(RED).distance(Cam.fromInt(BLUE)), 0.001f); +    } +} diff --git a/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java index 236c3daac272..4a5528d2ca36 100644 --- a/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java @@ -19,7 +19,6 @@ package com.android.internal.os;  import static com.google.common.truth.Truth.assertThat;  import android.os.BatteryConsumer; -import android.os.SystemBatteryConsumer;  import android.view.Display;  import androidx.test.filters.SmallTest; @@ -62,15 +61,13 @@ public class AmbientDisplayPowerCalculatorTest {          mStatsRule.apply(calculator); -        SystemBatteryConsumer consumer = -                mStatsRule.getSystemBatteryConsumer( -                        SystemBatteryConsumer.DRAIN_TYPE_AMBIENT_DISPLAY); -        assertThat(consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN)) +        BatteryConsumer consumer = mStatsRule.getDeviceBatteryConsumer(); +        assertThat(consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY))                  .isEqualTo(90 * MINUTE_IN_MS);          // 100,000,00 uC / 1000 (micro-/milli-) / 360 (seconds/hour) = 27.777778 mAh -        assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN)) +        assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY))                  .isWithin(PRECISION).of(27.777778); -        assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN)) +        assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY))                  .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);      } @@ -88,14 +85,12 @@ public class AmbientDisplayPowerCalculatorTest {          mStatsRule.apply(BatteryUsageStatsRule.POWER_PROFILE_MODEL_ONLY, calculator); -        SystemBatteryConsumer consumer = -                mStatsRule.getSystemBatteryConsumer( -                        SystemBatteryConsumer.DRAIN_TYPE_AMBIENT_DISPLAY); -        assertThat(consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN)) +        BatteryConsumer consumer = mStatsRule.getDeviceBatteryConsumer(); +        assertThat(consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY))                  .isEqualTo(90 * MINUTE_IN_MS); -        assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN)) +        assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY))                  .isWithin(PRECISION).of(15.0); -        assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN)) +        assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY))                  .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);      }  } diff --git a/core/tests/coretests/src/com/android/internal/os/AudioPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/AudioPowerCalculatorTest.java index c694d67cd97b..81940edaed6a 100644 --- a/core/tests/coretests/src/com/android/internal/os/AudioPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/AudioPowerCalculatorTest.java @@ -56,5 +56,19 @@ public class AudioPowerCalculatorTest {                  .isEqualTo(1000);          assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_AUDIO))                  .isWithin(PRECISION).of(0.1); + +        final BatteryConsumer deviceBatteryConsumer = mStatsRule.getDeviceBatteryConsumer(); +        assertThat(deviceBatteryConsumer +                .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_AUDIO)) +                .isEqualTo(1000); +        assertThat(deviceBatteryConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_AUDIO)) +                .isWithin(PRECISION).of(0.1); + +        final BatteryConsumer appsBatteryConsumer = mStatsRule.getDeviceBatteryConsumer(); +        assertThat(appsBatteryConsumer +                .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_AUDIO)) +                .isEqualTo(1000); +        assertThat(appsBatteryConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_AUDIO)) +                .isWithin(PRECISION).of(0.1);      }  } diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryChargeCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryChargeCalculatorTest.java index cf126c62dac7..23fc35d6ffa5 100644 --- a/core/tests/coretests/src/com/android/internal/os/BatteryChargeCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BatteryChargeCalculatorTest.java @@ -36,18 +36,12 @@ public class BatteryChargeCalculatorTest {      @Rule      public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule() -            .setAveragePower(PowerProfile.POWER_BATTERY_CAPACITY, 4000.0); +            .setAveragePower(PowerProfile.POWER_BATTERY_CAPACITY, 1234.0); // Should be ignored      @Test      public void testDischargeTotals() { -        BatteryChargeCalculator calculator = -                new BatteryChargeCalculator(mStatsRule.getPowerProfile()); -          final BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats(); -        mStatsRule.setTime(1000, 1000); -        batteryStats.resetAllStatsCmdLocked(); -        batteryStats.setNoAutoReset(true);          batteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING, 100,                  /* plugType */ 0, 90, 72, 3700, 3_600_000, 4_000_000, 0,                  1_000_000, 1_000_000, 1_000_000); @@ -58,8 +52,11 @@ public class BatteryChargeCalculatorTest {                  /* plugType */ 0, 80, 72, 3700, 2_400_000, 4_000_000, 0,                  2_000_000, 2_000_000, 2_000_000); +        BatteryChargeCalculator calculator = new BatteryChargeCalculator();          BatteryUsageStats batteryUsageStats = mStatsRule.apply(calculator); +        assertThat(batteryUsageStats.getConsumedPower()) +                .isWithin(PRECISION).of(380.0);          assertThat(batteryUsageStats.getDischargePercentage()).isEqualTo(10);          assertThat(batteryUsageStats.getDischargedPowerRange().getLower())                  .isWithin(PRECISION).of(360.0); diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java index 41fe372d5d9c..1a6408ff7eb3 100644 --- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java +++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java @@ -23,10 +23,10 @@ import static org.mockito.Mockito.when;  import android.content.Context;  import android.net.NetworkStats; +import android.os.BatteryConsumer;  import android.os.BatteryStats;  import android.os.BatteryUsageStats;  import android.os.BatteryUsageStatsQuery; -import android.os.SystemBatteryConsumer;  import android.os.UidBatteryConsumer;  import android.os.UserBatteryConsumer;  import android.util.SparseArray; @@ -186,6 +186,16 @@ public class BatteryUsageStatsRule implements TestRule {          return mBatteryUsageStats;      } +    public BatteryConsumer getDeviceBatteryConsumer() { +        return mBatteryUsageStats.getAggregateBatteryConsumer( +                BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE); +    } + +    public BatteryConsumer getAppsBatteryConsumer() { +        return mBatteryUsageStats.getAggregateBatteryConsumer( +                BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS); +    } +      public UidBatteryConsumer getUidBatteryConsumer(int uid) {          for (UidBatteryConsumer ubc : mBatteryUsageStats.getUidBatteryConsumers()) {              if (ubc.getUid() == uid) { @@ -195,16 +205,6 @@ public class BatteryUsageStatsRule implements TestRule {          return null;      } -    public SystemBatteryConsumer getSystemBatteryConsumer( -            @SystemBatteryConsumer.DrainType int drainType) { -        for (SystemBatteryConsumer sbc : mBatteryUsageStats.getSystemBatteryConsumers()) { -            if (sbc.getDrainType() == drainType) { -                return sbc; -            } -        } -        return null; -    } -      public UserBatteryConsumer getUserBatteryConsumer(int userId) {          for (UserBatteryConsumer ubc : mBatteryUsageStats.getUserBatteryConsumers()) {              if (ubc.getUserId() == userId) { diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java index 55302bcf3b8d..127cea84ba8c 100644 --- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java @@ -23,7 +23,6 @@ import static org.junit.Assert.fail;  import android.os.BatteryConsumer;  import android.os.BatteryUsageStats;  import android.os.Parcel; -import android.os.SystemBatteryConsumer;  import android.os.UidBatteryConsumer;  import androidx.test.filters.SmallTest; @@ -71,7 +70,6 @@ public class BatteryUsageStatsTest {                          .setDischargePercentage(20)                          .setDischargedPowerRange(1000, 2000)                          .setStatsStartTimestamp(1000); -          builder.getOrCreateUidBatteryConsumerBuilder(batteryStatsUid)                  .setPackageWithHighestDrain("foo")                  .setTimeInStateMs(UidBatteryConsumer.STATE_FOREGROUND, 1000) @@ -87,7 +85,8 @@ public class BatteryUsageStatsTest {                  .setUsageDurationForCustomComponentMillis(                          BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 800); -        builder.getOrCreateSystemBatteryConsumerBuilder(SystemBatteryConsumer.DRAIN_TYPE_CAMERA) +        builder.getAggregateBatteryConsumerBuilder( +                BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS)                  .setConsumedPower(                          BatteryConsumer.POWER_COMPONENT_CPU, 10100)                  .setConsumedPowerForCustomComponent( @@ -95,17 +94,25 @@ public class BatteryUsageStatsTest {                  .setUsageDurationMillis(                          BatteryConsumer.POWER_COMPONENT_CPU, 10300)                  .setUsageDurationForCustomComponentMillis( -                        BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 10400) -                .setPowerConsumedByApps(20000); +                        BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 10400); + +        builder.getAggregateBatteryConsumerBuilder( +                BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE) +                .setConsumedPower(30000) +                .setConsumedPower( +                        BatteryConsumer.POWER_COMPONENT_CPU, 20100) +                .setConsumedPowerForCustomComponent( +                        BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 20200) +                .setUsageDurationMillis( +                        BatteryConsumer.POWER_COMPONENT_CPU, 20300) +                .setUsageDurationForCustomComponentMillis( +                        BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 20400);          return builder.build();      }      public void validateBatteryUsageStats(BatteryUsageStats batteryUsageStats) { -        // Camera: (10100 + 10200) - 20000 (consumed by apps) = 300 -        // App: 300 + 400 + 500 = 1200 -        // Total: 1500 -        assertThat(batteryUsageStats.getConsumedPower()).isEqualTo(1500); +        assertThat(batteryUsageStats.getConsumedPower()).isEqualTo(30000);          assertThat(batteryUsageStats.getDischargePercentage()).isEqualTo(20);          assertThat(batteryUsageStats.getDischargedPowerRange().getLower()).isEqualTo(1000);          assertThat(batteryUsageStats.getDischargedPowerRange().getUpper()).isEqualTo(2000); @@ -139,28 +146,32 @@ public class BatteryUsageStatsTest {              }          } -        final List<SystemBatteryConsumer> systemBatteryConsumers = -                batteryUsageStats.getSystemBatteryConsumers(); -        for (SystemBatteryConsumer systemBatteryConsumer : systemBatteryConsumers) { -            if (systemBatteryConsumer.getDrainType() == SystemBatteryConsumer.DRAIN_TYPE_CAMERA) { -                assertThat(systemBatteryConsumer.getConsumedPower( -                        BatteryConsumer.POWER_COMPONENT_CPU)).isEqualTo(10100); -                assertThat(systemBatteryConsumer.getConsumedPowerForCustomComponent( -                        BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID)).isEqualTo(10200); -                assertThat(systemBatteryConsumer.getUsageDurationMillis( -                        BatteryConsumer.POWER_COMPONENT_CPU)).isEqualTo(10300); -                assertThat(systemBatteryConsumer.getUsageDurationForCustomComponentMillis( -                        BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID)).isEqualTo(10400); -                assertThat(systemBatteryConsumer.getConsumedPower()).isEqualTo(20300); -                assertThat(systemBatteryConsumer.getPowerConsumedByApps()).isEqualTo(20000); -                assertThat(systemBatteryConsumer.getUsageDurationMillis()) -                        .isEqualTo(10400); // max -                assertThat(systemBatteryConsumer.getCustomPowerComponentCount()).isEqualTo(1); -                assertThat(systemBatteryConsumer.getCustomPowerComponentName( -                        BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID)).isEqualTo("FOO"); -            } else { -                fail("Unexpected drain type " + systemBatteryConsumer.getDrainType()); -            } -        } +        final BatteryConsumer appsBatteryConsumer = batteryUsageStats.getAggregateBatteryConsumer( +                BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS); +        assertThat(appsBatteryConsumer.getConsumedPower( +                BatteryConsumer.POWER_COMPONENT_CPU)).isEqualTo(10100); +        assertThat(appsBatteryConsumer.getConsumedPowerForCustomComponent( +                BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID)).isEqualTo(10200); +        assertThat(appsBatteryConsumer.getUsageDurationMillis( +                BatteryConsumer.POWER_COMPONENT_CPU)).isEqualTo(10300); +        assertThat(appsBatteryConsumer.getUsageDurationForCustomComponentMillis( +                BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID)).isEqualTo(10400); +        assertThat(appsBatteryConsumer.getCustomPowerComponentCount()).isEqualTo(1); +        assertThat(appsBatteryConsumer.getCustomPowerComponentName( +                BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID)).isEqualTo("FOO"); + +        final BatteryConsumer deviceBatteryConsumer = batteryUsageStats.getAggregateBatteryConsumer( +                BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE); +        assertThat(deviceBatteryConsumer.getConsumedPower( +                BatteryConsumer.POWER_COMPONENT_CPU)).isEqualTo(20100); +        assertThat(deviceBatteryConsumer.getConsumedPowerForCustomComponent( +                BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID)).isEqualTo(20200); +        assertThat(deviceBatteryConsumer.getUsageDurationMillis( +                BatteryConsumer.POWER_COMPONENT_CPU)).isEqualTo(20300); +        assertThat(deviceBatteryConsumer.getUsageDurationForCustomComponentMillis( +                BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID)).isEqualTo(20400); +        assertThat(deviceBatteryConsumer.getCustomPowerComponentCount()).isEqualTo(1); +        assertThat(deviceBatteryConsumer.getCustomPowerComponentName( +                BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID)).isEqualTo("FOO");      }  } diff --git a/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java index 8723195ab6fe..2de621c8fa6f 100644 --- a/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java @@ -24,7 +24,6 @@ import android.bluetooth.UidTraffic;  import android.os.BatteryConsumer;  import android.os.BatteryUsageStatsQuery;  import android.os.Process; -import android.os.SystemBatteryConsumer;  import androidx.test.filters.SmallTest;  import androidx.test.runner.AndroidJUnit4; @@ -65,13 +64,18 @@ public class BluetoothPowerCalculatorTest {          mStatsRule.apply(BatteryUsageStatsRule.POWER_PROFILE_MODEL_ONLY, calculator); -        assertThat(mStatsRule.getUidBatteryConsumer(Process.BLUETOOTH_UID)).isNull(); +        assertBluetoothPowerAndDuration( +                mStatsRule.getUidBatteryConsumer(Process.BLUETOOTH_UID), +                0.11388, 6000, BatteryConsumer.POWER_MODEL_POWER_PROFILE);          assertBluetoothPowerAndDuration(                  mStatsRule.getUidBatteryConsumer(APP_UID),                  0.24722, 15000, BatteryConsumer.POWER_MODEL_POWER_PROFILE);          assertBluetoothPowerAndDuration( -                mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_BLUETOOTH), -                0.51944, 9000, 0.51944, 0.36111, BatteryConsumer.POWER_MODEL_POWER_PROFILE); +                mStatsRule.getDeviceBatteryConsumer(), +                0.40555, 24000, BatteryConsumer.POWER_MODEL_POWER_PROFILE); +        assertBluetoothPowerAndDuration( +                mStatsRule.getAppsBatteryConsumer(), +                0.36111, 21000, BatteryConsumer.POWER_MODEL_POWER_PROFILE);      }      @Test @@ -93,13 +97,18 @@ public class BluetoothPowerCalculatorTest {          mStatsRule.apply(BatteryUsageStatsRule.POWER_PROFILE_MODEL_ONLY, calculator); -        assertThat(mStatsRule.getUidBatteryConsumer(Process.BLUETOOTH_UID)).isNull(); +        assertBluetoothPowerAndDuration( +                mStatsRule.getUidBatteryConsumer(Process.BLUETOOTH_UID), +                0.1, 6000, BatteryConsumer.POWER_MODEL_POWER_PROFILE);          assertBluetoothPowerAndDuration(                  mStatsRule.getUidBatteryConsumer(APP_UID),                  0.2, 15000, BatteryConsumer.POWER_MODEL_POWER_PROFILE);          assertBluetoothPowerAndDuration( -                mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_BLUETOOTH), -                0.45, 9000, 0.45, 0.3, BatteryConsumer.POWER_MODEL_POWER_PROFILE); +                mStatsRule.getDeviceBatteryConsumer(), +                0.35, 24000, BatteryConsumer.POWER_MODEL_POWER_PROFILE); +        assertBluetoothPowerAndDuration( +                mStatsRule.getAppsBatteryConsumer(), +                0.3, 21000, BatteryConsumer.POWER_MODEL_POWER_PROFILE);      }      @Test @@ -118,13 +127,18 @@ public class BluetoothPowerCalculatorTest {          mStatsRule.apply(new BatteryUsageStatsQuery.Builder().includePowerModels().build(),                  calculator); -        assertThat(mStatsRule.getUidBatteryConsumer(Process.BLUETOOTH_UID)).isNull(); +        assertBluetoothPowerAndDuration( +                mStatsRule.getUidBatteryConsumer(Process.BLUETOOTH_UID), +                0.10378, 3583, BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);          assertBluetoothPowerAndDuration(                  mStatsRule.getUidBatteryConsumer(APP_UID),                  0.22950, 8416, BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);          assertBluetoothPowerAndDuration( -                mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_BLUETOOTH), -                0.43712, 3584, 0.43712, 0.33329, BatteryConsumer.POWER_MODEL_MEASURED_ENERGY); +                mStatsRule.getDeviceBatteryConsumer(), +                0.33333, 12000, BatteryConsumer.POWER_MODEL_MEASURED_ENERGY); +        assertBluetoothPowerAndDuration( +                mStatsRule.getAppsBatteryConsumer(), +                0.33329, 11999, BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);      }      private void setDurationsAndPower( @@ -151,16 +165,4 @@ public class BluetoothPowerCalculatorTest {          assertThat(usageDurationMillis).isEqualTo(durationMs);      } - -    private void assertBluetoothPowerAndDuration(@Nullable SystemBatteryConsumer batteryConsumer, -            double powerMah, int durationMs, double consumedPower, double attributedPower, -            @BatteryConsumer.PowerModel int powerModel) { -        assertBluetoothPowerAndDuration(batteryConsumer, powerMah, durationMs, powerModel); - -        assertThat(batteryConsumer.getConsumedPower()) -                .isWithin(PRECISION).of(consumedPower); - -        assertThat(batteryConsumer.getPowerConsumedByApps()) -                .isWithin(PRECISION).of(attributedPower); -    }  } diff --git a/core/tests/coretests/src/com/android/internal/os/CameraPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/CameraPowerCalculatorTest.java index 61eb173837e8..c40d8a0138c1 100644 --- a/core/tests/coretests/src/com/android/internal/os/CameraPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/CameraPowerCalculatorTest.java @@ -42,9 +42,9 @@ public class CameraPowerCalculatorTest {      @Test      public void testTimerBasedModel() { -        BatteryStatsImpl.Uid uidStats = mStatsRule.getUidStats(APP_UID); -        uidStats.noteCameraTurnedOnLocked(1000); -        uidStats.noteCameraTurnedOffLocked(2000); +        BatteryStatsImpl stats = mStatsRule.getBatteryStats(); +        stats.noteCameraOnLocked(APP_UID, 1000, 1000); +        stats.noteCameraOffLocked(APP_UID, 2000, 2000);          CameraPowerCalculator calculator =                  new CameraPowerCalculator(mStatsRule.getPowerProfile()); @@ -56,5 +56,19 @@ public class CameraPowerCalculatorTest {                  .isEqualTo(1000);          assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA))                  .isWithin(PRECISION).of(0.1); + +        final BatteryConsumer deviceBatteryConsumer = mStatsRule.getDeviceBatteryConsumer(); +        assertThat(deviceBatteryConsumer +                .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CAMERA)) +                .isEqualTo(1000); +        assertThat(deviceBatteryConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA)) +                .isWithin(PRECISION).of(0.1); + +        final BatteryConsumer appsBatteryConsumer = mStatsRule.getAppsBatteryConsumer(); +        assertThat(appsBatteryConsumer +                .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CAMERA)) +                .isEqualTo(1000); +        assertThat(appsBatteryConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA)) +                .isWithin(PRECISION).of(0.1);      }  } diff --git a/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java index 1a99fb0fd40f..152d246bc372 100644 --- a/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java @@ -160,6 +160,18 @@ public class CpuPowerCalculatorTest {          assertThat(uidConsumer2.getPowerModel(BatteryConsumer.POWER_COMPONENT_CPU))                  .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);          assertThat(uidConsumer2.getPackageWithHighestDrain()).isNull(); + +        final BatteryConsumer deviceBatteryConsumer = mStatsRule.getDeviceBatteryConsumer(); +        assertThat(deviceBatteryConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU)) +                .isWithin(PRECISION).of(3.76455); +        assertThat(deviceBatteryConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_CPU)) +                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE); + +        final BatteryConsumer appsBatteryConsumer = mStatsRule.getAppsBatteryConsumer(); +        assertThat(appsBatteryConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU)) +                .isWithin(PRECISION).of(3.76455); +        assertThat(appsBatteryConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_CPU)) +                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);      }      @Test @@ -224,5 +236,17 @@ public class CpuPowerCalculatorTest {          assertThat(uidConsumer2.getPowerModel(BatteryConsumer.POWER_COMPONENT_CPU))                  .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);          assertThat(uidConsumer2.getPackageWithHighestDrain()).isNull(); + +        final BatteryConsumer deviceBatteryConsumer = mStatsRule.getDeviceBatteryConsumer(); +        assertThat(deviceBatteryConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU)) +                .isWithin(PRECISION).of(10.62949); +        assertThat(deviceBatteryConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_CPU)) +                .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY); + +        final BatteryConsumer appsBatteryConsumer = mStatsRule.getDeviceBatteryConsumer(); +        assertThat(appsBatteryConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU)) +                .isWithin(PRECISION).of(10.62949); +        assertThat(appsBatteryConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_CPU)) +                .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);      }  } diff --git a/core/tests/coretests/src/com/android/internal/os/CustomMeasuredPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/CustomMeasuredPowerCalculatorTest.java index f0111171b83c..f8c2bc6c3d80 100644 --- a/core/tests/coretests/src/com/android/internal/os/CustomMeasuredPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/CustomMeasuredPowerCalculatorTest.java @@ -20,7 +20,6 @@ import static com.google.common.truth.Truth.assertThat;  import android.os.BatteryConsumer;  import android.os.Process; -import android.os.SystemBatteryConsumer;  import android.os.UidBatteryConsumer;  import android.util.SparseLongArray; @@ -68,12 +67,19 @@ public class CustomMeasuredPowerCalculatorTest {                  BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID + 1))                  .isWithin(PRECISION).of(33.33333); -        SystemBatteryConsumer systemConsumer = mStatsRule.getSystemBatteryConsumer( -                SystemBatteryConsumer.DRAIN_TYPE_CUSTOM); -        assertThat(systemConsumer.getConsumedPowerForCustomComponent( +        final BatteryConsumer deviceBatteryConsumer = mStatsRule.getDeviceBatteryConsumer(); +        assertThat(deviceBatteryConsumer.getConsumedPowerForCustomComponent(                  BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID))                  .isWithin(PRECISION).of(27.77777); -        assertThat(systemConsumer.getConsumedPowerForCustomComponent( +        assertThat(deviceBatteryConsumer.getConsumedPowerForCustomComponent( +                BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID + 1)) +                .isWithin(PRECISION).of(55.55555); + +        final BatteryConsumer appsBatteryConsumer = mStatsRule.getDeviceBatteryConsumer(); +        assertThat(appsBatteryConsumer.getConsumedPowerForCustomComponent( +                BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID)) +                .isWithin(PRECISION).of(27.77777); +        assertThat(appsBatteryConsumer.getConsumedPowerForCustomComponent(                  BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID + 1))                  .isWithin(PRECISION).of(55.55555);      } diff --git a/core/tests/coretests/src/com/android/internal/os/GnssPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/GnssPowerCalculatorTest.java index 7ea799ff5173..196443056d32 100644 --- a/core/tests/coretests/src/com/android/internal/os/GnssPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/GnssPowerCalculatorTest.java @@ -62,6 +62,18 @@ public class GnssPowerCalculatorTest {                  .isWithin(PRECISION).of(0.1);          assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_GNSS))                  .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE); + +        BatteryConsumer deviceConsumer = mStatsRule.getDeviceBatteryConsumer(); +        assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_GNSS)) +                .isWithin(PRECISION).of(0.1); +        assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_GNSS)) +                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE); + +        BatteryConsumer appsConsumer = mStatsRule.getAppsBatteryConsumer(); +        assertThat(appsConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_GNSS)) +                .isWithin(PRECISION).of(0.1); +        assertThat(appsConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_GNSS)) +                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);      }      @Test @@ -97,5 +109,17 @@ public class GnssPowerCalculatorTest {                  .isWithin(PRECISION).of(5.55555);          assertThat(consumer2.getPowerModel(BatteryConsumer.POWER_COMPONENT_GNSS))                  .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY); + +        BatteryConsumer deviceConsumer = mStatsRule.getDeviceBatteryConsumer(); +        assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_GNSS)) +                .isWithin(PRECISION).of(8.333333); +        assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_GNSS)) +                .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY); + +        BatteryConsumer appsConsumer = mStatsRule.getAppsBatteryConsumer(); +        assertThat(appsConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_GNSS)) +                .isWithin(PRECISION).of(8.333333); +        assertThat(appsConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_GNSS)) +                .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);      }  } diff --git a/core/tests/coretests/src/com/android/internal/os/IdlePowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/IdlePowerCalculatorTest.java index 2331eebf6dd1..67b1e516d704 100644 --- a/core/tests/coretests/src/com/android/internal/os/IdlePowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/IdlePowerCalculatorTest.java @@ -19,7 +19,6 @@ package com.android.internal.os;  import static com.google.common.truth.Truth.assertThat;  import android.os.BatteryConsumer; -import android.os.SystemBatteryConsumer;  import androidx.test.filters.SmallTest;  import androidx.test.runner.AndroidJUnit4; @@ -46,11 +45,16 @@ public class IdlePowerCalculatorTest {          mStatsRule.apply(calculator); -        SystemBatteryConsumer consumer = -                mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_IDLE); -        assertThat(consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_IDLE)) +        BatteryConsumer deviceConsumer = mStatsRule.getDeviceBatteryConsumer(); +        assertThat(deviceConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_IDLE))                  .isEqualTo(3000); -        assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_IDLE)) +        assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_IDLE))                  .isWithin(PRECISION).of(0.7); + +        BatteryConsumer appsConsumer = mStatsRule.getAppsBatteryConsumer(); +        assertThat(appsConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_IDLE)) +                .isEqualTo(0); +        assertThat(appsConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_IDLE)) +                .isWithin(PRECISION).of(0);      }  } diff --git a/core/tests/coretests/src/com/android/internal/os/MemoryPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/MemoryPowerCalculatorTest.java index 94e760a4e2e2..4868d6a87228 100644 --- a/core/tests/coretests/src/com/android/internal/os/MemoryPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/MemoryPowerCalculatorTest.java @@ -19,7 +19,6 @@ package com.android.internal.os;  import static com.google.common.truth.Truth.assertThat;  import android.os.BatteryConsumer; -import android.os.SystemBatteryConsumer;  import androidx.test.filters.SmallTest;  import androidx.test.runner.AndroidJUnit4; @@ -53,8 +52,7 @@ public class MemoryPowerCalculatorTest {          mStatsRule.apply(calculator); -        SystemBatteryConsumer consumer = -                mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_MEMORY); +        BatteryConsumer consumer = mStatsRule.getDeviceBatteryConsumer();          assertThat(consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_MEMORY))                  .isEqualTo(3000);          assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MEMORY)) diff --git a/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java index 5b84a1b320c7..48a1da15d574 100644 --- a/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java @@ -27,7 +27,6 @@ import android.net.NetworkCapabilities;  import android.net.NetworkStats;  import android.os.BatteryConsumer;  import android.os.Process; -import android.os.SystemBatteryConsumer;  import android.os.UidBatteryConsumer;  import android.telephony.DataConnectionRealTimeInfo;  import android.telephony.ModemActivityInfo; @@ -100,22 +99,23 @@ public class MobileRadioPowerCalculatorTest {          mStatsRule.apply(BatteryUsageStatsRule.POWER_PROFILE_MODEL_ONLY, calculator); -        SystemBatteryConsumer consumer = -                mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_MOBILE_RADIO); -        assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO)) -                .isWithin(PRECISION).of(2.2444); -        assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO)) -                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE); -        assertThat(consumer.getConsumedPower()) -                .isWithin(PRECISION).of(2.2444); -        assertThat(consumer.getPowerConsumedByApps()) -                .isWithin(PRECISION).of(0.8); -          UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);          assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))                  .isWithin(PRECISION).of(0.8);          assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))                  .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE); + +        BatteryConsumer deviceConsumer = mStatsRule.getDeviceBatteryConsumer(); +        assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO)) +                .isWithin(PRECISION).of(2.2444); +        assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO)) +                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE); + +        BatteryConsumer appsConsumer = mStatsRule.getAppsBatteryConsumer(); +        assertThat(appsConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO)) +                .isWithin(PRECISION).of(0.8); +        assertThat(appsConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO)) +                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);      }      @Test @@ -159,21 +159,22 @@ public class MobileRadioPowerCalculatorTest {          mStatsRule.apply(calculator); -        SystemBatteryConsumer consumer = -                mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_MOBILE_RADIO); +        UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID); +        assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO)) +                .isWithin(PRECISION).of(1.53934); +        assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO)) +                .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY); -        // 100000000 uAs * (1 mA / 1000 uA) * (1 h / 3600 s) + 1.53934 (apps)= 4.31711 mAh -        assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO)) +        BatteryConsumer deviceConsumer = mStatsRule.getDeviceBatteryConsumer(); +        assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))                  .isWithin(PRECISION).of(4.31711); -        assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO)) +        assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))                  .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY); -        assertThat(consumer.getPowerConsumedByApps()) -                .isWithin(PRECISION).of(1.53934); -        UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID); -        assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO)) +        BatteryConsumer appsConsumer = mStatsRule.getAppsBatteryConsumer(); +        assertThat(appsConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))                  .isWithin(PRECISION).of(1.53934); -        assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO)) +        assertThat(appsConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))                  .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);      }  } diff --git a/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java index 93c71068457e..4c29c204618a 100644 --- a/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java @@ -21,7 +21,6 @@ import static com.google.common.truth.Truth.assertThat;  import android.app.ActivityManager;  import android.os.BatteryConsumer;  import android.os.Process; -import android.os.SystemBatteryConsumer;  import android.os.UidBatteryConsumer;  import android.view.Display; @@ -82,21 +81,6 @@ public class ScreenPowerCalculatorTest {          mStatsRule.apply(calculator); -        SystemBatteryConsumer consumer = -                mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_SCREEN); -        assertThat(consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN)) -                .isEqualTo(80 * MINUTE_IN_MS); - -        // 600000000 uAs * (1 mA / 1000 uA) * (1 h / 3600 s)  = 166.66666 mAh -        assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN)) -                .isWithin(PRECISION).of(166.66666); -        assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN)) -                .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY); -        assertThat(consumer.getConsumedPower()) -                .isWithin(PRECISION).of(166.66666); -        assertThat(consumer.getPowerConsumedByApps()) -                .isWithin(PRECISION).of(166.66666); -          UidBatteryConsumer uid1 = mStatsRule.getUidBatteryConsumer(APP_UID1);          assertThat(uid1.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN))                  .isEqualTo(20 * MINUTE_IN_MS); @@ -120,6 +104,25 @@ public class ScreenPowerCalculatorTest {                  .isWithin(PRECISION).of(101.85185);          assertThat(uid2.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN))                  .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY); + +        BatteryConsumer deviceConsumer = mStatsRule.getDeviceBatteryConsumer(); +        assertThat(deviceConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN)) +                .isEqualTo(80 * MINUTE_IN_MS); + +        // 600000000 uAs * (1 mA / 1000 uA) * (1 h / 3600 s)  = 166.66666 mAh +        assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN)) +                .isWithin(PRECISION).of(166.66666); +        assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN)) +                .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY); + +        BatteryConsumer appsConsumer = mStatsRule.getAppsBatteryConsumer(); +        assertThat(appsConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN)) +                .isEqualTo(80 * MINUTE_IN_MS); + +        assertThat(appsConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN)) +                .isWithin(PRECISION).of(166.66666); +        assertThat(appsConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN)) +                .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);      }      @Test @@ -151,19 +154,6 @@ public class ScreenPowerCalculatorTest {          mStatsRule.apply(BatteryUsageStatsRule.POWER_PROFILE_MODEL_ONLY, calculator); -        SystemBatteryConsumer consumer = -                mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_SCREEN); -        assertThat(consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN)) -                .isEqualTo(80 * MINUTE_IN_MS); -        assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN)) -                .isWithin(PRECISION).of(92.0); -        assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN)) -                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE); -        assertThat(consumer.getConsumedPower()) -                .isWithin(PRECISION).of(92.0); -        assertThat(consumer.getPowerConsumedByApps()) -                .isWithin(PRECISION).of(92.0); -          UidBatteryConsumer uid1 = mStatsRule.getUidBatteryConsumer(APP_UID1);          assertThat(uid1.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN))                  .isEqualTo(20 * MINUTE_IN_MS); @@ -185,6 +175,22 @@ public class ScreenPowerCalculatorTest {                  .isWithin(PRECISION).of(69.0);          assertThat(uid2.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN))                  .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE); + +        BatteryConsumer deviceConsumer = mStatsRule.getDeviceBatteryConsumer(); +        assertThat(deviceConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN)) +                .isEqualTo(80 * MINUTE_IN_MS); +        assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN)) +                .isWithin(PRECISION).of(92); +        assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN)) +                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE); + +        BatteryConsumer appsConsumer = mStatsRule.getAppsBatteryConsumer(); +        assertThat(appsConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN)) +                .isEqualTo(80 * MINUTE_IN_MS); +        assertThat(appsConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN)) +                .isWithin(PRECISION).of(92); +        assertThat(appsConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN)) +                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);      }      private void setProcState(int uid, int procState, boolean resumed, long realtimeMs, diff --git a/core/tests/coretests/src/com/android/internal/os/SensorPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/SensorPowerCalculatorTest.java index 74235b28d43b..7563e3912766 100644 --- a/core/tests/coretests/src/com/android/internal/os/SensorPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/SensorPowerCalculatorTest.java @@ -59,11 +59,11 @@ public class SensorPowerCalculatorTest {          when(sensorManager.getSensorList(Sensor.TYPE_ALL))                  .thenReturn(List.of(sensor1, sensor2)); -        BatteryStatsImpl.Uid uidStats = mStatsRule.getUidStats(APP_UID); -        uidStats.noteStartSensor(SENSOR_HANDLE_1, 1000); -        uidStats.noteStopSensor(SENSOR_HANDLE_1, 2000); -        uidStats.noteStartSensor(SENSOR_HANDLE_2, 3000); -        uidStats.noteStopSensor(SENSOR_HANDLE_2, 5000); +        final BatteryStatsImpl stats = mStatsRule.getBatteryStats(); +        stats.noteStartSensorLocked(APP_UID, SENSOR_HANDLE_1, 1000, 1000); +        stats.noteStopSensorLocked(APP_UID, SENSOR_HANDLE_1, 2000, 2000); +        stats.noteStartSensorLocked(APP_UID, SENSOR_HANDLE_2, 3000, 3000); +        stats.noteStopSensorLocked(APP_UID, SENSOR_HANDLE_2, 5000, 5000);          SensorPowerCalculator calculator = new SensorPowerCalculator(sensorManager); @@ -74,6 +74,14 @@ public class SensorPowerCalculatorTest {                  .isEqualTo(3000);          assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SENSORS))                  .isWithin(PRECISION).of(0.5); + +        BatteryConsumer deviceConsumer = mStatsRule.getDeviceBatteryConsumer(); +        assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SENSORS)) +                .isWithin(PRECISION).of(0.5); + +        BatteryConsumer appsConsumer = mStatsRule.getDeviceBatteryConsumer(); +        assertThat(appsConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SENSORS)) +                .isWithin(PRECISION).of(0.5);      }      private Sensor createSensor(int handle, int type, double power) { diff --git a/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java index 58e2513897ac..cd45060b7cc4 100644 --- a/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java @@ -133,6 +133,12 @@ public class SystemServicePowerCalculatorTest {          assertThat(mStatsRule.getUidBatteryConsumer(Process.SYSTEM_UID)                  .getConsumedPower(BatteryConsumer.POWER_COMPONENT_REATTRIBUTED_TO_OTHER_CONSUMERS))                  .isWithin(PRECISION).of(-18.888888); +        assertThat(mStatsRule.getDeviceBatteryConsumer() +                .getConsumedPower(BatteryConsumer.POWER_COMPONENT_SYSTEM_SERVICES)) +                .isWithin(PRECISION).of(18.888888); +        assertThat(mStatsRule.getAppsBatteryConsumer() +                .getConsumedPower(BatteryConsumer.POWER_COMPONENT_SYSTEM_SERVICES)) +                .isWithin(PRECISION).of(18.888888);      }      private static class MockKernelCpuUidFreqTimeReader extends diff --git a/core/tests/coretests/src/com/android/internal/os/VideoPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/VideoPowerCalculatorTest.java index fa0dbc76d5c6..ae61d31e7af4 100644 --- a/core/tests/coretests/src/com/android/internal/os/VideoPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/VideoPowerCalculatorTest.java @@ -56,5 +56,19 @@ public class VideoPowerCalculatorTest {                  .isEqualTo(1000);          assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_VIDEO))                  .isWithin(PRECISION).of(0.1); + +        final BatteryConsumer deviceBatteryConsumer = mStatsRule.getDeviceBatteryConsumer(); +        assertThat(deviceBatteryConsumer +                .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_VIDEO)) +                .isEqualTo(1000); +        assertThat(deviceBatteryConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_VIDEO)) +                .isWithin(PRECISION).of(0.1); + +        final BatteryConsumer appsBatteryConsumer = mStatsRule.getDeviceBatteryConsumer(); +        assertThat(appsBatteryConsumer +                .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_VIDEO)) +                .isEqualTo(1000); +        assertThat(appsBatteryConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_VIDEO)) +                .isWithin(PRECISION).of(0.1);      }  } diff --git a/core/tests/coretests/src/com/android/internal/os/WakelockPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/WakelockPowerCalculatorTest.java index 9d3ed55a0729..82830f23fec3 100644 --- a/core/tests/coretests/src/com/android/internal/os/WakelockPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/WakelockPowerCalculatorTest.java @@ -72,5 +72,15 @@ public class WakelockPowerCalculatorTest {                  .isEqualTo(5000);          assertThat(osConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WAKELOCK))                  .isWithin(PRECISION).of(0.5); + +        BatteryConsumer deviceConsumer = mStatsRule.getDeviceBatteryConsumer(); +        assertThat(deviceConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WAKELOCK)) +                .isEqualTo(6000); +        assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WAKELOCK)) +                .isWithin(PRECISION).of(0.6); + +        BatteryConsumer appConsumer = mStatsRule.getDeviceBatteryConsumer(); +        assertThat(appConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WAKELOCK)) +                .isWithin(PRECISION).of(0.6);      }  } diff --git a/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java index 4a7cf1e21abe..fc44ddc216b4 100644 --- a/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java @@ -25,7 +25,6 @@ import android.net.NetworkCapabilities;  import android.net.NetworkStats;  import android.os.BatteryConsumer;  import android.os.Process; -import android.os.SystemBatteryConsumer;  import android.os.UidBatteryConsumer;  import android.os.WorkSource;  import android.os.connectivity.WifiActivityEnergyInfo; @@ -94,16 +93,19 @@ public class WifiPowerCalculatorTest {          assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_WIFI))                  .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE); -        SystemBatteryConsumer systemConsumer = -                mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_WIFI); -        assertThat(systemConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WIFI)) -                .isEqualTo(5577); -        assertThat(systemConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI)) -                .isWithin(PRECISION).of(1.11153); -        assertThat(systemConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_WIFI)) +        BatteryConsumer deviceConsumer = mStatsRule.getDeviceBatteryConsumer(); +        assertThat(deviceConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WIFI)) +                .isEqualTo(4002); +        assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI)) +                .isWithin(PRECISION).of(0.86666); +        assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_WIFI)) +                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE); + +        BatteryConsumer appsConsumer = mStatsRule.getDeviceBatteryConsumer(); +        assertThat(appsConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI)) +                .isWithin(PRECISION).of(0.866666); +        assertThat(appsConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_WIFI))                  .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE); -        assertThat(systemConsumer.getPowerConsumedByApps()) -                .isWithin(PRECISION).of(0.466333);      }      @Test @@ -125,17 +127,19 @@ public class WifiPowerCalculatorTest {          assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_WIFI))                  .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY); -        SystemBatteryConsumer systemConsumer = -                mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_WIFI); -        assertThat(systemConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WIFI)) -                .isEqualTo(5577); -        /* Same ratio as in testPowerControllerBasedModel_nonMeasured but scaled by 1_000_000uC. */ -        assertThat(systemConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI)) -                .isWithin(PRECISION).of(1.11153 / (0.2214666 + 0.645200) * 1_000_000 / 3600000); -        assertThat(systemConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_WIFI)) +        BatteryConsumer deviceConsumer = mStatsRule.getDeviceBatteryConsumer(); +        assertThat(deviceConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WIFI)) +                .isEqualTo(4002); +        assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI)) +                .isWithin(PRECISION).of(0.27777); +        assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_WIFI)) +                .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY); + +        BatteryConsumer appsConsumer = mStatsRule.getDeviceBatteryConsumer(); +        assertThat(appsConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI)) +                .isWithin(PRECISION).of(0.277777); +        assertThat(appsConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_WIFI))                  .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY); -        assertThat(systemConsumer.getPowerConsumedByApps()) -                .isWithin(PRECISION).of(0.14946);      }      /** Sets up batterystats object with prepopulated network & timer data for Timer-model tests. */ @@ -168,17 +172,6 @@ public class WifiPowerCalculatorTest {                  .isWithin(PRECISION).of(0.8231573);          assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_WIFI))                  .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE); - -        SystemBatteryConsumer systemConsumer = -                mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_WIFI); -        assertThat(systemConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WIFI)) -                .isEqualTo(2222); -        assertThat(systemConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI)) -                .isWithin(PRECISION).of(2.575000); -        assertThat(systemConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_WIFI)) -                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE); -        assertThat(systemConsumer.getPowerConsumedByApps()) -                .isWithin(PRECISION).of(1.69907);      }      @Test @@ -200,17 +193,5 @@ public class WifiPowerCalculatorTest {                  .isWithin(PRECISION).of(0.8231573 / (0.8231573 + 0.8759216) * 1_000_000 / 3600000);          assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_WIFI))                  .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY); - -        SystemBatteryConsumer systemConsumer = -                mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_WIFI); -        assertThat(systemConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WIFI)) -                .isEqualTo(2222); -        /* Same ratio as in testTimerBasedModel_nonMeasured but scaled by 1_000_000uC. */ -        assertThat(systemConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI)) -                .isWithin(PRECISION).of(2.575000 / (0.8231573 + 0.8759216) * 1_000_000 / 3600000); -        assertThat(systemConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_WIFI)) -                .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY); -        assertThat(systemConsumer.getPowerConsumedByApps()) -                .isWithin(PRECISION).of(0.277777);      }  } diff --git a/graphics/java/android/graphics/FrameInfo.java b/graphics/java/android/graphics/FrameInfo.java index b9393fff8896..b3615ff60bce 100644 --- a/graphics/java/android/graphics/FrameInfo.java +++ b/graphics/java/android/graphics/FrameInfo.java @@ -46,7 +46,7 @@ public final class FrameInfo {      public static final int FLAGS = 0;      // Is this the first-draw following a window layout? -    public static final long FLAG_WINDOW_LAYOUT_CHANGED = 1; +    public static final long FLAG_WINDOW_VISIBILITY_CHANGED = 1;      // A renderer associated with just a Surface, not with a ViewRootImpl instance.      public static final long FLAG_SURFACE_CANVAS = 1 << 2; @@ -56,7 +56,7 @@ public final class FrameInfo {      public static final long INVALID_VSYNC_ID = -1;      @LongDef(flag = true, value = { -            FLAG_WINDOW_LAYOUT_CHANGED, FLAG_SURFACE_CANVAS }) +            FLAG_WINDOW_VISIBILITY_CHANGED, FLAG_SURFACE_CANVAS })      @Retention(RetentionPolicy.SOURCE)      public @interface FrameInfoFlags {} diff --git a/graphics/java/android/graphics/RenderNode.java b/graphics/java/android/graphics/RenderNode.java index 6fcd8d09a770..01fd231d011f 100644 --- a/graphics/java/android/graphics/RenderNode.java +++ b/graphics/java/android/graphics/RenderNode.java @@ -280,8 +280,10 @@ public final class RenderNode {           *           * @hide           */ -        default void applyStretch(long frameNumber, float left, float top, float right, -                float bottom, float vecX, float vecY, float maxStretch) { } +        default void applyStretch(long frameNumber, float width, float height, +                float vecX, float vecY, +                float maxStretchX, float maxStretchY, float childRelativeLeft, +                float childRelativeTop, float childRelativeRight, float childRelativeBottom) { }          /**           * Called by native on RenderThread to notify that the view is no longer in the @@ -326,10 +328,13 @@ public final class RenderNode {          }          @Override -        public void applyStretch(long frameNumber, float left, float top, float right, float bottom, -                float vecX, float vecY, float maxStretch) { +        public void applyStretch(long frameNumber, float width, float height, +                float vecX, float vecY, float maxStretchX, float maxStretchY, float childRelativeLeft, +                float childRelativeTop, float childRelativeRight, float childRelativeBottom) {              for (PositionUpdateListener pul : mListeners) { -                pul.applyStretch(frameNumber, left, top, right, bottom, vecX, vecY, maxStretch); +                pul.applyStretch(frameNumber, width, height, vecX, vecY, maxStretchX, +                        maxStretchY, childRelativeLeft, childRelativeTop, childRelativeRight, +                        childRelativeBottom);              }          }      } @@ -719,19 +724,15 @@ public final class RenderNode {      }      /** @hide */ -    public boolean stretch(float left, float top, float right, float bottom, -            float vecX, float vecY, float maxStretchAmountX, float maxStretchAmountY) { +    public boolean stretch(float vecX, float vecY, +        float maxStretchAmountX, float maxStretchAmountY) {          if (Float.isInfinite(vecX) || Float.isNaN(vecX)) {              throw new IllegalArgumentException("vecX must be a finite, non-NaN value " + vecX);          }          if (Float.isInfinite(vecY) || Float.isNaN(vecY)) {              throw new IllegalArgumentException("vecY must be a finite, non-NaN value " + vecY);          } -        if (top >= bottom || left >= right) { -            throw new IllegalArgumentException( -                    "Stretch region must not be empty, got " -                            + new RectF(left, top, right, bottom).toString()); -        } +          if (maxStretchAmountX <= 0.0f) {              throw new IllegalArgumentException(                      "The max horizontal stretch amount must be >0, got " + maxStretchAmountX); @@ -742,10 +743,6 @@ public final class RenderNode {          }          return nStretch(                  mNativeRenderNode, -                left, -                top, -                right, -                bottom,                  vecX,                  vecY,                  maxStretchAmountX, @@ -1701,8 +1698,8 @@ public final class RenderNode {      private static native boolean nClearStretch(long renderNode);      @CriticalNative -    private static native boolean nStretch(long renderNode, float left, float top, float right, -            float bottom, float vecX, float vecY, float maxStretchX, float maxStretchY); +    private static native boolean nStretch(long renderNode, float vecX, float vecY, +            float maxStretchX, float maxStretchY);      @CriticalNative      private static native boolean nHasShadow(long renderNode); diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java index 895cd3e8531f..24d7780f5473 100644 --- a/graphics/java/android/graphics/drawable/RippleDrawable.java +++ b/graphics/java/android/graphics/drawable/RippleDrawable.java @@ -864,7 +864,6 @@ public class RippleDrawable extends LayerDrawable {          boolean shouldExit = mExitingAnimation;          mRippleActive = false;          mExitingAnimation = false; -        getRipplePaint();          drawContent(canvas);          drawPatternedBackground(canvas, cx, cy);          if (shouldAnimate && mRunningAnimations.size() <= MAX_RIPPLES) { @@ -928,7 +927,7 @@ public class RippleDrawable extends LayerDrawable {              startBackgroundAnimation();          }          if (mBackgroundOpacity == 0) return; -        Paint p = mRipplePaint; +        Paint p = getRipplePaint();          float newOpacity = mBackgroundOpacity;          final int origAlpha = p.getAlpha();          final int alpha = Math.min((int) (origAlpha * newOpacity + 0.5f), 255); @@ -957,7 +956,7 @@ public class RippleDrawable extends LayerDrawable {      @NonNull      private RippleAnimationSession.AnimationProperties<Float, Paint> createAnimationProperties(              float x, float y, float cx, float cy, float w, float h) { -        Paint p = new Paint(mRipplePaint); +        Paint p = new Paint(getRipplePaint());          float radius = getComputedRadius();          RippleAnimationSession.AnimationProperties<Float, Paint> properties;          RippleShader shader = new RippleShader(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java index 1971ca97d426..55dfc12966a9 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java @@ -15,6 +15,7 @@   */  package com.android.wm.shell.bubbles; +import static android.graphics.Paint.ANTI_ALIAS_FLAG;  import static android.graphics.Paint.DITHER_FLAG;  import static android.graphics.Paint.FILTER_BITMAP_FLAG; @@ -22,10 +23,10 @@ import android.annotation.Nullable;  import android.content.Context;  import android.graphics.Bitmap;  import android.graphics.Canvas; +import android.graphics.Paint;  import android.graphics.PaintFlagsDrawFilter;  import android.graphics.Path;  import android.graphics.Rect; -import android.graphics.drawable.Drawable;  import android.util.AttributeSet;  import android.util.PathParser;  import android.widget.ImageView; @@ -75,13 +76,13 @@ public class BadgedImageView extends ImageView {      private BubbleViewProvider mBubble;      private BubblePositioner mPositioner; +    private boolean mOnLeft;      private DotRenderer mDotRenderer;      private DotRenderer.DrawParams mDrawParams; -    private boolean mOnLeft; -      private int mDotColor; +    private Paint mPaint = new Paint(ANTI_ALIAS_FLAG);      private Rect mTempBounds = new Rect();      public BadgedImageView(Context context) { @@ -305,7 +306,7 @@ public class BadgedImageView extends ImageView {      }      void showBadge() { -        Drawable badge = mBubble.getAppBadge(); +        Bitmap badge = mBubble.getAppBadge();          if (badge == null) {              setImageBitmap(mBubble.getBubbleIcon());              return; @@ -318,13 +319,13 @@ public class BadgedImageView extends ImageView {          bubbleCanvas.setBitmap(bubble);          final int bubbleSize = bubble.getWidth();          final int badgeSize = (int) (ICON_BADGE_SCALE * bubbleSize); +        Rect dest = new Rect();          if (mOnLeft) { -            badge.setBounds(0, bubbleSize - badgeSize, badgeSize, bubbleSize); +            dest.set(0, bubbleSize - badgeSize, badgeSize, bubbleSize);          } else { -            badge.setBounds(bubbleSize - badgeSize, bubbleSize - badgeSize, -                    bubbleSize, bubbleSize); +            dest.set(bubbleSize - badgeSize, bubbleSize - badgeSize, bubbleSize, bubbleSize);          } -        badge.draw(bubbleCanvas); +        bubbleCanvas.drawBitmap(badge, null /* src */, dest, mPaint);          bubbleCanvas.setBitmap(null);          setImageBitmap(bubble);      } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java index f6e92ef0e8ea..afb40d1ff95c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java @@ -104,9 +104,10 @@ public class Bubble implements BubbleViewProvider {      }      private FlyoutMessage mFlyoutMessage; -    private Drawable mBadgeDrawable; -    // Bitmap with no badge, no dot +    // The developer provided image for the bubble      private Bitmap mBubbleBitmap; +    // The app badge for the bubble +    private Bitmap mBadgeBitmap;      private int mDotColor;      private Path mDotPath;      private int mFlags; @@ -242,8 +243,8 @@ public class Bubble implements BubbleViewProvider {      }      @Override -    public Drawable getAppBadge() { -        return mBadgeDrawable; +    public Bitmap getAppBadge() { +        return mBadgeBitmap;      }      @Override @@ -398,7 +399,7 @@ public class Bubble implements BubbleViewProvider {          mAppName = info.appName;          mFlyoutMessage = info.flyoutMessage; -        mBadgeDrawable = info.badgeDrawable; +        mBadgeBitmap = info.badgeBitmap;          mBubbleBitmap = info.bubbleBitmap;          mDotColor = info.dotColor; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java index 696f705782c0..d8ec6508d77c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java @@ -395,7 +395,6 @@ public class BubbleExpandedView extends LinearLayout {          mPointerView.setBackground(mCurrentPointer);      } -      private String getBubbleKey() {          return mBubble != null ? mBubble.getKey() : "null";      } @@ -519,16 +518,11 @@ public class BubbleExpandedView extends LinearLayout {                      + " bubble=" + getBubbleKey());          }          mIsContentVisible = visibility; - -        final float alpha = visibility ? 1f : 0f; - -        mPointerView.setAlpha(alpha);          if (mTaskView != null && !mIsAlphaAnimating) { -            mTaskView.setAlpha(alpha); +            mTaskView.setAlpha(visibility ? 1f : 0f);          }      } -      @Nullable      TaskView getTaskView() {          return mTaskView; @@ -673,26 +667,48 @@ public class BubbleExpandedView extends LinearLayout {      }      /** -     * Set the position that the tip of the triangle should point to. +     * Sets the position of the pointer. +     * +     * When bubbles are showing "vertically" they display along the left / right sides of the +     * screen with the expanded view beside them. +     * +     * If they aren't showing vertically they're positioned along the top of the screen with the +     * expanded view below them. +     * +     * @param bubblePosition the x position of the bubble if showing on top, the y position of +     *                       the bubble if showing vertically. +     * @param onLeft whether the stack was on the left side of the screen when expanded.       */ -    public void setPointerPosition(float x, float y, boolean isLandscape, boolean onLeft) { +    public void setPointerPosition(float bubblePosition, boolean onLeft) {          // Pointer gets drawn in the padding -        int paddingLeft = (isLandscape && onLeft) ? mPointerHeight : 0; -        int paddingRight = (isLandscape && !onLeft) ? mPointerHeight : 0; -        int paddingTop = isLandscape ? 0 : mExpandedViewPadding; +        final boolean showVertically = mPositioner.showBubblesVertically(); +        final int paddingLeft = (showVertically && onLeft) ? mPointerHeight : 0; +        final int paddingRight = (showVertically && !onLeft) ? mPointerHeight : 0; +        final int paddingTop = showVertically ? 0 : mExpandedViewPadding;          setPadding(paddingLeft, paddingTop, paddingRight, 0); -        if (isLandscape) { -            // TODO: why setY vs setTranslationY ? linearlayout? -            mPointerView.setY(y - (mPointerWidth / 2f)); -            mPointerView.setTranslationX(onLeft ? -mPointerHeight : x - mExpandedViewPadding); -        } else { -            mPointerView.setTranslationY(0f); -            mPointerView.setTranslationX(x - mExpandedViewPadding - (mPointerWidth / 2f)); -        } -        mCurrentPointer = isLandscape ? onLeft ? mLeftPointer : mRightPointer : mTopPointer; -        updatePointerView(); -        mPointerView.setVisibility(VISIBLE); +        final float expandedViewY = mPositioner.getExpandedViewY(); +        final float bubbleSize = mPositioner.getBubbleBitmapSize(); +        final float bubbleCenter = showVertically +                ? bubblePosition + (bubbleSize / 2f) - expandedViewY +                : bubblePosition + (bubbleSize / 2f); +        // Post because we need the width of the view +        post(() -> { +            float pointerY; +            float pointerX; +            if (showVertically) { +                pointerY = bubbleCenter - (mPointerWidth / 2f); +                pointerX = onLeft ? -mPointerHeight : getWidth() - mPaddingRight; +            } else { +                pointerY = 0; +                pointerX = bubbleCenter - mPaddingLeft - (mPointerWidth / 2f); +            } +            mPointerView.setTranslationY(pointerY); +            mPointerView.setTranslationX(pointerX); +            mCurrentPointer = showVertically ? onLeft ? mLeftPointer : mRightPointer : mTopPointer; +            updatePointerView(); +            mPointerView.setVisibility(VISIBLE); +        });      }      /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleIconFactory.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleIconFactory.java index e64ed6a0836c..b83feeedbf21 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleIconFactory.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleIconFactory.java @@ -101,6 +101,12 @@ public class BubbleIconFactory extends BaseIconFactory {                      userBadgedBitmap.getHeight(), userBadgedBitmap.getConfig());              Canvas c = new Canvas(badgeAndRing); +            Paint ringPaint = new Paint(); +            ringPaint.setStyle(Paint.Style.FILL); +            ringPaint.setColor(importantConversationColor); +            ringPaint.setAntiAlias(true); +            c.drawCircle(c.getWidth() / 2, c.getHeight() / 2, c.getWidth() / 2, ringPaint); +              final int bitmapTop = (int) ringStrokeWidth;              final int bitmapLeft = (int) ringStrokeWidth;              final int bitmapWidth = c.getWidth() - 2 * (int) ringStrokeWidth; @@ -110,14 +116,6 @@ public class BubbleIconFactory extends BaseIconFactory {                      bitmapHeight, /* filter */ true);              c.drawBitmap(scaledBitmap, bitmapTop, bitmapLeft, /* paint */null); -            Paint ringPaint = new Paint(); -            ringPaint.setStyle(Paint.Style.STROKE); -            ringPaint.setColor(importantConversationColor); -            ringPaint.setAntiAlias(true); -            ringPaint.setStrokeWidth(ringStrokeWidth); -            c.drawCircle(c.getWidth() / 2, c.getHeight() / 2, c.getWidth() / 2 - ringStrokeWidth, -                    ringPaint); -              shadowGenerator.recreateIcon(Bitmap.createBitmap(badgeAndRing), c);              return createIconBitmap(badgeAndRing);          } else { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt index 51d63cff385a..36908b854842 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt @@ -24,7 +24,6 @@ import android.graphics.Matrix  import android.graphics.Path  import android.graphics.drawable.AdaptiveIconDrawable  import android.graphics.drawable.ColorDrawable -import android.graphics.drawable.Drawable  import android.graphics.drawable.InsetDrawable  import android.util.PathParser  import android.util.TypedValue @@ -151,7 +150,7 @@ class BubbleOverflow(          return dotColor      } -    override fun getAppBadge(): Drawable? { +    override fun getAppBadge(): Bitmap? {          return null      } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java index c4d33877f17d..07d16b57d675 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java @@ -2487,7 +2487,7 @@ public class BubbleStackView extends FrameLayout          // name and icon.          if (show && mBubbleData.hasBubbleInStackWithKey(mExpandedBubble.getKey())) {              final Bubble bubble = mBubbleData.getBubbleInStackWithKey(mExpandedBubble.getKey()); -            mManageSettingsIcon.setImageDrawable(bubble.getAppBadge()); +            mManageSettingsIcon.setImageBitmap(bubble.getAppBadge());              mManageSettingsText.setText(getResources().getString(                      R.string.bubbles_app_settings, bubble.getAppName()));          } @@ -2683,7 +2683,7 @@ public class BubbleStackView extends FrameLayout              Log.d(TAG, "updateExpandedView: mIsExpanded=" + mIsExpanded);          }          boolean isOverflowExpanded = mExpandedBubble != null -                && mBubbleOverflow.KEY.equals(mExpandedBubble.getKey()); +                && BubbleOverflow.KEY.equals(mExpandedBubble.getKey());          int[] paddings = mPositioner.getExpandedViewPadding(                  mStackAnimationController.isStackOnLeftSide(), isOverflowExpanded);          mExpandedViewContainer.setPadding(paddings[0], 0, paddings[1], 0); @@ -2695,6 +2695,7 @@ public class BubbleStackView extends FrameLayout              mExpandedViewContainer.setTranslationX(0f);              mExpandedBubble.getExpandedView().updateView(                      mExpandedViewContainer.getLocationOnScreen()); +            updatePointerPosition();          }          mStackOnLeftOrWillBe = mStackAnimationController.isStackOnLeftSide(); @@ -2732,27 +2733,7 @@ public class BubbleStackView extends FrameLayout              return;          }          float bubblePosition = mExpandedAnimationController.getBubbleXOrYForOrientation(index); -        float expandedViewY = mPositioner.getExpandedViewY(); -        if (mPositioner.showBubblesVertically()) { -            float x = mStackOnLeftOrWillBe -                    ? mPositioner.getAvailableRect().left -                    : mPositioner.getAvailableRect().right -                            - mExpandedViewContainer.getPaddingRight() -                            - mPointerHeight; -            float bubbleCenter = bubblePosition - expandedViewY + (mBubbleSize / 2f); -            mExpandedBubble.getExpandedView().setPointerPosition( -                    x, -                    bubbleCenter, -                    true, -                    mStackOnLeftOrWillBe); -        } else { -            float bubbleCenter = bubblePosition + (mBubbleSize / 2f); -            mExpandedBubble.getExpandedView().setPointerPosition( -                    bubbleCenter, -                    expandedViewY, -                    false, -                    mStackOnLeftOrWillBe); -        } +        mExpandedBubble.getExpandedView().setPointerPosition(bubblePosition, mStackOnLeftOrWillBe);      }      /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java index fc53ef26dbd9..932f879caef8 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java @@ -126,7 +126,7 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask          ShortcutInfo shortcutInfo;          String appName;          Bitmap bubbleBitmap; -        Drawable badgeDrawable; +        Bitmap badgeBitmap;          int dotColor;          Path dotPath;          Bubble.FlyoutMessage flyoutMessage; @@ -188,7 +188,7 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask              BitmapInfo badgeBitmapInfo = iconFactory.getBadgeBitmap(badgedIcon,                      b.isImportantConversation()); -            info.badgeDrawable = badgedIcon; +            info.badgeBitmap = badgeBitmapInfo.icon;              info.bubbleBitmap = iconFactory.createBadgedIconBitmap(bubbleDrawable,                      null /* user */,                      true /* shrinkNonAdaptiveIcons */).icon; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewProvider.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewProvider.java index da4259c42558..38b3ba9dfda0 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewProvider.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewProvider.java @@ -18,7 +18,6 @@ package com.android.wm.shell.bubbles;  import android.graphics.Bitmap;  import android.graphics.Path; -import android.graphics.drawable.Drawable;  import android.view.View;  import androidx.annotation.Nullable; @@ -48,7 +47,7 @@ public interface BubbleViewProvider {      Bitmap getBubbleIcon();      /** App badge drawable to draw above bubble icon. */ -    @Nullable Drawable getAppBadge(); +    @Nullable Bitmap getAppBadge();      /** Path of normalized bubble icon to draw dot on. */      Path getDotPath(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAccessibilityUtil.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAccessibilityUtil.java index 130246177fdc..4892e6b1b30f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAccessibilityUtil.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAccessibilityUtil.java @@ -82,7 +82,7 @@ public final class OneHandedAccessibilityUtil {      public void dump(@NonNull PrintWriter pw) {          final String innerPrefix = "  "; -        pw.println(TAG + "States: "); +        pw.println(TAG);          pw.print(innerPrefix + "mPackageName=");          pw.println(mPackageName);          pw.print(innerPrefix + "mDescription="); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAnimationCallback.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAnimationCallback.java index 6749f7eec968..24e511143cff 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAnimationCallback.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAnimationCallback.java @@ -44,8 +44,9 @@ public interface OneHandedAnimationCallback {      }      /** -     * Called when OneHanded animator is updating offset +     * Called when OneHanded animator is updating position       */ -    default void onTutorialAnimationUpdate(int offset) {} +    default void onAnimationUpdate(float xPos, float yPos) { +    }  } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAnimationController.java index 25dd3ca57b92..180cceba068d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAnimationController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAnimationController.java @@ -25,8 +25,10 @@ import android.view.SurfaceControl;  import android.view.animation.BaseInterpolator;  import android.window.WindowContainerToken; +import androidx.annotation.NonNull;  import androidx.annotation.VisibleForTesting; +import java.io.PrintWriter;  import java.lang.annotation.Retention;  import java.lang.annotation.RetentionPolicy;  import java.util.ArrayList; @@ -37,6 +39,7 @@ import java.util.List;   * Controller class of OneHanded animations (both from and to OneHanded mode).   */  public class OneHandedAnimationController { +    private static final String TAG = "OneHandedAnimationController";      private static final float FRACTION_START = 0f;      private static final float FRACTION_END = 1f; @@ -68,17 +71,19 @@ public class OneHandedAnimationController {      @SuppressWarnings("unchecked")      OneHandedTransitionAnimator getAnimator(WindowContainerToken token, SurfaceControl leash, -            Rect startBounds, Rect endBounds) { +            float startPos, float endPos, Rect displayBounds) {          final OneHandedTransitionAnimator animator = mAnimatorMap.get(token);          if (animator == null) {              mAnimatorMap.put(token, setupOneHandedTransitionAnimator( -                    OneHandedTransitionAnimator.ofBounds(token, leash, startBounds, endBounds))); +                    OneHandedTransitionAnimator.ofYOffset(token, leash, startPos, endPos, +                            displayBounds)));          } else if (animator.isRunning()) { -            animator.updateEndValue(endBounds); +            animator.updateEndValue(endPos);          } else {              animator.cancel();              mAnimatorMap.put(token, setupOneHandedTransitionAnimator( -                    OneHandedTransitionAnimator.ofBounds(token, leash, startBounds, endBounds))); +                    OneHandedTransitionAnimator.ofYOffset(token, leash, startPos, endPos, +                            displayBounds)));          }          return mAnimatorMap.get(token);      } @@ -147,9 +152,7 @@ public class OneHandedAnimationController {          public void onAnimationStart(Animator animation) {              mCurrentValue = mStartValue;              mOneHandedAnimationCallbacks.forEach( -                    (callback) -> { -                        callback.onOneHandedAnimationStart(this); -                    } +                    (callback) -> callback.onOneHandedAnimationStart(this)              );          } @@ -159,9 +162,7 @@ public class OneHandedAnimationController {              final SurfaceControl.Transaction tx = newSurfaceControlTransaction();              onEndTransaction(mLeash, tx);              mOneHandedAnimationCallbacks.forEach( -                    (callback) -> { -                        callback.onOneHandedAnimationEnd(tx, this); -                    } +                    (callback) -> callback.onOneHandedAnimationEnd(tx, this)              );          } @@ -169,9 +170,7 @@ public class OneHandedAnimationController {          public void onAnimationCancel(Animator animation) {              mCurrentValue = mEndValue;              mOneHandedAnimationCallbacks.forEach( -                    (callback) -> { -                        callback.onOneHandedAnimationCancel(this); -                    } +                    (callback) -> callback.onOneHandedAnimationCancel(this)              );          } @@ -181,12 +180,10 @@ public class OneHandedAnimationController {          @Override          public void onAnimationUpdate(ValueAnimator animation) { -            applySurfaceControlTransaction(mLeash, newSurfaceControlTransaction(), -                    animation.getAnimatedFraction()); +            final SurfaceControl.Transaction tx = newSurfaceControlTransaction(); +            applySurfaceControlTransaction(mLeash, tx, animation.getAnimatedFraction());              mOneHandedAnimationCallbacks.forEach( -                    (callback) -> { -                        callback.onTutorialAnimationUpdate(((Rect) mCurrentValue).top); -                    } +                    (callback) -> callback.onAnimationUpdate(0f, (float) mCurrentValue)              );          } @@ -217,12 +214,8 @@ public class OneHandedAnimationController {              return mToken;          } -        Rect getDestinationBounds() { -            return (Rect) mEndValue; -        } - -        int getDestinationOffset() { -            return ((Rect) mEndValue).top - ((Rect) mStartValue).top; +        float getDestinationOffset() { +            return ((float) mEndValue - (float) mStartValue);          }          @TransitionDirection @@ -259,40 +252,42 @@ public class OneHandedAnimationController {          }          @VisibleForTesting -        static OneHandedTransitionAnimator<Rect> ofBounds(WindowContainerToken token, -                SurfaceControl leash, Rect startValue, Rect endValue) { +        static OneHandedTransitionAnimator<Float> ofYOffset(WindowContainerToken token, +                SurfaceControl leash, float startValue, float endValue, Rect displayBounds) { -            return new OneHandedTransitionAnimator<Rect>(token, leash, new Rect(startValue), -                    new Rect(endValue)) { +            return new OneHandedTransitionAnimator<Float>(token, leash, startValue, endValue) { -                private final Rect mTmpRect = new Rect(); +                private final Rect mTmpRect = new Rect(displayBounds); -                private int getCastedFractionValue(float start, float end, float fraction) { -                    return (int) (start * (1 - fraction) + end * fraction + .5f); +                private float getCastedFractionValue(float start, float end, float fraction) { +                    return (start * (1 - fraction) + end * fraction + .5f);                  }                  @Override                  void applySurfaceControlTransaction(SurfaceControl leash,                          SurfaceControl.Transaction tx, float fraction) { -                    final Rect start = getStartValue(); -                    final Rect end = getEndValue(); +                    final float start = getStartValue(); +                    final float end = getEndValue(); +                    final float currentValue = getCastedFractionValue(start, end, fraction);                      mTmpRect.set( -                            getCastedFractionValue(start.left, end.left, fraction), -                            getCastedFractionValue(start.top, end.top, fraction), -                            getCastedFractionValue(start.right, end.right, fraction), -                            getCastedFractionValue(start.bottom, end.bottom, fraction)); -                    setCurrentValue(mTmpRect); -                    getSurfaceTransactionHelper().crop(tx, leash, mTmpRect) -                            .round(tx, leash); +                            mTmpRect.left, +                            mTmpRect.top + Math.round(currentValue), +                            mTmpRect.right, +                            mTmpRect.bottom + Math.round(currentValue)); +                    setCurrentValue(currentValue); +                    getSurfaceTransactionHelper() +                            .crop(tx, leash, mTmpRect) +                            .round(tx, leash) +                            .translate(tx, leash, currentValue);                      tx.apply();                  }                  @Override                  void onStartTransaction(SurfaceControl leash, SurfaceControl.Transaction tx) {                      getSurfaceTransactionHelper() -                            .alpha(tx, leash, 1f) -                            .translate(tx, leash, getEndValue().top - getStartValue().top) -                            .round(tx, leash); +                            .crop(tx, leash, mTmpRect) +                            .round(tx, leash) +                            .translate(tx, leash, getStartValue());                      tx.apply();                  }              }; @@ -309,4 +304,15 @@ public class OneHandedAnimationController {                      * (2.0f * Math.PI) / 4.0f) + 1);          }      } + +    void dump(@NonNull PrintWriter pw) { +        final String innerPrefix = "  "; +        pw.println(TAG + "states: "); +        pw.print(innerPrefix + "mAnimatorMap="); +        pw.println(mAnimatorMap); + +        if (mSurfaceTransactionHelper != null) { +            mSurfaceTransactionHelper.dump(pw); +        } +    }  } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java index 703eba9d6af7..481b94817385 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java @@ -203,7 +203,7 @@ public class OneHandedBackgroundPanelOrganizer extends DisplayAreaOrganizer      void dump(@NonNull PrintWriter pw) {          final String innerPrefix = "  "; -        pw.println(TAG + "states: "); +        pw.println(TAG);          pw.print(innerPrefix + "mIsShowing=");          pw.println(mIsShowing);          pw.print(innerPrefix + "mBkgBounds="); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java index 04ec3917428e..ae7ab528ed0a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java @@ -630,7 +630,8 @@ public class OneHandedController implements RemoteCallable<OneHandedController>      public void dump(@NonNull PrintWriter pw) {          final String innerPrefix = "  "; -        pw.println(TAG + "States: "); +        pw.println(); +        pw.println(TAG);          pw.print(innerPrefix + "mOffSetFraction=");          pw.println(mOffSetFraction);          pw.print(innerPrefix + "mLockedDisabled="); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java index 4b4d934bef43..b8da37fd0c25 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java @@ -61,6 +61,7 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {      private DisplayLayout mDisplayLayout = new DisplayLayout(); +    private float mLastVisualOffset = 0;      private final Rect mLastVisualDisplayBounds = new Rect();      private final Rect mDefaultDisplayBounds = new Rect();      private final OneHandedSettingsUtil mOneHandedSettingsUtil; @@ -96,8 +97,7 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {                          OneHandedAnimationController.OneHandedTransitionAnimator animator) {                      mAnimationController.removeAnimator(animator.getToken());                      if (mAnimationController.isAnimatorsConsumed()) { -                        resetWindowsOffsetInternal(animator.getTransitionDirection()); -                        finishOffset(animator.getDestinationOffset(), +                        finishOffset((int) animator.getDestinationOffset(),                                  animator.getTransitionDirection());                      }                  } @@ -107,8 +107,7 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {                          OneHandedAnimationController.OneHandedTransitionAnimator animator) {                      mAnimationController.removeAnimator(animator.getToken());                      if (mAnimationController.isAnimatorsConsumed()) { -                        resetWindowsOffsetInternal(animator.getTransitionDirection()); -                        finishOffset(animator.getDestinationOffset(), +                        finishOffset((int) animator.getDestinationOffset(),                                  animator.getTransitionDirection());                      }                  } @@ -165,16 +164,16 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {      @Override      public void unregisterOrganizer() {          super.unregisterOrganizer(); -        resetWindowsOffset(null); +        resetWindowsOffset();      }      /**       * Handler for display rotation changes by {@link DisplayLayout}       * -     * @param context       Any context -     * @param toRotation    target rotation of the display (after rotating). -     * @param wct           A task transaction {@link WindowContainerTransaction} from -     *                      {@link DisplayChangeController} to populate. +     * @param context    Any context +     * @param toRotation target rotation of the display (after rotating). +     * @param wct        A task transaction {@link WindowContainerTransaction} from +     *                   {@link DisplayChangeController} to populate.       */      public void onRotateDisplay(Context context, int toRotation, WindowContainerTransaction wct) {          if (mDisplayLayout.rotation() == toRotation) { @@ -186,7 +185,6 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {              return;          }          mDisplayLayout.rotateTo(context.getResources(), toRotation); -        resetWindowsOffset(wct);          updateDisplayBounds();          finishOffset(0, TRANSITION_DIRECTION_EXIT);      } @@ -196,38 +194,20 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {       * Directly perform manipulation/offset on the leash.       */      public void scheduleOffset(int xOffset, int yOffset) { -        final Rect toBounds = new Rect(mDefaultDisplayBounds.left, -                mDefaultDisplayBounds.top + yOffset, -                mDefaultDisplayBounds.right, -                mDefaultDisplayBounds.bottom + yOffset); -        final Rect fromBounds = getLastVisualDisplayBounds(); +        final float fromPos = mLastVisualOffset;          final int direction = yOffset > 0                  ? TRANSITION_DIRECTION_TRIGGER                  : TRANSITION_DIRECTION_EXIT; - -        final WindowContainerTransaction wct = new WindowContainerTransaction();          mDisplayAreaTokenMap.forEach(                  (token, leash) -> { -                    animateWindows(token, leash, fromBounds, toBounds, direction, +                    animateWindows(token, leash, fromPos, yOffset, direction,                              mEnterExitAnimationDurationMs); -                    wct.setBounds(token, toBounds); -                    wct.setAppBounds(token, toBounds);                  }); -        applyTransaction(wct); -    } - -    private void resetWindowsOffsetInternal( -            @OneHandedAnimationController.TransitionDirection int td) { -        if (td == TRANSITION_DIRECTION_TRIGGER) { -            return; -        } -        final WindowContainerTransaction wct = new WindowContainerTransaction(); -        resetWindowsOffset(wct); -        applyTransaction(wct); +        mLastVisualOffset = yOffset;      }      @VisibleForTesting -    void resetWindowsOffset(WindowContainerTransaction wct) { +    void resetWindowsOffset() {          final SurfaceControl.Transaction tx =                  mSurfaceControlTransactionFactory.getTransaction();          mDisplayAreaTokenMap.forEach( @@ -238,21 +218,20 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {                          animator.cancel();                      }                      tx.setPosition(leash, 0, 0) -                            .setWindowCrop(leash, -1/* reset */, -1/* reset */); -                    // DisplayRotationController will applyTransaction() after finish rotating -                    if (wct != null) { -                        wct.setBounds(token, null/* reset */); -                        wct.setAppBounds(token, null/* reset */); -                    } +                            .setWindowCrop(leash, -1, -1) +                            .setCornerRadius(leash, -1);                  });          tx.apply(); +        mLastVisualOffset = 0; +        mLastVisualDisplayBounds.offsetTo(0, 0);      } -    private void animateWindows(WindowContainerToken token, SurfaceControl leash, Rect fromBounds, -            Rect toBounds, @OneHandedAnimationController.TransitionDirection int direction, +    private void animateWindows(WindowContainerToken token, SurfaceControl leash, float fromPos, +            float toPos, @OneHandedAnimationController.TransitionDirection int direction,              int durationMs) {          final OneHandedAnimationController.OneHandedTransitionAnimator animator = -                mAnimationController.getAnimator(token, leash, fromBounds, toBounds); +                mAnimationController.getAnimator(token, leash, fromPos, toPos, +                        mLastVisualDisplayBounds);          if (animator != null) {              animator.setTransitionDirection(direction)                      .addOneHandedAnimationCallback(mOneHandedAnimationCallback) @@ -265,10 +244,13 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {      }      @VisibleForTesting -    void finishOffset(int offset, -            @OneHandedAnimationController.TransitionDirection int direction) { -        mLastVisualDisplayBounds.offsetTo(0, -                direction == TRANSITION_DIRECTION_TRIGGER ? offset : 0); +    void finishOffset(int offset, @OneHandedAnimationController.TransitionDirection int direction) { +        if (direction == TRANSITION_DIRECTION_EXIT) { +            // We must do this to ensure reset property for leash when exit one handed mode +            resetWindowsOffset(); +        } +        mLastVisualOffset = direction == TRANSITION_DIRECTION_TRIGGER ? offset : 0; +        mLastVisualDisplayBounds.offsetTo(0, Math.round(mLastVisualOffset));          for (int i = mTransitionCallbacks.size() - 1; i >= 0; i--) {              final OneHandedTransitionCallback cb = mTransitionCallbacks.get(i);              cb.onStartTransition(false /* isTransitioning */); @@ -285,7 +267,7 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {       *       * @return Rect latest finish_offset       */ -    public Rect getLastVisualDisplayBounds() { +    private Rect getLastVisualDisplayBounds() {          return mLastVisualDisplayBounds;      } @@ -323,7 +305,7 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {      void dump(@NonNull PrintWriter pw) {          final String innerPrefix = "  "; -        pw.println(TAG + "states: "); +        pw.println(TAG);          pw.print(innerPrefix + "mDisplayLayout.rotation()=");          pw.println(mDisplayLayout.rotation());          pw.print(innerPrefix + "mDisplayAreaTokenMap="); @@ -332,5 +314,11 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {          pw.println(mDefaultDisplayBounds);          pw.print(innerPrefix + "mLastVisualDisplayBounds=");          pw.println(mLastVisualDisplayBounds); +        pw.print(innerPrefix + "mLastVisualOffset="); +        pw.println(mLastVisualOffset); + +        if (mAnimationController != null) { +            mAnimationController.dump(pw); +        }      }  } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedGestureHandler.java index 9e83a61667b2..03832294aaca 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedGestureHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedGestureHandler.java @@ -276,7 +276,7 @@ public class OneHandedGestureHandler implements OneHandedTransitionCallback {      void dump(@NonNull PrintWriter pw) {          final String innerPrefix = "  "; -        pw.println(TAG + "States: "); +        pw.println(TAG);          pw.print(innerPrefix + "mAllowGesture=");          pw.println(mAllowGesture);          pw.print(innerPrefix + "mIsEnabled="); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java index 1b2fcdd6313e..2ab51f3f1313 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java @@ -137,8 +137,8 @@ public final class OneHandedSettingsUtil {      void dump(PrintWriter pw, String prefix, ContentResolver resolver,              int userId) { -        final String innerPrefix = prefix + "  "; -        pw.println(innerPrefix + TAG); +        final String innerPrefix = "  "; +        pw.println(TAG);          pw.print(innerPrefix + "isOneHandedModeEnable=");          pw.println(getSettingsOneHandedModeEnabled(resolver, userId));          pw.print(innerPrefix + "oneHandedTimeOut="); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedState.java index cc874432be87..facc4bd2b6e8 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedState.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedState.java @@ -90,7 +90,7 @@ public class OneHandedState {      /** Dumps internal state. */      public void dump(PrintWriter pw) {          final String innerPrefix = "  "; -        pw.println(TAG + "states: "); +        pw.println(TAG);          pw.println(innerPrefix + "sCurrentState=" + sCurrentState);      }  } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSurfaceTransactionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSurfaceTransactionHelper.java index e7010db97d77..e9048c6df587 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSurfaceTransactionHelper.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSurfaceTransactionHelper.java @@ -21,18 +21,28 @@ import android.content.res.Resources;  import android.graphics.Rect;  import android.view.SurfaceControl; +import androidx.annotation.NonNull; +  import com.android.wm.shell.R; +import java.io.PrintWriter; +  /**   * Abstracts the common operations on {@link SurfaceControl.Transaction} for OneHanded transition.   */  public class OneHandedSurfaceTransactionHelper { +    private static final String TAG = "OneHandedSurfaceTransactionHelper"; +      private final boolean mEnableCornerRadius;      private final float mCornerRadius; +    private final float mCornerRadiusAdjustment;      public OneHandedSurfaceTransactionHelper(Context context) {          final Resources res = context.getResources(); -        mCornerRadius = res.getDimension(com.android.internal.R.dimen.rounded_corner_radius); +        mCornerRadiusAdjustment = res.getDimension( +                com.android.internal.R.dimen.rounded_corner_radius_adjustment); +        mCornerRadius = res.getDimension(com.android.internal.R.dimen.rounded_corner_radius) +                - mCornerRadiusAdjustment;          mEnableCornerRadius = res.getBoolean(R.bool.config_one_handed_enable_round_corner);      } @@ -48,25 +58,13 @@ public class OneHandedSurfaceTransactionHelper {      }      /** -     * Operates the alpha on a given transaction and leash -     * -     * @return same {@link OneHandedSurfaceTransactionHelper} instance for method chaining -     */ -    OneHandedSurfaceTransactionHelper alpha(SurfaceControl.Transaction tx, SurfaceControl leash, -            float alpha) { -        tx.setAlpha(leash, alpha); -        return this; -    } - -    /**       * Operates the crop (setMatrix) on a given transaction and leash       *       * @return same {@link OneHandedSurfaceTransactionHelper} instance for method chaining       */      OneHandedSurfaceTransactionHelper crop(SurfaceControl.Transaction tx, SurfaceControl leash,              Rect destinationBounds) { -        tx.setWindowCrop(leash, destinationBounds.width(), destinationBounds.height()) -                .setPosition(leash, destinationBounds.left, destinationBounds.top); +        tx.setWindowCrop(leash, destinationBounds.width(), destinationBounds.height());          return this;      } @@ -85,4 +83,15 @@ public class OneHandedSurfaceTransactionHelper {      interface SurfaceControlTransactionFactory {          SurfaceControl.Transaction getTransaction();      } + +    void dump(@NonNull PrintWriter pw) { +        final String innerPrefix = "  "; +        pw.println(TAG + "states: "); +        pw.print(innerPrefix + "mEnableCornerRadius="); +        pw.println(mEnableCornerRadius); +        pw.print(innerPrefix + "mCornerRadiusAdjustment="); +        pw.println(mCornerRadiusAdjustment); +        pw.print(innerPrefix + "mCornerRadius="); +        pw.println(mCornerRadius); +    }  } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTimeoutHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTimeoutHandler.java index 4a98941b7410..899c9ae748d0 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTimeoutHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTimeoutHandler.java @@ -18,8 +18,6 @@ package com.android.wm.shell.onehanded;  import static com.android.wm.shell.onehanded.OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_MEDIUM_IN_SECONDS; -import android.os.Handler; -  import androidx.annotation.NonNull;  import androidx.annotation.VisibleForTesting; @@ -122,7 +120,7 @@ public class OneHandedTimeoutHandler {      void dump(@NonNull PrintWriter pw) {          final String innerPrefix = "  "; -        pw.println(TAG + "states: "); +        pw.println(TAG);          pw.print(innerPrefix + "sTimeout=");          pw.println(mTimeout);          pw.print(innerPrefix + "sListeners="); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTouchHandler.java index c7a49ff01d15..0f9b320791b9 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTouchHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTouchHandler.java @@ -156,7 +156,7 @@ public class OneHandedTouchHandler implements OneHandedTransitionCallback {      void dump(@NonNull PrintWriter pw) {          final String innerPrefix = "  "; -        pw.println(TAG + "states: "); +        pw.println(TAG);          pw.print(innerPrefix + "mLastUpdatedBounds=");          pw.println(mLastUpdatedBounds);      } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java index 7a3f34d0e5a5..e8cee8a95c44 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java @@ -78,16 +78,21 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback {      private final OneHandedAnimationCallback mAnimationCallback = new OneHandedAnimationCallback() {          @Override -        public void onTutorialAnimationUpdate(int offset) { -            onAnimationUpdate(offset); +        public void onAnimationUpdate(float xPos, float yPos) { +            if (!canShowTutorial()) { +                return; +            } +            mTargetViewContainer.setVisibility(View.VISIBLE); +            mTargetViewContainer.setTransitionGroup(true); +            mTargetViewContainer.setTranslationY(yPos - mTargetViewContainer.getHeight());          }          @Override          public void onOneHandedAnimationStart(                  OneHandedAnimationController.OneHandedTransitionAnimator animator) { -            final Rect startValue = (Rect) animator.getStartValue(); +            final float startValue = (float) animator.getStartValue();              if (mTriggerState == ONE_HANDED_TRIGGER_STATE.UNSET) { -                mTriggerState = (startValue.top == 0) +                mTriggerState = (startValue == 0f)                          ? ONE_HANDED_TRIGGER_STATE.ENTERING : ONE_HANDED_TRIGGER_STATE.EXITING;                  if (mCanShowTutorial && mTriggerState == ONE_HANDED_TRIGGER_STATE.ENTERING) {                      attachTurtorialTarget(); @@ -219,7 +224,7 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback {      void dump(@NonNull PrintWriter pw) {          final String innerPrefix = "  "; -        pw.println(TAG + " states: "); +        pw.println(TAG);          pw.print(innerPrefix + "mTriggerState=");          pw.println(mTriggerState);          pw.print(innerPrefix + "mDisplayBounds="); @@ -239,15 +244,6 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback {          return true;      } -    private void onAnimationUpdate(float value) { -        if (!canShowTutorial()) { -            return; -        } -        mTargetViewContainer.setVisibility(View.VISIBLE); -        mTargetViewContainer.setTransitionGroup(true); -        mTargetViewContainer.setTranslationY(value - mTargetViewContainer.getHeight()); -    } -      /**       * onConfigurationChanged events for updating tutorial text.       * @param newConfig diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedAnimationControllerTest.java index a8feb04f31d4..af11b7ebfa3d 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedAnimationControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedAnimationControllerTest.java @@ -26,8 +26,6 @@ import android.window.WindowContainerToken;  import androidx.test.filters.SmallTest; -import com.android.wm.shell.common.ShellExecutor; -  import org.junit.Before;  import org.junit.Test;  import org.junit.runner.RunWith; @@ -43,8 +41,6 @@ import org.mockito.MockitoAnnotations;  @SmallTest  @TestableLooper.RunWithLooper(setAsMainLooper = true)  public class OneHandedAnimationControllerTest extends OneHandedTestCase { -    private static final int TEST_BOUNDS_WIDTH = 1000; -    private static final int TEST_BOUNDS_HEIGHT = 1000;      OneHandedAnimationController mOneHandedAnimationController; @@ -52,9 +48,7 @@ public class OneHandedAnimationControllerTest extends OneHandedTestCase {      private SurfaceControl mMockLeash;      @Mock      private WindowContainerToken mMockToken; - -    @Mock -    private ShellExecutor mMainExecutor; +    private Rect mDisplayBounds = new Rect();      @Before      public void setUp() throws Exception { @@ -64,12 +58,10 @@ public class OneHandedAnimationControllerTest extends OneHandedTestCase {      @Test      public void testGetAnimator_withSameBounds_returnAnimator() { -        final Rect originalBounds = new Rect(0, 0, TEST_BOUNDS_WIDTH, TEST_BOUNDS_HEIGHT); -        final Rect destinationBounds = originalBounds; -        destinationBounds.offset(0, 300); +        final float yOffset = 300;          final OneHandedAnimationController.OneHandedTransitionAnimator animator =                  mOneHandedAnimationController -                        .getAnimator(mMockToken, mMockLeash, originalBounds, destinationBounds); +                        .getAnimator(mMockToken, mMockLeash, 0, yOffset, mDisplayBounds);          assertNotNull(animator);      } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java index eb731d2c674d..a27ed114de70 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java @@ -116,7 +116,9 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase {          mDisplayLayout = new DisplayLayout(mContext, mDisplay);          mDisplayAreaInfo = new DisplayAreaInfo(mToken, DEFAULT_DISPLAY, FEATURE_ONE_HANDED);          mDisplayAreaInfo.configuration.orientation = Configuration.ORIENTATION_PORTRAIT; -        when(mMockAnimationController.getAnimator(any(), any(), any(), any())).thenReturn(null); +        when(mMockAnimationController.getAnimator(any(), any(), anyFloat(), anyFloat(), +                any())).thenReturn( +                null);          when(mMockDisplayController.getDisplay(anyInt())).thenReturn(mDisplay);          when(mMockSurfaceTransactionHelper.translate(any(), any(), anyFloat())).thenReturn(                  mMockSurfaceTransactionHelper); @@ -164,7 +166,8 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase {                          info.getDisplayAreaInfo(),                          info.getLeash())); -        verify(mMockAnimationController, never()).getAnimator(any(), any(), any(), any()); +        verify(mMockAnimationController, never()).getAnimator(any(), any(), anyFloat(), anyFloat(), +                any());      }      @Test @@ -189,7 +192,7 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase {          mSpiedDisplayAreaOrganizer.onRotateDisplay(mContext, Surface.ROTATION_90,                  mMockWindowContainerTransaction); -        verify(mSpiedDisplayAreaOrganizer).resetWindowsOffset(mMockWindowContainerTransaction); +        verify(mSpiedDisplayAreaOrganizer).resetWindowsOffset();          verify(mSpiedDisplayAreaOrganizer).finishOffset(anyInt(), anyInt());      } @@ -200,7 +203,7 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase {          mSpiedDisplayAreaOrganizer.onRotateDisplay(mContext, Surface.ROTATION_270,                  mMockWindowContainerTransaction); -        verify(mSpiedDisplayAreaOrganizer).resetWindowsOffset(mMockWindowContainerTransaction); +        verify(mSpiedDisplayAreaOrganizer).resetWindowsOffset();          verify(mSpiedDisplayAreaOrganizer).finishOffset(anyInt(), anyInt());      } @@ -213,7 +216,7 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase {          mSpiedDisplayAreaOrganizer.onRotateDisplay(mContext, Surface.ROTATION_90,                  mMockWindowContainerTransaction); -        verify(mSpiedDisplayAreaOrganizer).resetWindowsOffset(mMockWindowContainerTransaction); +        verify(mSpiedDisplayAreaOrganizer).resetWindowsOffset();          verify(mSpiedDisplayAreaOrganizer).finishOffset(anyInt(), anyInt());      } @@ -226,7 +229,7 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase {          mSpiedDisplayAreaOrganizer.onRotateDisplay(mContext, Surface.ROTATION_270,                  mMockWindowContainerTransaction); -        verify(mSpiedDisplayAreaOrganizer).resetWindowsOffset(mMockWindowContainerTransaction); +        verify(mSpiedDisplayAreaOrganizer).resetWindowsOffset();          verify(mSpiedDisplayAreaOrganizer).finishOffset(anyInt(), anyInt());      } @@ -239,7 +242,7 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase {          mSpiedDisplayAreaOrganizer.onRotateDisplay(mContext, Surface.ROTATION_0,                  mMockWindowContainerTransaction); -        verify(mSpiedDisplayAreaOrganizer).resetWindowsOffset(mMockWindowContainerTransaction); +        verify(mSpiedDisplayAreaOrganizer).resetWindowsOffset();          verify(mSpiedDisplayAreaOrganizer).finishOffset(anyInt(), anyInt());      } @@ -252,7 +255,7 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase {          mSpiedDisplayAreaOrganizer.onRotateDisplay(mContext, Surface.ROTATION_180,                  mMockWindowContainerTransaction); -        verify(mSpiedDisplayAreaOrganizer).resetWindowsOffset(mMockWindowContainerTransaction); +        verify(mSpiedDisplayAreaOrganizer).resetWindowsOffset();          verify(mSpiedDisplayAreaOrganizer).finishOffset(anyInt(), anyInt());      } @@ -265,7 +268,7 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase {          mSpiedDisplayAreaOrganizer.onRotateDisplay(mContext, Surface.ROTATION_0,                  mMockWindowContainerTransaction); -        verify(mSpiedDisplayAreaOrganizer).resetWindowsOffset(mMockWindowContainerTransaction); +        verify(mSpiedDisplayAreaOrganizer).resetWindowsOffset();          verify(mSpiedDisplayAreaOrganizer).finishOffset(anyInt(), anyInt());      } @@ -278,7 +281,7 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase {          mSpiedDisplayAreaOrganizer.onRotateDisplay(mContext, Surface.ROTATION_180,                  mMockWindowContainerTransaction); -        verify(mSpiedDisplayAreaOrganizer).resetWindowsOffset(mMockWindowContainerTransaction); +        verify(mSpiedDisplayAreaOrganizer).resetWindowsOffset();          verify(mSpiedDisplayAreaOrganizer).finishOffset(anyInt(), anyInt());      } @@ -289,8 +292,7 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase {          mSpiedDisplayAreaOrganizer.onRotateDisplay(mContext, Surface.ROTATION_0,                  mMockWindowContainerTransaction); -        verify(mSpiedDisplayAreaOrganizer, never()).resetWindowsOffset( -                mMockWindowContainerTransaction); +        verify(mSpiedDisplayAreaOrganizer, never()).resetWindowsOffset();          verify(mSpiedDisplayAreaOrganizer, never()).finishOffset(anyInt(), anyInt());      } @@ -301,7 +303,7 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase {          mSpiedDisplayAreaOrganizer.onRotateDisplay(mContext, Surface.ROTATION_180,                  mMockWindowContainerTransaction); -        verify(mSpiedDisplayAreaOrganizer).resetWindowsOffset(mMockWindowContainerTransaction); +        verify(mSpiedDisplayAreaOrganizer).resetWindowsOffset();          verify(mSpiedDisplayAreaOrganizer).finishOffset(anyInt(), anyInt());      } @@ -314,8 +316,7 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase {          mSpiedDisplayAreaOrganizer.onRotateDisplay(mContext, Surface.ROTATION_180,                  mMockWindowContainerTransaction); -        verify(mSpiedDisplayAreaOrganizer, never()).resetWindowsOffset( -                mMockWindowContainerTransaction); +        verify(mSpiedDisplayAreaOrganizer, never()).resetWindowsOffset();          verify(mSpiedDisplayAreaOrganizer, never()).finishOffset(anyInt(), anyInt());      } @@ -328,7 +329,7 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase {          mSpiedDisplayAreaOrganizer.onRotateDisplay(mContext, Surface.ROTATION_0,                  mMockWindowContainerTransaction); -        verify(mSpiedDisplayAreaOrganizer).resetWindowsOffset(mMockWindowContainerTransaction); +        verify(mSpiedDisplayAreaOrganizer).resetWindowsOffset();          verify(mSpiedDisplayAreaOrganizer).finishOffset(anyInt(), anyInt());      } @@ -341,8 +342,7 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase {          mSpiedDisplayAreaOrganizer.onRotateDisplay(mContext, Surface.ROTATION_90,                  mMockWindowContainerTransaction); -        verify(mSpiedDisplayAreaOrganizer, never()).resetWindowsOffset( -                mMockWindowContainerTransaction); +        verify(mSpiedDisplayAreaOrganizer, never()).resetWindowsOffset();          verify(mSpiedDisplayAreaOrganizer, never()).finishOffset(anyInt(), anyInt());      } @@ -355,7 +355,7 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase {          mSpiedDisplayAreaOrganizer.onRotateDisplay(mContext, Surface.ROTATION_270,                  mMockWindowContainerTransaction); -        verify(mSpiedDisplayAreaOrganizer).resetWindowsOffset(mMockWindowContainerTransaction); +        verify(mSpiedDisplayAreaOrganizer).resetWindowsOffset();          verify(mSpiedDisplayAreaOrganizer).finishOffset(anyInt(), anyInt());      } @@ -368,8 +368,7 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase {          mSpiedDisplayAreaOrganizer.onRotateDisplay(mContext, Surface.ROTATION_270,                  mMockWindowContainerTransaction); -        verify(mSpiedDisplayAreaOrganizer, never()).resetWindowsOffset( -                mMockWindowContainerTransaction); +        verify(mSpiedDisplayAreaOrganizer, never()).resetWindowsOffset();          verify(mSpiedDisplayAreaOrganizer, never()).finishOffset(anyInt(), anyInt());      } @@ -382,8 +381,7 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase {          mSpiedDisplayAreaOrganizer.onRotateDisplay(mContext, Surface.ROTATION_90,                  mMockWindowContainerTransaction); -        verify(mSpiedDisplayAreaOrganizer).resetWindowsOffset( -                mMockWindowContainerTransaction); +        verify(mSpiedDisplayAreaOrganizer).resetWindowsOffset();          verify(mSpiedDisplayAreaOrganizer).finishOffset(anyInt(), anyInt());      } @@ -406,4 +404,18 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase {          assertThat(mSpiedDisplayAreaOrganizer.getLastDisplayBounds()).isEqualTo(testBounds);      } + +    @Test +    public void testExit_must_resetWindowsOffset() { +        mSpiedDisplayAreaOrganizer.finishOffset(0, TRANSITION_DIRECTION_EXIT); + +        verify(mSpiedDisplayAreaOrganizer).resetWindowsOffset(); +    } + +    @Test +    public void testTrigger_not_resetWindowsOffset() { +        mSpiedDisplayAreaOrganizer.finishOffset(0, TRANSITION_DIRECTION_TRIGGER); + +        verify(mSpiedDisplayAreaOrganizer, never()).resetWindowsOffset(); +    }  } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedUiEventLoggerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedUiEventLoggerTest.java index e29fc6a91933..aae1dd0f726f 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedUiEventLoggerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedUiEventLoggerTest.java @@ -24,6 +24,7 @@ import com.android.internal.logging.UiEventLogger;  import com.android.internal.logging.testing.UiEventLoggerFake;  import org.junit.Before; +import org.junit.Ignore;  import org.junit.Test;  import org.junit.runner.RunWith;  import org.junit.runners.Parameterized; @@ -51,6 +52,7 @@ public class OneHandedUiEventLoggerTest extends OneHandedTestCase {      }      @Test +    @Ignore("b/184813408, go/wm-tests showing test flaky")      public void testLogEvent() {          if (mUiEvent != null) {              assertEquals(1, mUiEventLogger.numLogs()); diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h index 1e90b7c71376..17c1404c0d98 100644 --- a/libs/androidfw/include/androidfw/ResourceTypes.h +++ b/libs/androidfw/include/androidfw/ResourceTypes.h @@ -816,6 +816,11 @@ private:      uint32_t                    mSourceResourceId;  }; +static inline bool operator==(const android::ResXMLParser::ResXMLPosition& lhs, +                              const android::ResXMLParser::ResXMLPosition& rhs) { +  return lhs.curNode == rhs.curNode; +} +  class DynamicRefTable;  /** diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index f2c48bb8d2bc..02123090e1c4 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -467,6 +467,7 @@ cc_defaults {          "pipeline/skia/HolePunch.cpp",          "pipeline/skia/SkiaDisplayList.cpp",          "pipeline/skia/SkiaRecordingCanvas.cpp", +        "pipeline/skia/StretchMask.cpp",          "pipeline/skia/RenderNodeDrawable.cpp",          "pipeline/skia/ReorderBarrierDrawables.cpp",          "pipeline/skia/TransformCanvas.cpp", diff --git a/libs/hwui/DamageAccumulator.cpp b/libs/hwui/DamageAccumulator.cpp index 0bf948006ea0..94fe243378b1 100644 --- a/libs/hwui/DamageAccumulator.cpp +++ b/libs/hwui/DamageAccumulator.cpp @@ -197,6 +197,27 @@ static void applyTransforms(DirtyStack* frame, DirtyStack* end) {      }  } +static void computeTransformImpl(const DirtyStack* frame, const DirtyStack* end, +                                 Matrix4* outMatrix) { +  while (frame != end) { +    switch (frame->type) { +        case TransformRenderNode: +            frame->renderNode->applyViewPropertyTransforms(*outMatrix); +            break; +        case TransformMatrix4: +            outMatrix->multiply(*frame->matrix4); +            break; +        case TransformNone: +            // nothing to be done +            break; +        default: +            LOG_ALWAYS_FATAL("Tried to compute transform with an invalid type: %d", +                             frame->type); +    } +    frame = frame->prev; +  } +} +  void DamageAccumulator::applyRenderNodeTransform(DirtyStack* frame) {      if (frame->pendingDirty.isEmpty()) {          return; @@ -249,19 +270,38 @@ void DamageAccumulator::finish(SkRect* totalDirty) {      mHead->pendingDirty.setEmpty();  } -const StretchEffect* DamageAccumulator::findNearestStretchEffect() const { +DamageAccumulator::StretchResult DamageAccumulator::findNearestStretchEffect() const {      DirtyStack* frame = mHead;      while (frame->prev != frame) { -        frame = frame->prev;          if (frame->type == TransformRenderNode) { +            const auto& renderNode = frame->renderNode; +            const auto& frameRenderNodeProperties = renderNode->properties();              const auto& effect = -                    frame->renderNode->properties().layerProperties().getStretchEffect(); +                    frameRenderNodeProperties.layerProperties().getStretchEffect(); +            const float width = (float) renderNode->getWidth(); +            const float height = (float) renderNode->getHeight();              if (!effect.isEmpty()) { -                return &effect; +                Matrix4 stretchMatrix; +                computeTransformImpl(mHead, frame, &stretchMatrix); +                Rect stretchRect = Rect(0.f, 0.f, width, height); +                stretchMatrix.mapRect(stretchRect); + +                return StretchResult{ +                    .stretchEffect = &effect, +                    .childRelativeBounds = SkRect::MakeLTRB( +                        stretchRect.left, +                        stretchRect.top, +                        stretchRect.right, +                        stretchRect.bottom +                    ), +                    .width = width, +                    .height = height +                };              }          } +        frame = frame->prev;      } -    return nullptr; +    return StretchResult{};  }  } /* namespace uirenderer */ diff --git a/libs/hwui/DamageAccumulator.h b/libs/hwui/DamageAccumulator.h index 89ee0e34055b..90a35174d929 100644 --- a/libs/hwui/DamageAccumulator.h +++ b/libs/hwui/DamageAccumulator.h @@ -21,6 +21,7 @@  #include <SkMatrix.h>  #include <SkRect.h> +#include <effects/StretchEffect.h>  #include "utils/Macros.h" @@ -35,7 +36,6 @@ namespace uirenderer {  struct DirtyStack;  class RenderNode;  class Matrix4; -class StretchEffect;  class DamageAccumulator {      PREVENT_COPY_AND_ASSIGN(DamageAccumulator); @@ -63,7 +63,29 @@ public:      void finish(SkRect* totalDirty); -    const StretchEffect* findNearestStretchEffect() const; +    struct StretchResult { +        /** +         * Stretch parameters configured on the stretch container +         */ +        const StretchEffect* stretchEffect; + +        /** +         * Bounds of the child relative to the stretch container +         */ +        const SkRect childRelativeBounds; + +        /** +         * Width of the stretch container +         */ +        const float width; + +        /** +         * Height of the stretch container +         */ +        const float height; +    }; + +    [[nodiscard]] StretchResult findNearestStretchEffect() const;  private:      void pushCommon(); diff --git a/libs/hwui/FrameInfo.h b/libs/hwui/FrameInfo.h index 2a134fa214e7..540a88b16dc9 100644 --- a/libs/hwui/FrameInfo.h +++ b/libs/hwui/FrameInfo.h @@ -68,7 +68,7 @@ extern const std::array<const char*, static_cast<int>(FrameInfoIndex::NumIndexes  namespace FrameInfoFlags {  enum { -    WindowLayoutChanged = 1 << 0, +    WindowVisibilityChanged = 1 << 0,      RTAnimation = 1 << 1,      SurfaceCanvas = 1 << 2,      SkippedFrame = 1 << 3, diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index e9eae3d14760..fce2e1fa9970 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -194,6 +194,9 @@ void RenderNode::pushLayerUpdate(TreeInfo& info) {      SkRect dirty;      info.damageAccumulator->peekAtDirty(&dirty);      info.layerUpdateQueue->enqueueLayerWithDamage(this, dirty); +    if (!dirty.isEmpty()) { +      mStretchMask.markDirty(); +    }      // There might be prefetched layers that need to be accounted for.      // That might be us, so tell CanvasContext that this layer is in the @@ -302,6 +305,12 @@ void RenderNode::pushStagingPropertiesChanges(TreeInfo& info) {          damageSelf(info);          info.damageAccumulator->popTransform();          syncProperties(); + +        const StretchEffect& stagingStretch = +            mProperties.layerProperties().getStretchEffect(); +        if (stagingStretch.isEmpty()) { +            mStretchMask.clear(); +        }          // We could try to be clever and only re-damage if the matrix changed.          // However, we don't need to worry about that. The cost of over-damaging          // here is only going to be a single additional map rect of this node diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h index 988141fe191d..6a0b1aafd7c7 100644 --- a/libs/hwui/RenderNode.h +++ b/libs/hwui/RenderNode.h @@ -40,6 +40,7 @@  #include "pipeline/skia/SkiaLayer.h"  #include <vector> +#include <pipeline/skia/StretchMask.h>  class SkBitmap;  class SkPaint; @@ -127,6 +128,8 @@ public:          }      } +    StretchMask& getStretchMask() { return mStretchMask; } +      VirtualLightRefBase* getUserContext() const { return mUserContext.get(); }      void setUserContext(VirtualLightRefBase* context) { mUserContext = context; } @@ -286,6 +289,7 @@ private:      UsageHint mUsageHint = UsageHint::Unknown;      bool mHasHolePunches; +    StretchMask mStretchMask;      // METHODS & FIELDS ONLY USED BY THE SKIA RENDERER  public: diff --git a/libs/hwui/effects/StretchEffect.cpp b/libs/hwui/effects/StretchEffect.cpp index 6eb6e1ee4a5c..1519d69d7053 100644 --- a/libs/hwui/effects/StretchEffect.cpp +++ b/libs/hwui/effects/StretchEffect.cpp @@ -189,17 +189,12 @@ static const float ZERO = 0.f;  static const float CONTENT_DISTANCE_STRETCHED = 1.f;  static const float INTERPOLATION_STRENGTH_VALUE = 0.7f; -sk_sp<SkShader> StretchEffect::getShader(const sk_sp<SkImage>& snapshotImage) const { +sk_sp<SkShader> StretchEffect::getShader(float width, float height, +                                         const sk_sp<SkImage>& snapshotImage) const {      if (isEmpty()) {          return nullptr;      } -    if (mStretchShader != nullptr) { -        return mStretchShader; -    } - -    float viewportWidth = stretchArea.width(); -    float viewportHeight = stretchArea.height();      float normOverScrollDistX = mStretchDirection.x();      float normOverScrollDistY = mStretchDirection.y();      float distanceStretchedX = CONTENT_DISTANCE_STRETCHED / (1 + abs(normOverScrollDistX)); @@ -228,12 +223,10 @@ sk_sp<SkShader> StretchEffect::getShader(const sk_sp<SkImage>& snapshotImage) co      mBuilder->uniform("uOverscrollY").set(&normOverScrollDistY, 1);      mBuilder->uniform("uScrollX").set(&ZERO, 1);      mBuilder->uniform("uScrollY").set(&ZERO, 1); -    mBuilder->uniform("viewportWidth").set(&viewportWidth, 1); -    mBuilder->uniform("viewportHeight").set(&viewportHeight, 1); - -    mStretchShader = mBuilder->makeShader(nullptr, false); +    mBuilder->uniform("viewportWidth").set(&width, 1); +    mBuilder->uniform("viewportHeight").set(&height, 1); -    return mStretchShader; +    return mBuilder->makeShader(nullptr, false);  }  sk_sp<SkRuntimeEffect> StretchEffect::getStretchEffect() { diff --git a/libs/hwui/effects/StretchEffect.h b/libs/hwui/effects/StretchEffect.h index 546d53b1a2df..61537f0b5a2c 100644 --- a/libs/hwui/effects/StretchEffect.h +++ b/libs/hwui/effects/StretchEffect.h @@ -26,19 +26,15 @@  namespace android::uirenderer { -// TODO: Inherit from base RenderEffect type?  class StretchEffect {  public: -    enum class StretchInterpolator { -        SmoothStep, -    }; -    StretchEffect(const SkRect& area, const SkVector& direction, float maxStretchAmountX, +    StretchEffect(const SkVector& direction, +                  float maxStretchAmountX,                    float maxStretchAmountY) -            : stretchArea(area) -            , maxStretchAmountX(maxStretchAmountX) +            : maxStretchAmountX(maxStretchAmountX)              , maxStretchAmountY(maxStretchAmountY) -            , mStretchDirection(direction) {} +            , mStretchDirection(direction) { }      StretchEffect() {} @@ -51,14 +47,18 @@ public:      }      StretchEffect& operator=(const StretchEffect& other) { -        this->stretchArea = other.stretchArea;          this->mStretchDirection = other.mStretchDirection; -        this->mStretchShader = other.mStretchShader;          this->maxStretchAmountX = other.maxStretchAmountX;          this->maxStretchAmountY = other.maxStretchAmountY;          return *this;      } +    bool operator==(const StretchEffect& other) const { +        return mStretchDirection == other.mStretchDirection && +                maxStretchAmountX == other.maxStretchAmountX && +                maxStretchAmountY == other.maxStretchAmountY; +    } +      void mergeWith(const StretchEffect& other) {          if (other.isEmpty()) {              return; @@ -67,33 +67,26 @@ public:              *this = other;              return;          } -        setStretchDirection(mStretchDirection + other.mStretchDirection); +        mStretchDirection += other.mStretchDirection;          if (isEmpty()) {              return setEmpty();          } -        stretchArea.join(other.stretchArea);          maxStretchAmountX = std::max(maxStretchAmountX, other.maxStretchAmountX);          maxStretchAmountY = std::max(maxStretchAmountY, other.maxStretchAmountY);      } -    sk_sp<SkShader> getShader(const sk_sp<SkImage>& snapshotImage) const; +    sk_sp<SkShader> getShader(float width, float height, +                              const sk_sp<SkImage>& snapshotImage) const; -    SkRect stretchArea {0, 0, 0, 0};      float maxStretchAmountX = 0;      float maxStretchAmountY = 0; -    void setStretchDirection(const SkVector& direction) { -        mStretchShader = nullptr; -        mStretchDirection = direction; -    } -      const SkVector getStretchDirection() const { return mStretchDirection; }  private:      static sk_sp<SkRuntimeEffect> getStretchEffect();      mutable SkVector mStretchDirection{0, 0};      mutable std::unique_ptr<SkRuntimeShaderBuilder> mBuilder; -    mutable sk_sp<SkShader> mStretchShader;  };  } // namespace android::uirenderer diff --git a/libs/hwui/jni/android_graphics_RenderNode.cpp b/libs/hwui/jni/android_graphics_RenderNode.cpp index fffa80614370..5131c646c4a4 100644 --- a/libs/hwui/jni/android_graphics_RenderNode.cpp +++ b/libs/hwui/jni/android_graphics_RenderNode.cpp @@ -180,12 +180,10 @@ static jboolean android_view_RenderNode_clearStretch(CRITICAL_JNI_PARAMS_COMMA j  }  static jboolean android_view_RenderNode_stretch(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr, -                                                jfloat left, jfloat top, jfloat right, -                                                jfloat bottom, jfloat vX, jfloat vY, jfloat maxX, +                                                jfloat vX, jfloat vY, jfloat maxX,                                                  jfloat maxY) { -    StretchEffect effect = StretchEffect(SkRect::MakeLTRB(left, top, right, bottom), -                                         {.fX = vX, .fY = vY}, maxX, maxY); -    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); +    auto* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); +    StretchEffect effect = StretchEffect({.fX = vX, .fY = vY}, maxX, maxY);      renderNode->mutateStagingProperties().mutateLayerProperties().mutableStretchEffect().mergeWith(              effect);      renderNode->setPropertyFieldsDirty(RenderNode::GENERIC); @@ -643,13 +641,15 @@ static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject,          void handleStretchEffect(const TreeInfo& info, const Matrix4& transform) {              // Search up to find the nearest stretcheffect parent -            const StretchEffect* effect = info.damageAccumulator->findNearestStretchEffect(); +            const DamageAccumulator::StretchResult result = +                info.damageAccumulator->findNearestStretchEffect(); +            const StretchEffect* effect = result.stretchEffect;              if (!effect) {                  return;              } -            uirenderer::Rect area = effect->stretchArea; -            transform.mapRect(area); +            const auto& childRelativeBounds = result.childRelativeBounds; +              JNIEnv* env = jnienv();              jobject localref = env->NewLocalRef(mWeakRef); @@ -661,9 +661,17 @@ static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject,  #ifdef __ANDROID__  // Layoutlib does not support CanvasContext              SkVector stretchDirection = effect->getStretchDirection();              env->CallVoidMethod(localref, gPositionListener_ApplyStretchMethod, -                                info.canvasContext.getFrameNumber(), area.left, area.top, -                                area.right, area.bottom, stretchDirection.fX, stretchDirection.fY, -                                effect->maxStretchAmountX, effect->maxStretchAmountY); +                                info.canvasContext.getFrameNumber(), +                                result.width, +                                result.height, +                                stretchDirection.fX, +                                stretchDirection.fY, +                                effect->maxStretchAmountX, +                                effect->maxStretchAmountY, +                                childRelativeBounds.left(), +                                childRelativeBounds.top(), +                                childRelativeBounds.right(), +                                childRelativeBounds.bottom());  #endif              env->DeleteLocalRef(localref);          } @@ -739,7 +747,7 @@ static const JNINativeMethod gMethods[] = {          {"nSetOutlineEmpty", "(J)Z", (void*)android_view_RenderNode_setOutlineEmpty},          {"nSetOutlineNone", "(J)Z", (void*)android_view_RenderNode_setOutlineNone},          {"nClearStretch", "(J)Z", (void*)android_view_RenderNode_clearStretch}, -        {"nStretch", "(JFFFFFFFF)Z", (void*)android_view_RenderNode_stretch}, +        {"nStretch", "(JFFFF)Z", (void*)android_view_RenderNode_stretch},          {"nHasShadow", "(J)Z", (void*)android_view_RenderNode_hasShadow},          {"nSetSpotShadowColor", "(JI)Z", (void*)android_view_RenderNode_setSpotShadowColor},          {"nGetSpotShadowColor", "(J)I", (void*)android_view_RenderNode_getSpotShadowColor}, @@ -814,7 +822,7 @@ int register_android_view_RenderNode(JNIEnv* env) {      gPositionListener_PositionChangedMethod = GetMethodIDOrDie(env, clazz,              "positionChanged", "(JIIII)V");      gPositionListener_ApplyStretchMethod = -            GetMethodIDOrDie(env, clazz, "applyStretch", "(JFFFFFFF)V"); +            GetMethodIDOrDie(env, clazz, "applyStretch", "(JFFFFFFFFFF)V");      gPositionListener_PositionLostMethod = GetMethodIDOrDie(env, clazz,              "positionLost", "(J)V");      return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods)); diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp index 77d99a67b602..1ae06d082744 100644 --- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp +++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp @@ -16,6 +16,7 @@  #include "RenderNodeDrawable.h"  #include <SkPaintFilterCanvas.h> +#include "StretchMask.h"  #include "RenderNode.h"  #include "SkiaDisplayList.h"  #include "TransformCanvas.h" @@ -245,17 +246,37 @@ void RenderNodeDrawable::drawContent(SkCanvas* canvas) const {                      "SurfaceID|%" PRId64, renderNode->uniqueId()).c_str(), nullptr);              } -            if (renderNode->hasHolePunches()) { -                TransformCanvas transformCanvas(canvas); -                displayList->draw(&transformCanvas); -            } -              const StretchEffect& stretch = properties.layerProperties().getStretchEffect();              if (stretch.isEmpty()) { +                // If we don't have any stretch effects, issue the filtered +                // canvas draw calls to make sure we still punch a hole +                // with the same canvas transformation + clip into the target +                // canvas then draw the layer on top +                if (renderNode->hasHolePunches()) { +                    TransformCanvas transformCanvas(canvas, SkBlendMode::kClear); +                    displayList->draw(&transformCanvas); +                }                  canvas->drawImageRect(snapshotImage, bounds, bounds, sampling, &paint,                                        SkCanvas::kStrict_SrcRectConstraint);              } else { -                sk_sp<SkShader> stretchShader = stretch.getShader(snapshotImage); +                // If we do have stretch effects and have hole punches, +                // then create a mask and issue the filtered draw calls to +                // get the corresponding hole punches. +                // Then apply the stretch to the mask and draw the mask to +                // the destination +                if (renderNode->hasHolePunches()) { +                    GrRecordingContext* context = canvas->recordingContext(); +                    StretchMask& stretchMask = renderNode->getStretchMask(); +                    stretchMask.draw(context, +                                     stretch, +                                     bounds, +                                     displayList, +                                     canvas); +                } + +                sk_sp<SkShader> stretchShader = stretch.getShader(bounds.width(), +                                                                  bounds.height(), +                                                                  snapshotImage);                  paint.setShader(stretchShader);                  canvas->drawRect(bounds, paint);              } diff --git a/libs/hwui/pipeline/skia/StretchMask.cpp b/libs/hwui/pipeline/skia/StretchMask.cpp new file mode 100644 index 000000000000..2bbd8a4fa028 --- /dev/null +++ b/libs/hwui/pipeline/skia/StretchMask.cpp @@ -0,0 +1,64 @@ +/* + * 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 "StretchMask.h" +#include "SkSurface.h" +#include "SkCanvas.h" +#include "TransformCanvas.h" +#include "SkiaDisplayList.h" + +using android::uirenderer::StretchMask; + +void StretchMask::draw(GrRecordingContext* context, +                       const StretchEffect& stretch, +                       const SkRect& bounds, +                       skiapipeline::SkiaDisplayList* displayList, +                       SkCanvas* canvas) { +    float width = bounds.width(); +    float height = bounds.height(); +    if (mMaskSurface == nullptr || mMaskSurface->width() != width || +        mMaskSurface->height() != height) { +        // Create a new surface if we don't have one or our existing size does +        // not match. +        mMaskSurface = SkSurface::MakeRenderTarget( +            context, +            SkBudgeted::kYes, +            SkImageInfo::Make( +                width, +                height, +                SkColorType::kAlpha_8_SkColorType, +                SkAlphaType::kPremul_SkAlphaType) +        ); +        mIsDirty = true; +    } + +    if (mIsDirty) { +        SkCanvas* maskCanvas = mMaskSurface->getCanvas(); +        maskCanvas->drawColor(0, SkBlendMode::kClear); +        TransformCanvas transformCanvas(maskCanvas, SkBlendMode::kSrcOver); +        displayList->draw(&transformCanvas); +    } + +    sk_sp<SkImage> maskImage = mMaskSurface->makeImageSnapshot(); +    sk_sp<SkShader> maskStretchShader = stretch.getShader( +        width, height, maskImage); + +    SkPaint maskPaint; +    maskPaint.setShader(maskStretchShader); +    maskPaint.setBlendMode(SkBlendMode::kDstOut); +    canvas->drawRect(bounds, maskPaint); + +    mIsDirty = false; +}
\ No newline at end of file diff --git a/libs/hwui/pipeline/skia/StretchMask.h b/libs/hwui/pipeline/skia/StretchMask.h new file mode 100644 index 000000000000..dc698b8e57ff --- /dev/null +++ b/libs/hwui/pipeline/skia/StretchMask.h @@ -0,0 +1,62 @@ +/* + * 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. + */ +#pragma once + +#include "GrRecordingContext.h" +#include <effects/StretchEffect.h> +#include <SkSurface.h> +#include "SkiaDisplayList.h" + +namespace android::uirenderer { + +/** + * Helper class used to create/cache an SkSurface instance + * to create a mask that is used to draw a stretched hole punch + */ +class StretchMask { + public: +  /** +   * Release the current surface used for the stretch mask +   */ +  void clear() { +      mMaskSurface = nullptr; +  } + +  /** +   * Reset the dirty flag to re-create the stretch mask on the next draw +   * pass +   */ +  void markDirty() { +      mIsDirty = true; +  } + +  /** +   * Draws the stretch mask into the given target canvas +   * @param context GrRecordingContext used to create the surface if necessary +   * @param stretch StretchEffect to apply to the mask +   * @param bounds Target bounds to draw into the given canvas +   * @param displayList List of drawing commands to render into the stretch mask +   * @param canvas Target canvas to draw the mask into +   */ +  void draw(GrRecordingContext* context, +            const StretchEffect& stretch, const SkRect& bounds, +            skiapipeline::SkiaDisplayList* displayList, SkCanvas* canvas); +private: +  sk_sp<SkSurface> mMaskSurface; +  bool mIsDirty = true; +}; + +} diff --git a/libs/hwui/pipeline/skia/TransformCanvas.cpp b/libs/hwui/pipeline/skia/TransformCanvas.cpp index a6e4c4cf9ca7..6777c00c4655 100644 --- a/libs/hwui/pipeline/skia/TransformCanvas.cpp +++ b/libs/hwui/pipeline/skia/TransformCanvas.cpp @@ -28,8 +28,8 @@ void TransformCanvas::onDrawAnnotation(const SkRect& rect, const char* key, SkDa          SkRRect roundRect = SkRRect::MakeRectXY(rect, radiusX, radiusY);          SkPaint paint; -        paint.setColor(0); -        paint.setBlendMode(SkBlendMode::kClear); +        paint.setColor(SkColors::kBlack); +        paint.setBlendMode(mHolePunchBlendMode);          mWrappedCanvas->drawRRect(roundRect, paint);      }  } diff --git a/libs/hwui/pipeline/skia/TransformCanvas.h b/libs/hwui/pipeline/skia/TransformCanvas.h index 47f77f107441..685b71d017e9 100644 --- a/libs/hwui/pipeline/skia/TransformCanvas.h +++ b/libs/hwui/pipeline/skia/TransformCanvas.h @@ -17,10 +17,12 @@  #include <include/core/SkCanvas.h>  #include "SkPaintFilterCanvas.h" +#include <effects/StretchEffect.h>  class TransformCanvas : public SkPaintFilterCanvas {  public: -    TransformCanvas(SkCanvas* target) : SkPaintFilterCanvas(target), mWrappedCanvas(target) {} +    TransformCanvas(SkCanvas* target, SkBlendMode blendmode) : +        SkPaintFilterCanvas(target), mWrappedCanvas(target), mHolePunchBlendMode(blendmode) {}  protected:      bool onFilter(SkPaint& paint) const override; @@ -32,4 +34,5 @@ protected:  private:      // We don't own the canvas so just maintain a raw pointer to it      SkCanvas* mWrappedCanvas; +    const SkBlendMode mHolePunchBlendMode;  }; diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index c1d672524ac5..5952479da702 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -360,6 +360,9 @@ public class LocationManager {          }      } +    private static volatile LocationEnabledCache sLocationEnabledCache = +            new LocationEnabledCache(4); +      @GuardedBy("sLocationListeners")      private static final WeakHashMap<LocationListener, WeakReference<LocationListenerTransport>>              sLocationListeners = new WeakHashMap<>(); @@ -386,20 +389,6 @@ public class LocationManager {      final Context mContext;      final ILocationManager mService; -    private volatile PropertyInvalidatedCache<Integer, Boolean> mLocationEnabledCache = -            new PropertyInvalidatedCache<Integer, Boolean>( -                    4, -                    CACHE_KEY_LOCATION_ENABLED_PROPERTY) { -                @Override -                protected Boolean recompute(Integer userHandle) { -                    try { -                        return mService.isLocationEnabledForUser(userHandle); -                    } catch (RemoteException e) { -                        throw e.rethrowFromSystemServer(); -                    } -                } -            }; -      /**       * @hide       */ @@ -533,7 +522,7 @@ public class LocationManager {       * @return true if location is enabled and false if location is disabled.       */      public boolean isLocationEnabled() { -        return isLocationEnabledForUser(Process.myUserHandle()); +        return isLocationEnabledForUser(mContext.getUser());      }      /** @@ -546,12 +535,17 @@ public class LocationManager {       */      @SystemApi      public boolean isLocationEnabledForUser(@NonNull UserHandle userHandle) { -        PropertyInvalidatedCache<Integer, Boolean> cache = mLocationEnabledCache; -        if (cache != null) { -            return cache.query(userHandle.getIdentifier()); +        // skip the cache for any "special" user ids - special ids like CURRENT_USER may change +        // their meaning over time and should never be in the cache. we could resolve the special +        // user ids here, but that would require an x-process call anyways, and the whole point of +        // the cache is to avoid x-process calls. +        if (userHandle.getIdentifier() >= 0) { +            PropertyInvalidatedCache<Integer, Boolean> cache = sLocationEnabledCache; +            if (cache != null) { +                return cache.query(userHandle.getIdentifier()); +            }          } -        // fallback if cache is disabled          try {              return mService.isLocationEnabledForUser(userHandle.getIdentifier());          } catch (RemoteException e) { @@ -3004,7 +2998,7 @@ public class LocationManager {              ListenerExecutor, CancellationSignal.OnCancelListener {          private final Executor mExecutor; -        private volatile @Nullable Consumer<Location> mConsumer; +        volatile @Nullable Consumer<Location> mConsumer;          GetCurrentLocationTransport(Executor executor, Consumer<Location> consumer,                  @Nullable CancellationSignal cancellationSignal) { @@ -3465,6 +3459,37 @@ public class LocationManager {          }      } +    private static class LocationEnabledCache extends PropertyInvalidatedCache<Integer, Boolean> { + +        // this is not loaded immediately because this class is created as soon as LocationManager +        // is referenced for the first time, and within the system server, the ILocationManager +        // service may not have been loaded yet at that time. +        private @Nullable ILocationManager mManager; + +        LocationEnabledCache(int numEntries) { +            super(numEntries, CACHE_KEY_LOCATION_ENABLED_PROPERTY); +        } + +        @Override +        protected Boolean recompute(Integer userId) { +            Preconditions.checkArgument(userId >= 0); + +            if (mManager == null) { +                try { +                    mManager = getService(); +                } catch (RemoteException e) { +                    e.rethrowFromSystemServer(); +                } +            } + +            try { +                return mManager.isLocationEnabledForUser(userId); +            } catch (RemoteException e) { +                throw e.rethrowFromSystemServer(); +            } +        } +    } +      /**       * @hide       */ @@ -3475,7 +3500,7 @@ public class LocationManager {      /**       * @hide       */ -    public void disableLocalLocationEnabledCaches() { -        mLocationEnabledCache = null; +    public static void disableLocalLocationEnabledCaches() { +        sLocationEnabledCache = null;      }  } diff --git a/mime/java/android/content/type/DefaultMimeMapFactory.java b/mime/java/android/content/type/DefaultMimeMapFactory.java index 11d20d4d6c80..bcd0eb0a9e39 100644 --- a/mime/java/android/content/type/DefaultMimeMapFactory.java +++ b/mime/java/android/content/type/DefaultMimeMapFactory.java @@ -96,7 +96,7 @@ public class DefaultMimeMapFactory {                      specs.add(spec);                      startIdx = endIdx + 1; // skip over the space                  } while (startIdx < line.length()); -                builder.put(specs.get(0), specs.subList(1, specs.size())); +                builder.addMimeMapping(specs.get(0), specs.subList(1, specs.size()));              }          } catch (IOException | RuntimeException e) {              throw new RuntimeException("Failed to parse " + resourceName, e); diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/DeleteStagedFileOnResult.java b/packages/PackageInstaller/src/com/android/packageinstaller/DeleteStagedFileOnResult.java index 399cf1f5e0d6..33e5231acee5 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/DeleteStagedFileOnResult.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/DeleteStagedFileOnResult.java @@ -42,10 +42,17 @@ public class DeleteStagedFileOnResult extends Activity {      @Override      protected void onActivityResult(int requestCode, int resultCode, Intent data) { -        File sourceFile = new File(getIntent().getData().getPath()); -        sourceFile.delete(); -          setResult(resultCode, data);          finish();      } + +    @Override +    protected void onDestroy() { +        super.onDestroy(); + +        if (isFinishing()) { +            File sourceFile = new File(getIntent().getData().getPath()); +            new Thread(sourceFile::delete).start(); +        } +    }  } diff --git a/packages/SettingsLib/TopIntroPreference/src/com/android/settingslib/widget/TopIntroPreference.java b/packages/SettingsLib/TopIntroPreference/src/com/android/settingslib/widget/TopIntroPreference.java index 9c82907da72a..778537b0a2fc 100644 --- a/packages/SettingsLib/TopIntroPreference/src/com/android/settingslib/widget/TopIntroPreference.java +++ b/packages/SettingsLib/TopIntroPreference/src/com/android/settingslib/widget/TopIntroPreference.java @@ -39,11 +39,4 @@ public class TopIntroPreference extends Preference {          setLayoutResource(R.layout.top_intro_preference);          setSelectable(false);      } - -    @Override -    public void onBindViewHolder(PreferenceViewHolder holder) { -        super.onBindViewHolder(holder); -        holder.setDividerAllowedAbove(true); -        holder.setDividerAllowedBelow(true); -    }  } diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java index f180776bbe93..f046f06cc691 100644 --- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java +++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java @@ -2027,6 +2027,7 @@ public class ApplicationsState {                  }              }; +    /* For the Storage Settings which shows category of app types. */      public static final AppFilter FILTER_OTHER_APPS =              new AppFilter() {                  @Override @@ -2046,4 +2047,21 @@ public class ApplicationsState {                      return !isCategorized;                  }              }; + +    /* For the Storage Settings which shows category of file types. */ +    public static final AppFilter FILTER_APPS_EXCEPT_GAMES = +            new AppFilter() { +                @Override +                public void init() { +                } + +                @Override +                public boolean filterApp(AppEntry entry) { +                    boolean isCategorized; +                    synchronized (entry) { +                        isCategorized = FILTER_GAMES.filterApp(entry); +                    } +                    return !isCategorized; +                } +            };  } diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/applications/ApplicationsStateTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/applications/ApplicationsStateTest.java index d9ac262f4414..f1e1e7d920cc 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/applications/ApplicationsStateTest.java +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/applications/ApplicationsStateTest.java @@ -138,6 +138,34 @@ public class ApplicationsStateTest {      }      @Test +    public void testAppsExceptGamesFilterRejectsGame() { +        mEntry.info.category = ApplicationInfo.CATEGORY_GAME; + +        assertThat(ApplicationsState.FILTER_APPS_EXCEPT_GAMES.filterApp(mEntry)).isFalse(); +    } + +    @Test +    public void testAppsExceptGamesFilterAcceptsImage() { +        mEntry.info.category = ApplicationInfo.CATEGORY_IMAGE; + +        assertThat(ApplicationsState.FILTER_APPS_EXCEPT_GAMES.filterApp(mEntry)).isTrue(); +    } + +    @Test +    public void testAppsExceptGamesFilterAcceptsVideo() { +        mEntry.info.category = ApplicationInfo.CATEGORY_VIDEO; + +        assertThat(ApplicationsState.FILTER_APPS_EXCEPT_GAMES.filterApp(mEntry)).isTrue(); +    } + +    @Test +    public void testAppsExceptGamesFilterAcceptsAudio() { +        mEntry.info.category = ApplicationInfo.CATEGORY_AUDIO; + +        assertThat(ApplicationsState.FILTER_APPS_EXCEPT_GAMES.filterApp(mEntry)).isTrue(); +    } + +    @Test      public void testDownloadAndLauncherAndInstantAcceptsCorrectApps() {          // should include instant apps          mEntry.isHomeApp = false; diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp index 8b226c926c99..4f587ebba89c 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -50,13 +50,6 @@ java_library {      srcs: ["src/com/android/systemui/EventLogTags.logtags"],  } -java_library { -    name: "SystemUI-sensors", -    srcs: [ -        "src/com/android/systemui/util/sensors/ThresholdSensor.java", -    ], -} -  android_library {      name: "SystemUI-core",      srcs: [ diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 173e95954014..d6989753f16e 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -62,11 +62,13 @@      <!-- Networking and telephony -->      <uses-permission android:name="android.permission.BLUETOOTH" />      <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> -    <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE"/> -    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> -    <uses-permission android:name="android.permission.BLUETOOTH_SCAN" /> +    <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" +            android:usesPermissionFlags="neverForLocation" /> +    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" +            android:usesPermissionFlags="neverForLocation" /> +    <uses-permission android:name="android.permission.BLUETOOTH_SCAN" +            android:usesPermissionFlags="neverForLocation" />      <uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" /> -    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>      <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />      <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />      <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" /> diff --git a/packages/SystemUI/animation/Android.bp b/packages/SystemUI/animation/Android.bp index ab9ab831157c..1b15d20d2c52 100644 --- a/packages/SystemUI/animation/Android.bp +++ b/packages/SystemUI/animation/Android.bp @@ -36,7 +36,6 @@ android_library {      static_libs: [          "PluginCoreLib", -        "SystemUI-sensors",      ],      manifest: "AndroidManifest.xml", diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt index 20273d05f059..1cf0c5f52bb4 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt @@ -17,6 +17,7 @@ import android.view.RemoteAnimationAdapter  import android.view.RemoteAnimationTarget  import android.view.SyncRtSurfaceTransactionApplier  import android.view.View +import android.view.ViewGroup  import android.view.WindowManager  import android.view.animation.AnimationUtils  import android.view.animation.PathInterpolator @@ -112,7 +113,7 @@ class ActivityLaunchAnimator(context: Context) {      @PublishedApi      internal fun Controller.callOnIntentStartedOnMainThread(willAnimate: Boolean) {          if (Looper.myLooper() != Looper.getMainLooper()) { -            this.getRootView().context.mainExecutor.execute { +            this.launchContainer.context.mainExecutor.execute {                  this.onIntentStarted(willAnimate)              }          } else { @@ -166,15 +167,19 @@ class ActivityLaunchAnimator(context: Context) {          }          /** -         * Return the root [View] that contains the view that started the intent and will be -         * animating together with the window. +         * The container in which the view that started the intent will be animating together with +         * the opening window.           * -         * This view will be used to: +         * This will be used to:           *  - Get the associated [Context].           *  - Compute whether we are expanding fully above the current window.           *  - Apply surface transactions in sync with RenderThread. +         * +         * This container can be changed to force this [Controller] to animate the expanding view +         * inside a different location, for instance to ensure correct layering during the +         * animation.           */ -        fun getRootView(): View +        var launchContainer: ViewGroup          /**           * Return the [State] of the view that will be animated. We will animate from this state to @@ -272,9 +277,9 @@ class ActivityLaunchAnimator(context: Context) {      @VisibleForTesting      inner class Runner(private val controller: Controller) : IRemoteAnimationRunner.Stub() { -        private val rootView = controller.getRootView() -        @PublishedApi internal val context = rootView.context -        private val transactionApplier = SyncRtSurfaceTransactionApplier(rootView) +        private val launchContainer = controller.launchContainer +        @PublishedApi internal val context = launchContainer.context +        private val transactionApplier = SyncRtSurfaceTransactionApplier(launchContainer)          private var animator: ValueAnimator? = null          private var windowCrop = Rect() @@ -291,11 +296,11 @@ class ActivityLaunchAnimator(context: Context) {          @PublishedApi          internal fun postTimeout() { -            rootView.postDelayed(onTimeout, LAUNCH_TIMEOUT) +            launchContainer.postDelayed(onTimeout, LAUNCH_TIMEOUT)          }          private fun removeTimeout() { -            rootView.removeCallbacks(onTimeout) +            launchContainer.removeCallbacks(onTimeout)          }          override fun onAnimationStart( @@ -369,11 +374,11 @@ class ActivityLaunchAnimator(context: Context) {              val endWidth = endRight - endLeft              // TODO(b/184121838): Ensure that we are launching on the same screen. -            val rootViewLocation = rootView.locationOnScreen +            val rootViewLocation = launchContainer.locationOnScreen              val isExpandingFullyAbove = endTop <= rootViewLocation[1] && -                endBottom >= rootViewLocation[1] + rootView.height && +                endBottom >= rootViewLocation[1] + launchContainer.height &&                  endLeft <= rootViewLocation[0] && -                endRight >= rootViewLocation[0] + rootView.width +                endRight >= rootViewLocation[0] + launchContainer.width              // TODO(b/184121838): We should somehow get the top and bottom radius of the window.              val endRadius = if (isExpandingFullyAbove) { diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/DelegateLaunchAnimatorController.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/DelegateLaunchAnimatorController.kt new file mode 100644 index 000000000000..d4be25382395 --- /dev/null +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/DelegateLaunchAnimatorController.kt @@ -0,0 +1,10 @@ +package com.android.systemui.animation + +/** + * A base class to easily create an implementation of [ActivityLaunchAnimator.Controller] which + * delegates most of its call to [delegate]. This is mostly useful for Java code which can't easily + * create such a delegated class. + */ +open class DelegateLaunchAnimatorController( +    protected val delegate: ActivityLaunchAnimator.Controller +) : ActivityLaunchAnimator.Controller by delegate
\ No newline at end of file diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt index 3da45210e8c2..ce9feede8759 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt @@ -14,6 +14,7 @@ import android.graphics.drawable.LayerDrawable  import android.view.GhostView  import android.view.View  import android.view.ViewGroup +import android.view.ViewGroupOverlay  import android.widget.FrameLayout  import kotlin.math.min @@ -32,9 +33,10 @@ open class GhostedViewLaunchAnimatorController(      /** The view that will be ghosted and from which the background will be extracted. */      private val ghostedView: View  ) : ActivityLaunchAnimator.Controller { -    /** The root view to which we will add the ghost view and expanding background. */ -    private val rootView = ghostedView.rootView as ViewGroup -    private val rootViewOverlay = rootView.overlay +    /** The container to which we will add the ghost view and expanding background. */ +    override var launchContainer = ghostedView.rootView as ViewGroup +    private val launchContainerOverlay: ViewGroupOverlay +        get() = launchContainer.overlay      /** The ghost view that is drawn and animated instead of the ghosted view. */      private var ghostView: GhostView? = null @@ -42,7 +44,7 @@ open class GhostedViewLaunchAnimatorController(      private val ghostViewMatrix = Matrix()      /** -     * The expanding background view that will be added to [rootView] (below [ghostView]) and +     * The expanding background view that will be added to [launchContainer] (below [ghostView]) and       * animate.       */      private var backgroundView: FrameLayout? = null @@ -96,10 +98,6 @@ open class GhostedViewLaunchAnimatorController(          return gradient.cornerRadii?.get(CORNER_RADIUS_BOTTOM_INDEX) ?: gradient.cornerRadius      } -    override fun getRootView(): View { -        return rootView -    } -      override fun createAnimatorState(): ActivityLaunchAnimator.State {          val location = ghostedView.locationOnScreen          return ActivityLaunchAnimator.State( @@ -113,10 +111,10 @@ open class GhostedViewLaunchAnimatorController(      }      override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) { -        backgroundView = FrameLayout(rootView.context).apply { +        backgroundView = FrameLayout(launchContainer.context).apply {              forceHasOverlappingRendering(false)          } -        rootViewOverlay.add(backgroundView) +        launchContainerOverlay.add(backgroundView)          // We wrap the ghosted view background and use it to draw the expandable background. Its          // alpha will be set to 0 as soon as we start drawing the expanding background. @@ -127,7 +125,7 @@ open class GhostedViewLaunchAnimatorController(          // Create a ghost of the view that will be moving and fading out. This allows to fade out          // the content before fading out the background. -        ghostView = GhostView.addGhost(ghostedView, rootView).apply { +        ghostView = GhostView.addGhost(ghostedView, launchContainer).apply {              setLayerType(View.LAYER_TYPE_HARDWARE, null)          } @@ -169,7 +167,7 @@ open class GhostedViewLaunchAnimatorController(          backgroundDrawable?.wrapped?.alpha = startBackgroundAlpha          GhostView.removeGhost(ghostedView) -        rootViewOverlay.remove(backgroundView) +        launchContainerOverlay.remove(backgroundView)          ghostedView.invalidate()      } diff --git a/packages/SystemUI/plugin/Android.bp b/packages/SystemUI/plugin/Android.bp index 9f02fdbf3ec9..cafaaf854eed 100644 --- a/packages/SystemUI/plugin/Android.bp +++ b/packages/SystemUI/plugin/Android.bp @@ -34,7 +34,6 @@ java_library {      static_libs: [          "androidx.annotation_annotation",          "PluginCoreLib", -        "SystemUI-sensors",          "SystemUIAnimationLib",      ], diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java index b75252b46785..5ac8961aceeb 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java @@ -21,7 +21,6 @@ import android.net.Uri;  import android.view.MotionEvent;  import com.android.systemui.plugins.annotations.ProvidesInterface; -import com.android.systemui.util.sensors.ThresholdSensor;  import java.io.FileDescriptor;  import java.io.PrintWriter; @@ -118,7 +117,7 @@ public interface FalsingManager {      void cleanup();      /** Call to report a ProximityEvent to the FalsingManager. */ -    void onProximityEvent(ThresholdSensor.ThresholdSensorEvent proximityEvent); +    void onProximityEvent(ProximityEvent proximityEvent);      /** Adds a {@link FalsingBeliefListener}. */      void addFalsingBeliefListener(FalsingBeliefListener listener); @@ -141,4 +140,13 @@ public interface FalsingManager {      interface FalsingTapListener {          void onDoubleTapRequired();      } + +    /** Passed to {@link FalsingManager#onProximityEvent}. */ +    interface ProximityEvent { +        /** Returns true when the proximity sensor was covered. */ +        boolean getCovered(); + +        /** Returns when the proximity sensor was covered in nanoseconds. */ +        long getTimestampNs(); +    }  } diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml index 1a38585ea78d..ce63082868bb 100644 --- a/packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml +++ b/packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml @@ -40,7 +40,7 @@          android:clipToPadding="false">          <LinearLayout -            android:id="@+id/container" +            android:id="@+id/pattern_container"              android:layout_height="wrap_content"              android:layout_width="wrap_content"              android:orientation="vertical" diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml index 50ffbc802a7d..c64afd307f23 100644 --- a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml +++ b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml @@ -27,7 +27,7 @@          android:orientation="vertical"          >      <LinearLayout -            android:id="@+id/container" +            android:id="@+id/pin_container"              android:layout_width="match_parent"              android:layout_height="0dp"              android:orientation="vertical" diff --git a/packages/SystemUI/res/drawable/ic_qs_no_calling_sms.xml b/packages/SystemUI/res/drawable/ic_qs_no_calling_sms.xml index 0e308d2f5bfb..da581061370b 100644 --- a/packages/SystemUI/res/drawable/ic_qs_no_calling_sms.xml +++ b/packages/SystemUI/res/drawable/ic_qs_no_calling_sms.xml @@ -1,12 +1,24 @@ +<!-- +    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. +-->  <vector xmlns:android="http://schemas.android.com/apk/res/android" -        android:width="24dp" -        android:height="24dp" -        android:viewportWidth="24.0" -        android:viewportHeight="24.0"> +        android:width="16dp" +        android:height="16dp" +        android:viewportWidth="16.0" +        android:viewportHeight="16.0">      <path          android:fillColor="#FF000000" -        android:pathData="M20.17,14.84l-3.26,-0.65c-0.33,-0.07 -0.67,0.04 -0.9,0.27l-2.62,2.62c-2.75,-1.49 -5.01,-3.75 -6.5,-6.5l2.62,-2.62c0.24,-0.24 0.34,-0.58 0.27,-0.9L9.13,3.8C9.04,3.34 8.63,3 8.15,3H4C3.44,3 2.97,3.47 3,4.03c0.17,2.91 1.04,5.63 2.43,8.01c1.57,2.69 3.81,4.93 6.5,6.5c2.38,1.39 5.1,2.26 8.01,2.43c0.56,0.03 1.03,-0.44 1.03,-1v-4.15C20.97,15.34 20.64,14.93 20.17,14.84z"/> -    <path -        android:fillColor="#FF000000" -        android:pathData="M22,3.41L20.59,2L18.5,4.09L16.41,2L15,3.41l2.09,2.09L15,7.59L16.41,9l2.09,-2.08L20.59,9L22,7.59L19.92,5.5L22,3.41z"/> +        android:pathData="M6.52,11.37c0.46,0.37 0.94,0.7 1.45,0.99c1.59,0.93 3.4,1.51 5.34,1.62C13.69,14 14,13.69 14,13.31v-2.77c0,-0.32 -0.23,-0.59 -0.53,-0.65l-2.17,-0.43c-0.22,-0.05 -0.45,0.03 -0.6,0.18l-1.75,1.75c-0.52,-0.28 -1.01,-0.61 -1.48,-0.97l7.61,-7.61l-0.95,-0.94L1.87,14.13l0.94,0.94L6.52,11.37L6.52,11.37zM5.59,8.55C5.22,8.08 4.89,7.58 4.61,7.05l1.75,-1.75c0.16,-0.16 0.23,-0.39 0.18,-0.6L6.1,2.53C6.04,2.23 5.77,2 5.45,2H2.68C2.31,2 1.99,2.31 2.01,2.69c0.11,1.94 0.69,3.75 1.62,5.34c0.3,0.51 0.64,1.01 1.01,1.47L5.59,8.55L5.59,8.55z"/>  </vector>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/notification_material_bg.xml b/packages/SystemUI/res/drawable/notification_material_bg.xml index 085263a031cf..61a8e8e9c6e1 100644 --- a/packages/SystemUI/res/drawable/notification_material_bg.xml +++ b/packages/SystemUI/res/drawable/notification_material_bg.xml @@ -17,7 +17,7 @@  <ripple xmlns:android="http://schemas.android.com/apk/res/android"          xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" -        android:color="@color/notification_ripple_untinted_color"> +        android:color="?android:attr/colorControlHighlight">      <item>          <shape>              <solid android:color="?androidprv:attr/colorSurface" /> diff --git a/packages/SystemUI/res/drawable/qs_media_button_background.xml b/packages/SystemUI/res/drawable/qs_media_button_background.xml index 2241abf130e3..ed9bd263a79d 100644 --- a/packages/SystemUI/res/drawable/qs_media_button_background.xml +++ b/packages/SystemUI/res/drawable/qs_media_button_background.xml @@ -26,4 +26,5 @@              android:right="16dp"              android:top="8dp"              android:bottom="8dp" /> +        <solid android:color="@android:color/transparent" />  </shape>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/media_carousel.xml b/packages/SystemUI/res/layout/media_carousel.xml index 95cee66af536..87acfd088939 100644 --- a/packages/SystemUI/res/layout/media_carousel.xml +++ b/packages/SystemUI/res/layout/media_carousel.xml @@ -22,7 +22,7 @@      android:layout_height="wrap_content"      android:clipChildren="false"      android:clipToPadding="false" -    > +    android:theme="@style/MediaPlayer">      <com.android.systemui.media.MediaScrollView          android:id="@+id/media_carousel_scroller"          android:layout_width="match_parent" @@ -47,7 +47,7 @@          android:layout_width="wrap_content"          android:layout_height="48dp"          android:layout_marginBottom="4dp" -        android:tint="?android:attr/textColorPrimary" +        android:tint="?android:attr/textColor"          android:forceHasOverlappingRendering="false"      />  </FrameLayout> diff --git a/packages/SystemUI/res/layout/media_smartspace_recommendations.xml b/packages/SystemUI/res/layout/media_smartspace_recommendations.xml index 1c4c89fb254a..8c54e2c1cec4 100644 --- a/packages/SystemUI/res/layout/media_smartspace_recommendations.xml +++ b/packages/SystemUI/res/layout/media_smartspace_recommendations.xml @@ -19,7 +19,6 @@  <com.android.systemui.util.animation.TransitionLayout      xmlns:android="http://schemas.android.com/apk/res/android"      xmlns:app="http://schemas.android.com/apk/res-auto" -    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"      android:id="@+id/media_recommendations"      android:layout_width="match_parent"      android:layout_height="wrap_content" @@ -28,7 +27,8 @@      android:clipChildren="false"      android:clipToPadding="false"      android:forceHasOverlappingRendering="false" -    android:background="@drawable/qs_media_background"> +    android:background="@drawable/qs_media_background" +    android:theme="@style/MediaPlayer">      <androidx.constraintlayout.widget.Guideline          android:id="@+id/media_vertical_start_guideline" @@ -37,12 +37,19 @@          android:orientation="vertical"          app:layout_constraintGuide_percent="0.25" /> -    <ImageView +    <androidx.constraintlayout.widget.Guideline +        android:id="@+id/media_horizontal_center_guideline" +        android:layout_width="wrap_content" +        android:layout_height="wrap_content" +        android:orientation="horizontal" +        app:layout_constraintGuide_percent="0.5" /> + +    <com.android.internal.widget.CachingIconView          android:id="@+id/recommendation_card_icon"          android:layout_width="@dimen/qs_aa_media_rec_header_icon_size"          android:layout_height="@dimen/qs_aa_media_rec_header_icon_size"          android:src="@drawable/ic_headset" -        android:tint="?android:attr/colorPrimary" /> +        android:tint="?android:attr/textColor" />      <TextView          android:id="@+id/recommendation_card_text" @@ -51,7 +58,6 @@          android:singleLine="true"          android:text="@string/controls_media_smartspace_rec_title"          android:fontFamily="google-sans-medium" -        android:textColor="?android:attr/colorPrimary"          android:textDirection="locale"          android:textSize="@dimen/qq_aa_media_rec_header_text_size" /> @@ -61,7 +67,7 @@          android:layout_height="@dimen/qs_aa_media_rec_album_size"          android:adjustViewBounds="true"          android:background="@drawable/bg_smartspace_media_item" -        android:backgroundTint="?androidprv:attr/colorAccentSecondary" +        style="@style/MediaPlayer.Album"          android:clipToOutline="true"          android:scaleType="centerCrop"/> @@ -69,7 +75,7 @@          android:id="@+id/media_logo1"          android:layout_width="@dimen/qs_media_icon_size"          android:layout_height="@dimen/qs_media_icon_size" -        android:background="@drawable/qs_media_icon_background" /> +        style="@style/MediaPlayer.AppIcon" />      <ImageView          android:id="@+id/media_cover2" @@ -77,7 +83,7 @@          android:layout_height="@dimen/qs_aa_media_rec_album_size"          android:adjustViewBounds="true"          android:background="@drawable/bg_smartspace_media_item" -        android:backgroundTint="?androidprv:attr/colorAccentSecondary" +        style="@style/MediaPlayer.Album"          android:clipToOutline="true"          android:scaleType="centerCrop"/> @@ -85,7 +91,7 @@          android:id="@+id/media_logo2"          android:layout_width="@dimen/qs_media_icon_size"          android:layout_height="@dimen/qs_media_icon_size" -        android:background="@drawable/qs_media_icon_background" /> +        style="@style/MediaPlayer.AppIcon" />      <ImageView          android:id="@+id/media_cover3" @@ -93,7 +99,7 @@          android:layout_height="@dimen/qs_aa_media_rec_album_size"          android:adjustViewBounds="true"          android:background="@drawable/bg_smartspace_media_item" -        android:backgroundTint="?androidprv:attr/colorAccentSecondary" +        style="@style/MediaPlayer.Album"          android:clipToOutline="true"          android:scaleType="centerCrop"/> @@ -101,7 +107,7 @@          android:id="@+id/media_logo3"          android:layout_width="@dimen/qs_media_icon_size"          android:layout_height="@dimen/qs_media_icon_size" -        android:background="@drawable/qs_media_icon_background" /> +        style="@style/MediaPlayer.AppIcon" />      <ImageView          android:id="@+id/media_cover4" @@ -109,7 +115,7 @@          android:layout_height="@dimen/qs_aa_media_rec_album_size"          android:adjustViewBounds="true"          android:background="@drawable/bg_smartspace_media_item" -        android:backgroundTint="?androidprv:attr/colorAccentSecondary" +        style="@style/MediaPlayer.Album"          android:clipToOutline="true"          android:scaleType="centerCrop"/> @@ -117,7 +123,7 @@          android:id="@+id/media_logo4"          android:layout_width="@dimen/qs_media_icon_size"          android:layout_height="@dimen/qs_media_icon_size" -        android:background="@drawable/qs_media_icon_background" /> +        style="@style/MediaPlayer.AppIcon" />      <ImageView          android:id="@+id/media_cover5" @@ -125,7 +131,7 @@          android:layout_height="@dimen/qs_aa_media_rec_album_size"          android:adjustViewBounds="true"          android:background="@drawable/bg_smartspace_media_item" -        android:backgroundTint="?androidprv:attr/colorAccentSecondary" +        style="@style/MediaPlayer.Album"          android:clipToOutline="true"          android:scaleType="centerCrop"/> @@ -133,7 +139,7 @@          android:id="@+id/media_logo5"          android:layout_width="@dimen/qs_media_icon_size"          android:layout_height="@dimen/qs_media_icon_size" -        android:background="@drawable/qs_media_icon_background" /> +        style="@style/MediaPlayer.AppIcon" />      <ImageView          android:id="@+id/media_cover6" @@ -141,7 +147,7 @@          android:layout_height="@dimen/qs_aa_media_rec_album_size"          android:adjustViewBounds="true"          android:background="@drawable/bg_smartspace_media_item" -        android:backgroundTint="?androidprv:attr/colorAccentSecondary" +        style="@style/MediaPlayer.Album"          android:clipToOutline="true"          android:scaleType="centerCrop"/> @@ -149,7 +155,7 @@          android:id="@+id/media_logo6"          android:layout_width="@dimen/qs_media_icon_size"          android:layout_height="@dimen/qs_media_icon_size" -        android:background="@drawable/qs_media_icon_background" /> +        style="@style/MediaPlayer.AppIcon" />      <!-- Long press menu -->      <TextView @@ -161,7 +167,6 @@          android:id="@+id/remove_text"          android:fontFamily="@*android:string/config_headlineFontFamily"          android:singleLine="true" -        android:textColor="?android:attr/textColorPrimary"          android:text="@string/controls_media_close_session"          android:gravity="center_horizontal|top"          app:layout_constraintTop_toTopOf="parent" @@ -186,9 +191,7 @@              android:layout_gravity="bottom"              android:layout_width="wrap_content"              android:layout_height="wrap_content" -            android:background="@drawable/qs_media_button_background" -            android:fontFamily="@*android:string/config_headlineFontFamilyMedium" -            android:textColor="?android:attr/textColorPrimary" +            style="@style/MediaPlayer.OutlineButton"              android:text="@string/controls_media_settings_button" />      </FrameLayout> @@ -209,9 +212,7 @@              android:layout_gravity="bottom"              android:layout_width="wrap_content"              android:layout_height="wrap_content" -            android:background="@drawable/qs_media_button_background" -            android:fontFamily="@*android:string/config_headlineFontFamilyMedium" -            android:textColor="?android:attr/textColorPrimary" +            style="@style/MediaPlayer.OutlineButton"              android:text="@string/cancel" />      </FrameLayout> @@ -232,9 +233,7 @@              android:layout_gravity="bottom"              android:layout_width="wrap_content"              android:layout_height="wrap_content" -            android:background="@drawable/qs_media_button_background" -            android:fontFamily="@*android:string/config_headlineFontFamilyMedium" -            android:textColor="?android:attr/textColorPrimary" +            style="@style/MediaPlayer.OutlineButton"              android:text="@string/controls_media_dismiss_button"              />      </FrameLayout> diff --git a/packages/SystemUI/res/layout/media_view.xml b/packages/SystemUI/res/layout/media_view.xml index cdced5a1be71..e9a24e284601 100644 --- a/packages/SystemUI/res/layout/media_view.xml +++ b/packages/SystemUI/res/layout/media_view.xml @@ -18,7 +18,6 @@  <!-- Layout for media controls inside QSPanel carousel -->  <com.android.systemui.util.animation.TransitionLayout xmlns:android="http://schemas.android.com/apk/res/android"      xmlns:app="http://schemas.android.com/apk/res-auto" -    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"      android:id="@+id/qs_media_controls"      android:layout_width="match_parent"      android:layout_height="wrap_content" @@ -26,7 +25,8 @@      android:clipToPadding="false"      android:gravity="center_horizontal|fill_vertical"      android:forceHasOverlappingRendering="false" -    android:background="@drawable/qs_media_background"> +    android:background="@drawable/qs_media_background" +    android:theme="@style/MediaPlayer">      <androidx.constraintlayout.widget.Guideline          android:id="@+id/center_vertical_guideline" @@ -55,7 +55,6 @@              android:layout_height="wrap_content"              android:layout_alignParentStart="true"              android:fontFamily="@*android:string/config_bodyFontFamily" -            android:textColor="?android:attr/textColorPrimary"              android:gravity="start"              android:textSize="12sp" /> @@ -65,7 +64,6 @@              android:layout_height="wrap_content"              android:layout_alignParentEnd="true"              android:fontFamily="@*android:string/config_bodyFontFamily" -            android:textColor="?android:attr/textColorPrimary"              android:gravity="end"              android:textSize="12sp" />      </FrameLayout> @@ -86,31 +84,31 @@      <ImageButton          android:id="@+id/action0" -        style="@style/MediaPlayer.Button" +        style="@style/MediaPlayer.Action"          android:layout_width="48dp"          android:layout_height="48dp" />      <ImageButton          android:id="@+id/action1" -        style="@style/MediaPlayer.Button" +        style="@style/MediaPlayer.Action"          android:layout_width="48dp"          android:layout_height="48dp" />      <ImageButton          android:id="@+id/action2" -        style="@style/MediaPlayer.Button" +        style="@style/MediaPlayer.Action"          android:layout_width="48dp"          android:layout_height="48dp" />      <ImageButton          android:id="@+id/action3" -        style="@style/MediaPlayer.Button" +        style="@style/MediaPlayer.Action"          android:layout_width="48dp"          android:layout_height="48dp" />      <ImageButton          android:id="@+id/action4" -        style="@style/MediaPlayer.Button" +        style="@style/MediaPlayer.Action"          android:layout_width="48dp"          android:layout_height="48dp" /> @@ -120,8 +118,8 @@          android:layout_width="@dimen/qs_media_album_size"          android:layout_height="@dimen/qs_media_album_size"          android:layout_gravity="center_vertical" +        style="@style/MediaPlayer.Album"          android:background="@drawable/qs_media_art_background" -        android:backgroundTint="?androidprv:attr/colorAccentSecondary"          android:clipToOutline="true" />      <!-- Seamless Output Switcher --> @@ -138,6 +136,7 @@          <LinearLayout              android:layout_width="wrap_content"              android:layout_height="@dimen/qs_seamless_height" +            android:theme="@style/MediaPlayer.SolidButton"              android:background="@drawable/qs_media_seamless_background"              android:orientation="horizontal"              android:contentDescription="@string/quick_settings_media_device_label"> @@ -146,7 +145,6 @@                  android:layout_width="@dimen/qs_seamless_icon_size"                  android:layout_height="@dimen/qs_seamless_icon_size"                  android:layout_gravity="center" -                android:tint="?android:attr/colorPrimary"                  android:src="@*android:drawable/ic_media_seamless" />              <TextView                  android:id="@+id/media_seamless_text" @@ -157,7 +155,6 @@                  android:fontFamily="@*android:string/config_headlineFontFamily"                  android:singleLine="true"                  android:text="@*android:string/ext_media_seamless_action" -                android:textColor="?android:attr/colorPrimary"                  android:textDirection="locale"                  android:textSize="12sp" />          </LinearLayout> @@ -171,7 +168,7 @@          android:layout_marginBottom="@dimen/qs_media_padding"          android:layout_marginStart="@dimen/qs_center_guideline_padding"          android:layout_marginEnd="@dimen/qs_seamless_fallback_margin" -        android:tint="?android:attr/textColorPrimary" +        android:tint="?android:attr/textColor"          android:src="@drawable/ic_cast_connected"          android:forceHasOverlappingRendering="false" /> @@ -179,17 +176,13 @@      <!-- As per Material Design on Biderectionality, this is forced to LTR in code -->      <SeekBar          android:id="@+id/media_progress_bar" -        style="@android:style/Widget.ProgressBar.Horizontal" +        style="@style/MediaPlayer.ProgressBar"          android:layout_width="0dp"          android:layout_height="wrap_content" -        android:clickable="true"          android:maxHeight="@dimen/qs_media_enabled_seekbar_height"          android:paddingTop="@dimen/qs_media_enabled_seekbar_vertical_padding"          android:layout_marginTop="-22dp"          android:paddingBottom="0dp" -        android:thumbTint="?android:attr/textColorPrimary" -        android:progressTint="?android:attr/textColorPrimary" -        android:progressBackgroundTint="?android:attr/textColorTertiary"          android:splitTrack="false" />      <!-- Song name --> @@ -199,7 +192,6 @@          android:layout_height="wrap_content"          android:fontFamily="@*android:string/config_headlineFontFamilyMedium"          android:singleLine="true" -        android:textColor="?android:attr/textColorPrimary"          android:textSize="16sp" />      <!-- Artist name --> @@ -209,16 +201,14 @@          android:layout_height="wrap_content"          android:fontFamily="@*android:string/config_headlineFontFamily"          android:singleLine="true" -        android:textColor="?android:attr/textColorSecondary" +        style="@style/MediaPlayer.Subtitle"          android:textSize="14sp" />      <com.android.internal.widget.CachingIconView          android:id="@+id/icon" -        android:tint="?android:attr/colorAccent" +        style="@style/MediaPlayer.AppIcon"          android:layout_width="@dimen/qs_media_icon_size" -        android:layout_height="@dimen/qs_media_icon_size" -        android:background="@drawable/qs_media_icon_background" -    /> +        android:layout_height="@dimen/qs_media_icon_size" />      <!-- Long press menu -->      <TextView @@ -230,7 +220,6 @@          android:id="@+id/remove_text"          android:fontFamily="@*android:string/config_headlineFontFamily"          android:singleLine="true" -        android:textColor="?android:attr/textColorPrimary"          android:text="@string/controls_media_close_session"          android:gravity="center_horizontal|top"          app:layout_constraintTop_toTopOf="parent" @@ -255,9 +244,7 @@              android:layout_gravity="bottom"              android:layout_width="wrap_content"              android:layout_height="wrap_content" -            android:background="@drawable/qs_media_button_background" -            android:fontFamily="@*android:string/config_headlineFontFamilyMedium" -            android:textColor="?android:attr/textColorPrimary" +            style="@style/MediaPlayer.OutlineButton"              android:text="@string/controls_media_settings_button" />      </FrameLayout> @@ -278,9 +265,7 @@              android:layout_gravity="bottom"              android:layout_width="wrap_content"              android:layout_height="wrap_content" -            android:background="@drawable/qs_media_button_background" -            android:fontFamily="@*android:string/config_headlineFontFamilyMedium" -            android:textColor="?android:attr/textColorPrimary" +            style="@style/MediaPlayer.OutlineButton"              android:text="@string/cancel" />      </FrameLayout> @@ -301,9 +286,7 @@              android:layout_gravity="bottom"              android:layout_width="wrap_content"              android:layout_height="wrap_content" -            android:background="@drawable/qs_media_button_background" -            android:fontFamily="@*android:string/config_headlineFontFamilyMedium" -            android:textColor="?android:attr/textColorPrimary" +            style="@style/MediaPlayer.OutlineButton"              android:text="@string/controls_media_dismiss_button"          />      </FrameLayout> diff --git a/packages/SystemUI/res/layout/notification_conversation_info.xml b/packages/SystemUI/res/layout/notification_conversation_info.xml index ea644cfca68a..c332f4cf7a39 100644 --- a/packages/SystemUI/res/layout/notification_conversation_info.xml +++ b/packages/SystemUI/res/layout/notification_conversation_info.xml @@ -254,7 +254,6 @@                      android:layout_height="wrap_content"                      android:layout_marginTop="@dimen/notification_importance_button_description_top_margin"                      android:visibility="gone" -                    android:text="@string/notification_channel_summary_priority"                      android:clickable="false"                      android:focusable="false"                      android:ellipsize="end" diff --git a/packages/SystemUI/res/layout/people_tile_empty_layout.xml b/packages/SystemUI/res/layout/people_tile_empty_layout.xml new file mode 100644 index 000000000000..7d3b919ce040 --- /dev/null +++ b/packages/SystemUI/res/layout/people_tile_empty_layout.xml @@ -0,0 +1,29 @@ +<!-- +  ~ 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. +  --> +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" +    android:theme="@android:style/Theme.DeviceDefault.DayNight" +    android:background="@drawable/people_space_tile_view_card" +    android:layout_width="match_parent" +    android:layout_height="match_parent"> + +    <ImageView +        android:id="@+id/item" +        android:gravity="center" +        android:layout_gravity="center" +        android:padding="8dp" +        android:layout_width="wrap_content" +        android:layout_height="wrap_content"/> +</FrameLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/priority_onboarding_half_shell.xml b/packages/SystemUI/res/layout/priority_onboarding_half_shell.xml deleted file mode 100644 index 3f0e514a9af2..000000000000 --- a/packages/SystemUI/res/layout/priority_onboarding_half_shell.xml +++ /dev/null @@ -1,166 +0,0 @@ -<!-- -  ~ Copyright (C) 2020 The Android Open Source Project -  ~ -  ~ Licensed under the Apache License, Version 2.0 (the "License"); -  ~ you may not use this file except in compliance with the License. -  ~ You may obtain a copy of the License at -  ~ -  ~      http://www.apache.org/licenses/LICENSE-2.0 -  ~ -  ~ Unless required by applicable law or agreed to in writing, software -  ~ distributed under the License is distributed on an "AS IS" BASIS, -  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -  ~ See the License for the specific language governing permissions and -  ~ limitations under the License -  --> - -<FrameLayout -    xmlns:android="http://schemas.android.com/apk/res/android" -    android:id="@+id/onboarding_half_shell_container" -    android:orientation="vertical" -    android:layout_width="wrap_content" -    android:layout_height="wrap_content" -    android:layout_gravity="center_horizontal|bottom" -    android:paddingStart="4dp" -    android:paddingEnd="4dp" -    > - -    <LinearLayout -        android:id="@+id/half_shell" -        android:layout_width="@dimen/qs_panel_width" -        android:layout_height="wrap_content" -        android:paddingTop="16dp" -        android:paddingStart="16dp" -        android:paddingEnd="16dp" -        android:orientation="vertical" -        android:gravity="bottom" -        android:layout_gravity="center_horizontal|bottom" -        android:background="@drawable/rounded_bg_full" -        > - -    <FrameLayout -        android:layout_width="wrap_content" -        android:layout_height="wrap_content" -        android:clipChildren="false" -        android:clipToPadding="false" -        android:padding="12dp" -        android:layout_gravity="center_horizontal" -    > - -        <!-- Big icon: 52x52, 12dp padding left + top, 16dp padding right --> -        <ImageView -            android:id="@+id/conversation_icon" -            android:layout_width="@*android:dimen/conversation_avatar_size" -            android:layout_height="@*android:dimen/conversation_avatar_size" -            android:scaleType="centerCrop" -            android:importantForAccessibility="no" -        /> - -        <FrameLayout -            android:id="@+id/conversation_icon_badge" -            android:layout_width="@*android:dimen/conversation_icon_size_badged" -            android:layout_height="@*android:dimen/conversation_icon_size_badged" -            android:layout_marginLeft="@*android:dimen/conversation_badge_side_margin" -            android:layout_marginTop="@*android:dimen/conversation_badge_side_margin" -            android:clipChildren="false" -            android:clipToPadding="false" -        > -            <ImageView -                android:id="@+id/conversation_icon_badge_bg" -                android:layout_width="match_parent" -                android:layout_height="match_parent" -                android:layout_gravity="center" -                android:src="@*android:drawable/conversation_badge_background" -                android:forceHasOverlappingRendering="false" -            /> -            <ImageView -                android:id="@+id/icon" -                android:layout_width="match_parent" -                android:layout_height="match_parent" -                android:layout_margin="4dp" -                android:layout_gravity="center" -                android:forceHasOverlappingRendering="false" -            /> -            <ImageView -                android:id="@+id/conversation_icon_badge_ring" -                android:layout_width="wrap_content" -                android:layout_height="wrap_content" -                android:layout_gravity="center" -                android:src="@*android:drawable/conversation_badge_ring" -                android:forceHasOverlappingRendering="false" -                android:clipToPadding="false" -                android:scaleType="center" -            /> -        </FrameLayout> -    </FrameLayout> - -        <TextView -            android:id="@+id/title" -            android:layout_width="match_parent" -            android:layout_height="wrap_content" -            android:gravity="center_horizontal" -            android:layout_marginTop="16dp" -            android:text="@string/priority_onboarding_title" -            style="@style/TextAppearance.NotificationImportanceChannel" -        /> - -        <View -            android:id="@+id/divider" -            android:layout_width="match_parent" -            android:layout_height="0.5dp" -            android:layout_marginTop="20dp" -            android:layout_marginBottom="20dp" -            android:background="@color/material_grey_300" /> - -        <TextView -            android:layout_width="match_parent" -            android:layout_height="wrap_content" -            android:gravity="start" -            android:text="@string/priority_onboarding_behavior" -            style="@style/TextAppearance.NotificationImportanceChannelGroup" -        /> - -        <TextView -            android:id="@+id/behaviors" -            android:layout_width="match_parent" -            android:layout_height="wrap_content" -            android:gravity="start" -            android:layout_marginTop="8dp" -            style="@style/TextAppearance.NotificationImportanceChannelGroup" -        /> - -        <!-- Bottom button container --> -        <RelativeLayout -            android:id="@+id/button_container" -            android:layout_width="match_parent" -            android:layout_height="wrap_content" -            android:layout_marginTop="32dp" -            android:orientation="horizontal" -            > -            <TextView -                android:id="@+id/settings_button" -                android:text="@string/priority_onboarding_settings_button_title" -                android:layout_width="wrap_content" -                android:layout_height="wrap_content" -                android:layout_alignParentStart="true" -                android:gravity="start|center_vertical" -                android:minWidth="@dimen/notification_importance_toggle_size" -                android:minHeight="@dimen/notification_importance_toggle_size" -                android:maxWidth="125dp" -                style="@style/TextAppearance.NotificationInfo.Button"/> -            <TextView -                android:id="@+id/done_button" -                android:text="@string/priority_onboarding_done_button_title" -                android:layout_width="wrap_content" -                android:layout_height="wrap_content" -                android:layout_alignParentEnd="true" -                android:gravity="end|center_vertical" -                android:minWidth="@dimen/notification_importance_toggle_size" -                android:minHeight="@dimen/notification_importance_toggle_size" -                android:maxWidth="125dp" -                style="@style/TextAppearance.NotificationInfo.Button"/> - -        </RelativeLayout> - -    </LinearLayout> -</FrameLayout> diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml index 5bf691928300..bb540990ccb7 100644 --- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml +++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml @@ -36,7 +36,7 @@      <include layout="@layout/quick_status_bar_header_date_privacy"/>      <RelativeLayout -        android:id="@+id/container" +        android:id="@+id/qs_container"          android:layout_width="match_parent"          android:layout_height="wrap_content"          android:layout_gravity="top" diff --git a/packages/SystemUI/res/layout/super_status_bar.xml b/packages/SystemUI/res/layout/super_status_bar.xml index 7142929bab64..5176d966a694 100644 --- a/packages/SystemUI/res/layout/super_status_bar.xml +++ b/packages/SystemUI/res/layout/super_status_bar.xml @@ -26,6 +26,11 @@      android:fitsSystemWindows="true">      <FrameLayout +        android:id="@+id/status_bar_launch_animation_container" +        android:layout_width="match_parent" +        android:layout_height="match_parent" /> + +    <FrameLayout          android:id="@+id/status_bar_container"          android:layout_width="match_parent"          android:layout_height="wrap_content" diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index b94e9e8ae1c3..f17067a58b69 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Beweeg na regs onder"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Beweeg na rand en versteek"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Beweeg weg van rand en wys"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"wissel"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"Toestelkontroles"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"Voeg kontroles vir jou gekoppelde toestelle by"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"Stel toestelkontroles op"</string> @@ -1092,8 +1091,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Maak toe"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"Hervat"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"Instellings"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Speel"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"Onaktief, gaan program na"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"Fout, probeer tans weer …"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"Nie gekry nie"</string> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index d2ee53d54a46..d2ecd78df75c 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"ታችኛውን ቀኝ አንቀሳቅስ"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"ወደ ጠርዝ አንቀሳቅስ እና ደደብቅ"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"ጠርዙን ወደ ውጭ አንቀሳቅስ እና አሳይ"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ቀያይር"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"የመሣሪያ መቆጣጠሪያዎች"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"ለእርስዎ የተገናኙ መሣሪያዎች መቆጣጠሪያዎችን ያክሉ"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"የመሣሪያ መቆጣጠሪያዎችን ያቀናብሩ"</string> @@ -1092,8 +1091,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"አሰናብት"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"ከቆመበት ቀጥል"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"ቅንብሮች"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"አጫውት"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"ንቁ ያልኾነ፣ መተግበሪያን ይፈትሹ"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"ስህተት፣ እንደገና በመሞከር ላይ…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"አልተገኘም"</string> diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml index a32a55ce8101..bceb6c9250ae 100644 --- a/packages/SystemUI/res/values-as/strings.xml +++ b/packages/SystemUI/res/values-as/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"তলৰ সোঁফালে নিয়ক"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"কাষলৈ নিয়ক আৰু লুকুৱাওক"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"কাষৰ বাহিৰলৈ নিয়ক আৰু দেখুৱাওক"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ট’গল কৰক"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"ডিভাইচৰ নিয়ন্ত্ৰণসমূহ"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"আপোনাৰ সংযোজিত ডিভাইচৰ বাবে নিয়ন্ত্ৰণ যোগ কৰক"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"ডিভাইচৰ নিয়ন্ত্ৰণসমূহ ছেট আপ কৰক"</string> @@ -1087,15 +1086,12 @@      <string name="controls_structure_tooltip" msgid="4355922222944447867">"অধিক চাবলৈ ছোৱাইপ কৰক"</string>      <string name="controls_seeding_in_progress" msgid="3033855341410264148">"চুপাৰিছসমূহ ল’ড কৰি থকা হৈছে"</string>      <string name="controls_media_title" msgid="1746947284862928133">"মিডিয়া"</string> -    <!-- no translation found for controls_media_close_session (1193000643003066508) --> -    <skip /> -    <!-- no translation found for controls_media_active_session (3146882316024153337) --> -    <skip /> +    <string name="controls_media_close_session" msgid="1193000643003066508">"এই মিডিয়াৰ ছেশ্বনটো লুকুৱাবনে?"</string> +    <string name="controls_media_active_session" msgid="3146882316024153337">"বৰ্তমানৰ মিডিয়াৰ ছেশ্বনটো লুকুৱাব নোৱাৰি।"</string>      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"অগ্ৰাহ্য কৰক"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"পুনৰ আৰম্ভ কৰক"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"ছেটিংসমূহ"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"প্লে’ কৰক"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"সক্ৰিয় নহয়, এপ্টো পৰীক্ষা কৰক"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"আসোঁৱাহ, পুনৰ চেষ্টা কৰি আছে…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"বিচাৰি পোৱা নগ’ল"</string> @@ -1156,6 +1152,5 @@      <string name="accessibility_udfps_disabled_button" msgid="4284034245130239384">"ফিংগাৰপ্ৰিণ্ট ছেন্সৰ অক্ষম হৈ আছে"</string>      <string name="accessibility_authenticate_hint" msgid="798914151813205721">"বিশ্বাসযোগ্যতা প্ৰমাণ কৰক"</string>      <string name="accessibility_enter_hint" msgid="2617864063504824834">"ডিভাইচ আনলক কৰক"</string> -    <!-- no translation found for keyguard_try_fingerprint (2825130772993061165) --> -    <skip /> +    <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"খুলিবলৈ ফিংগাৰপ্ৰিণ্ট ব্যৱহাৰ কৰক"</string>  </resources> diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml index 9318906f4a49..466d24ef491d 100644 --- a/packages/SystemUI/res/values-az/strings.xml +++ b/packages/SystemUI/res/values-az/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Aşağıya sağa köçürün"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"İçəri keçirib gizlədin"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Kənara daşıyıb göstərin"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"keçirin"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"Cihaz idarəetmələri"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"Qoşulmuş cihazlarınız üçün nizamlayıcılar əlavə edin"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"Cihaz idarəetmələrini ayarlayın"</string> @@ -1092,8 +1091,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"İmtina edin"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"Davam edin"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"Ayarlar"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Oxudun"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"Aktiv deyil, tətbiqi yoxlayın"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"Xəta, yenidən cəhd edilir…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"Tapılmadı"</string> diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml index eeb3061fe8e7..f1303ce06190 100644 --- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml @@ -1049,8 +1049,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Premesti dole desno"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Premesti do ivice i sakrij"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Premesti izvan ivice i prikaži"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"uključite/isključite"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"Kontrole uređaja"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"Dodajte kontrole za povezane uređaje"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"Podesite kontrole uređaja"</string> @@ -1098,8 +1097,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Odbaci"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"Nastavi"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"Podešavanja"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Pusti"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno. Vidite aplikaciju"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"Greška, pokušava se ponovo…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"Nije pronađeno"</string> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index 44f6ff96d323..e857489eff56 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Преместване долу вдясно"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Преместване в края и скриване"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Преместване в края и показване"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"превключване"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"Контроли за устройството"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"Добавяне на контроли за свързаните ви устройства"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"Настройване на контролите за устройството"</string> @@ -1092,8 +1091,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Отхвърляне"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"Възобновяване"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"Настройки"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Google Play"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"Неактивно, проверете прилож."</string>      <string name="controls_error_retryable" msgid="864025882878378470">"Грешка. Извършва се нов опит…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"Не е намерено"</string> diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index 959f07b36b92..8f9953ba2a6d 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -1087,10 +1087,8 @@      <string name="controls_structure_tooltip" msgid="4355922222944447867">"আরও দেখতে সোয়াইপ করুন"</string>      <string name="controls_seeding_in_progress" msgid="3033855341410264148">"সাজেশন লোড করা হচ্ছে"</string>      <string name="controls_media_title" msgid="1746947284862928133">"মিডিয়া"</string> -    <!-- no translation found for controls_media_close_session (1193000643003066508) --> -    <skip /> -    <!-- no translation found for controls_media_active_session (3146882316024153337) --> -    <skip /> +    <string name="controls_media_close_session" msgid="1193000643003066508">"এই মিডিয়া সেশন লুকিয়ে রাখতে চান?"</string> +    <string name="controls_media_active_session" msgid="3146882316024153337">"বর্তমান মিডিয়া সেশন লুকিয়ে রাখা যাবে না।"</string>      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"খারিজ করুন"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"আবার চালু করুন"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"সেটিংস"</string> @@ -1156,6 +1154,5 @@      <string name="accessibility_udfps_disabled_button" msgid="4284034245130239384">"ফিঙ্গারপ্রিন্ট সেন্সর বন্ধ করা আছে"</string>      <string name="accessibility_authenticate_hint" msgid="798914151813205721">"যাচাই করিয়ে নিন"</string>      <string name="accessibility_enter_hint" msgid="2617864063504824834">"ডিভাইস আনলক করুন"</string> -    <!-- no translation found for keyguard_try_fingerprint (2825130772993061165) --> -    <skip /> +    <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"খুলতে ফিঙ্গারপ্রিন্ট ব্যবহার করুন"</string>  </resources> diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index 674f049849b0..482c8ad816f9 100644 --- a/packages/SystemUI/res/values-bs/strings.xml +++ b/packages/SystemUI/res/values-bs/strings.xml @@ -1049,8 +1049,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Pomjeranje dolje desno"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Pomjeranje do ivice i sakrivanje"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Pomjeranje izvan ivice i prikaz"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"aktiviranje/deaktiviranje"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"Kontrole uređaja"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"Dodajte kontrole za povezane uređaje"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"Postavite kontrole uređaja"</string> @@ -1098,8 +1097,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Odbaci"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"Nastavi"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"Postavke"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Pokrenite"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno, vidite aplikaciju"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"Greška, ponovni pokušaj…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"Nije pronađeno"</string> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index b9e01021df59..ac86cfbba09e 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Mou a baix a la dreta"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Mou dins de les vores i amaga"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Mou fora de les vores i mostra"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"commuta"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"Controls de dispositius"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"Afegeix controls per als teus dispositius connectats"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"Configura els controls de dispositius"</string> @@ -1092,8 +1091,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Ignora"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"Reprèn"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"Configuració"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Reprodueix"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"Inactiu; comprova l\'aplicació"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"Error. S\'està tornant a provar…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"No s\'ha trobat"</string> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index 123b09fc1816..bf969a19d21e 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -1054,8 +1054,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Přesunout vpravo dolů"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Přesunout k okraji a skrýt"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Přesunout okraj ven a zobrazit"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"přepnout"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"Ovládání zařízení"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"Přidejte si ovládací prvky pro připojená zařízení"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"Nastavení ovládání zařízení"</string> @@ -1104,8 +1103,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Zavřít"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"Pokračovat"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"Nastavení"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Přehrát"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"Neaktivní, zkontrolujte aplikaci"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"Chyba. Nový pokus…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"Nenalezeno"</string> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index 5ccdbf38680a..abcb89e0de39 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Flyt ned til højre"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Flyt ud til kanten, og skjul"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Flyt ud til kanten, og vis"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"slå til/fra"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"Enhedsstyring"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"Tilføj styring af dine tilsluttede enheder"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"Konfigurer enhedsstyring"</string> @@ -1092,8 +1091,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Luk"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"Genoptag"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"Indstillinger"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Afspil"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv. Tjek appen"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"Fejl. Prøver igen…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"Ikke fundet"</string> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index 6885380b2cc5..2bc8a0392261 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -1087,10 +1087,8 @@      <string name="controls_structure_tooltip" msgid="4355922222944447867">"Wischen, um weitere zu sehen"</string>      <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Empfehlungen werden geladen"</string>      <string name="controls_media_title" msgid="1746947284862928133">"Medien"</string> -    <!-- no translation found for controls_media_close_session (1193000643003066508) --> -    <skip /> -    <!-- no translation found for controls_media_active_session (3146882316024153337) --> -    <skip /> +    <string name="controls_media_close_session" msgid="1193000643003066508">"Diese Mediensitzung ausblenden?"</string> +    <string name="controls_media_active_session" msgid="3146882316024153337">"Die Mediensitzung kann nicht ausgeblendet werden."</string>      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Ablehnen"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"Fortsetzen"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"Einstellungen"</string> @@ -1156,6 +1154,5 @@      <string name="accessibility_udfps_disabled_button" msgid="4284034245130239384">"Fingerabdrucksensor ist deaktiviert"</string>      <string name="accessibility_authenticate_hint" msgid="798914151813205721">"zu authentifizieren"</string>      <string name="accessibility_enter_hint" msgid="2617864063504824834">"das Gerät einzugeben"</string> -    <!-- no translation found for keyguard_try_fingerprint (2825130772993061165) --> -    <skip /> +    <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Mit Fingerabdruck öffnen"</string>  </resources> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index f8420271d256..545d822c50ac 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Μετακίνηση κάτω δεξιά"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Μετακίν. στο άκρο και απόκρυψη"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Μετακ. εκτός άκρου και εμφάν."</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"εναλλαγή"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"Στοιχεία ελέγχου συσκευής"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"Προσθήκη στοιχείων ελέγχου για τις συνδεδεμένες συσκευές σας."</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"Ρύθμιση στοιχείων ελέγχου συσκευής"</string> @@ -1092,8 +1091,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Παράβλεψη"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"Συνέχιση"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"Ρυθμίσεις"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Play"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"Ανενεργό, έλεγχος εφαρμογής"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"Προέκυψε σφάλμα. Επανάληψη…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"Δεν βρέθηκε."</string> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index 21ed95421f1f..5292f8741446 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Mover abajo a la derecha"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Mover fuera de borde y ocultar"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Mover fuera de borde y mostrar"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"activar o desactivar"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"Controles de dispositivos"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"Agrega controles para los dispositivos conectados"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"Configurar controles de dispositivos"</string> @@ -1092,8 +1091,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Descartar"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"Reanudar"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"Configuración"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Reproducir"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"Inactivo. Verifica la app"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"Hubo un error. Reintentando…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"No se encontró"</string> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index eaeaf0b6fbf8..d23f073d387f 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Mover abajo a la derecha"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Mover al borde y ocultar"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Mover al borde y mostrar"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"activar/desactivar"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"Control de dispositivos"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"Añade controles para tus dispositivos conectados"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"Configurar control de dispositivos"</string> @@ -1092,8 +1091,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Cerrar"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"Reanudar"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"Ajustes"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Reproducir"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"Inactivo, comprobar aplicación"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"Error; reintentando…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"No se ha encontrado"</string> diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index ceaf3fcadb96..d227dcbfd225 100644 --- a/packages/SystemUI/res/values-et/strings.xml +++ b/packages/SystemUI/res/values-et/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Teisalda alla paremale"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Teisalda serva ja kuva"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Teisalda servast eemale ja kuva"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"lülita"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"Seadmete juhikud"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"Lisage juhtelemendid ühendatud seadmete jaoks"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"Seadmete juhtimisvidinate seadistamine"</string> @@ -1092,8 +1091,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Loobu"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"Jätka"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"Seaded"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Esitamine"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"Passiivne, vaadake rakendust"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"Viga, proovitakse uuesti …"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"Ei leitud"</string> diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml index 3cb0b4398f4e..199107c2be56 100644 --- a/packages/SystemUI/res/values-eu/strings.xml +++ b/packages/SystemUI/res/values-eu/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Eraman behealdera, eskuinetara"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Eraman ertzera eta ezkutatu"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Atera ertzetik eta erakutsi"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"aldatu"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"Gailuak kontrolatzeko widgetak"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"Gehitu konektatutako gailuak kontrolatzeko widgetak"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"Konfiguratu gailuak kontrolatzeko widgetak"</string> @@ -1092,8 +1091,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Baztertu"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"Berrekin"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"Ezarpenak"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Erreproduzitu"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"Inaktibo; egiaztatu aplikazioa"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"Errorea. Berriro saiatzen…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"Ez da aurkitu"</string> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index 7e9dabb4089a..d6b018df10b7 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"انتقال به پایین سمت چپ"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"انتقال به لبه و پنهان کردن"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"انتقال به خارج از لبه و نمایش"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"روشن/ خاموش کردن"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"کنترلهای دستگاه"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"افزودن کنترلها برای دستگاههای متصل"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"تنظیم کنترلهای دستگاه"</string> @@ -1092,8 +1091,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"رد کردن"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"ازسرگیری"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"تنظیمات"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"پخش"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"غیرفعال، برنامه را بررسی کنید"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"خطا، درحال تلاش مجدد…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"پیدا نشد"</string> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index 89566a6e6e29..d4da4597d56c 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Déplacer dans coin inf. droit"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Éloigner du bord et masquer"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Éloigner du bord et afficher"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"basculer"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"Commandes des appareils"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"Ajoutez des commandes pour vos appareils connectés"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"Configurer les commandes des appareils"</string> @@ -1092,8 +1091,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Fermer"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"Reprendre"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"Paramètres"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Faire jouer"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"Délai expiré, vérifiez l\'appli"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"Erreur, nouvelle tentative…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"Introuvable"</string> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index 7f73bab04817..c17bf8ffe906 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Déplacer en bas à droite"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Rapprocher du bord et masquer"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Éloigner du bord et afficher"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"activer/désactiver"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"Commandes des appareils"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"Ajouter des commandes pour vos appareils connectés"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"Configurer les commandes des appareils"</string> @@ -1092,8 +1091,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Fermer"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"Reprendre"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"Paramètres"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Lire"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"Délai expiré, vérifier l\'appli"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"Erreur. Nouvelle tentative…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"Introuvable"</string> diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml index 4a2a93ef0ec1..73d2de64d194 100644 --- a/packages/SystemUI/res/values-gl/strings.xml +++ b/packages/SystemUI/res/values-gl/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Mover á parte inferior dereita"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Mover ao bordo e ocultar"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Mover fóra do bordo e mostrar"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"activar/desactivar"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"Control de dispositivos"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"Engade controis para os dispositivos conectados"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"Configurar o control de dispositivos"</string> @@ -1092,8 +1091,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Ignorar"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"Retomar"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"Configuración"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Reproducir"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"Inactivo. Comproba a app"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"Erro. Tentando de novo…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"Non se atopou"</string> diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml index 25eb4163d3e9..4c5308bfc2fd 100644 --- a/packages/SystemUI/res/values-gu/strings.xml +++ b/packages/SystemUI/res/values-gu/strings.xml @@ -137,8 +137,7 @@      <string name="accessibility_phone_button" msgid="4256353121703100427">"ફોન"</string>      <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"વૉઇસ સહાય"</string>      <string name="accessibility_unlock_button" msgid="122785427241471085">"અનલૉક કરો"</string> -    <!-- no translation found for accessibility_lock_icon (661492842417875775) --> -    <skip /> +    <string name="accessibility_lock_icon" msgid="661492842417875775">"ડિવાઇસ લૉક કરેલું છે"</string>      <string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"ફિંગરપ્રિન્ટની રાહ જોઈ રહ્યાં છીએ"</string>      <string name="accessibility_unlock_without_fingerprint" msgid="1811563723195375298">"તમારી ફિંગરપ્રિન્ટનો ઉપયોગ કર્યા વગર અનલૉક કરો"</string>      <string name="accessibility_scanning_face" msgid="3093828357921541387">"ચહેરો સ્કૅન કરવો"</string> @@ -1088,10 +1087,8 @@      <string name="controls_structure_tooltip" msgid="4355922222944447867">"વધુ જોવા માટે સ્વાઇપ કરો"</string>      <string name="controls_seeding_in_progress" msgid="3033855341410264148">"સુઝાવ લોડ કરી રહ્યાં છીએ"</string>      <string name="controls_media_title" msgid="1746947284862928133">"મીડિયા"</string> -    <!-- no translation found for controls_media_close_session (1193000643003066508) --> -    <skip /> -    <!-- no translation found for controls_media_active_session (3146882316024153337) --> -    <skip /> +    <string name="controls_media_close_session" msgid="1193000643003066508">"શું આ મીડિયા સત્ર છુપાવીએ?"</string> +    <string name="controls_media_active_session" msgid="3146882316024153337">"હાલનું મીડિયા સત્ર છુપાવી શકાતું નથી."</string>      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"છોડી દો"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"ફરી શરૂ કરો"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"સેટિંગ"</string> @@ -1153,14 +1150,9 @@      <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"તમારું બૅટરી મીટર વાંચવામાં સમસ્યા આવી"</string>      <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"વધુ માહિતી માટે ટૅપ કરો"</string>      <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"કોઈ અલાર્મ સેટ નથી"</string> -    <!-- no translation found for accessibility_fingerprint_label (5255731221854153660) --> -    <skip /> -    <!-- no translation found for accessibility_udfps_disabled_button (4284034245130239384) --> -    <skip /> -    <!-- no translation found for accessibility_authenticate_hint (798914151813205721) --> -    <skip /> -    <!-- no translation found for accessibility_enter_hint (2617864063504824834) --> -    <skip /> -    <!-- no translation found for keyguard_try_fingerprint (2825130772993061165) --> -    <skip /> +    <string name="accessibility_fingerprint_label" msgid="5255731221854153660">"ફિંગરપ્રિન્ટ સેન્સર"</string> +    <string name="accessibility_udfps_disabled_button" msgid="4284034245130239384">"ફિંગરપ્રિન્ટ સેન્સર બંધ કરેલું છે"</string> +    <string name="accessibility_authenticate_hint" msgid="798914151813205721">"ખાતરી કરો"</string> +    <string name="accessibility_enter_hint" msgid="2617864063504824834">"ડિવાઇસ અનલૉક કરો"</string> +    <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ખોલવા માટે ફિંગરપ્રિન્ટનો ઉપયોગ કરો"</string>  </resources> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index 02e4a45751a8..6b03458b0f73 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"सबसे नीचे दाईं ओर ले जाएं"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"एज पर ले जाएं और छिपाएं"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"एज से निकालें और दिखाएं"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"टॉगल करें"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"डिवाइस कंट्रोल"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"कनेक्ट किए गए डिवाइस के लिए कंट्रोल जोड़ें"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"डिवाइस कंट्रोल सेट अप करें"</string> @@ -1092,8 +1091,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"खारिज करें"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"फिर से शुरू करें"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"सेटिंग"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"चलाएं"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"काम नहीं कर रहा, ऐप जांचें"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"कोई गड़बड़ी हुई, फिर से कोशिश की जा रही है…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"कंट्रोल नहीं है"</string> @@ -1153,6 +1151,6 @@      <string name="accessibility_fingerprint_label" msgid="5255731221854153660">"फ़िंगरप्रिंट सेंसर"</string>      <string name="accessibility_udfps_disabled_button" msgid="4284034245130239384">"फ़िंगरप्रिंट सेंसर बंद है"</string>      <string name="accessibility_authenticate_hint" msgid="798914151813205721">"पुष्टि करें"</string> -    <string name="accessibility_enter_hint" msgid="2617864063504824834">"डिवाइस अनलॉक करें"</string> +    <string name="accessibility_enter_hint" msgid="2617864063504824834">"डिवाइस की होम स्क्रीन पर जाएं"</string>      <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"खोलने के लिए, फ़िंगरप्रिंट का इस्तेमाल करें"</string>  </resources> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index 39e628296126..3b4d034c8039 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -1049,8 +1049,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Premjesti u donji desni kut"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Premjesti na rub i sakrij"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Ukloni s ruba i prikaži"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"promijeni"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"Kontrole uređaja"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"Dodajte kontrole za povezane uređaje"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"Postavljanje kontrola uređaja"</string> @@ -1098,8 +1097,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Odbaci"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"Nastavi"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"Postavke"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Reprodukcija"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno, provjerite aplik."</string>      <string name="controls_error_retryable" msgid="864025882878378470">"Pogreška, pokušavamo ponovo…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"Nije pronađeno"</string> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index 906b45fe13e9..1940cd5ef2ea 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Áthelyezés le és jobbra"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Áthelyezés a szélen kívül és elrejtés"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Áthelyezés a szélen kívül és mutatás"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"váltás"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"Eszközvezérlők"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"Vezérlők hozzáadása a csatlakoztatott eszközökhöz"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"Eszközvezérlők beállítása"</string> @@ -1092,8 +1091,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Elvetés"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"Folytatás"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"Beállítások"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Játék"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"Inaktív, ellenőrizze az appot"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"Hiba, újrapróbálkozás…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"Nem található"</string> diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml index 630792f1ec4f..aaf2b5d8c31a 100644 --- a/packages/SystemUI/res/values-is/strings.xml +++ b/packages/SystemUI/res/values-is/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Færa neðst til hægri"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Færa að jaðri og fela"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Færa að jaðri og birta"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"kveikja/slökkva"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"Tækjastjórnun"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"Bæta við stýringum fyrir tengd tæki"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"Setja upp tækjastjórnun"</string> @@ -1092,8 +1091,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Hunsa"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"Halda áfram"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"Stillingar"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Spila"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"Óvirkt, athugaðu forrit"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"Villa, reynir aftur…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"Fannst ekki"</string> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index 0fd51ec1ad09..40294d5a32fe 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Sposta in basso a destra"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Sposta fino a bordo e nascondi"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Sposta fuori da bordo e mostra"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"attiva/disattiva"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"Controllo dei dispositivi"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"Aggiungi controlli per i dispositivi connessi"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"Configura il controllo dei dispositivi"</string> @@ -1092,8 +1091,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Ignora"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"Riprendi"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"Impostazioni"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Riproduci"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"Inattivo, controlla l\'app"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"Errore. Nuovo tentativo…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"Controllo non trovato"</string> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index 98ae9d1ae9d4..0a9cceb32c5b 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -1099,10 +1099,8 @@      <string name="controls_structure_tooltip" msgid="4355922222944447867">"יש להחליק כדי להציג עוד פריטים"</string>      <string name="controls_seeding_in_progress" msgid="3033855341410264148">"ההמלצות בטעינה"</string>      <string name="controls_media_title" msgid="1746947284862928133">"מדיה"</string> -    <!-- no translation found for controls_media_close_session (1193000643003066508) --> -    <skip /> -    <!-- no translation found for controls_media_active_session (3146882316024153337) --> -    <skip /> +    <string name="controls_media_close_session" msgid="1193000643003066508">"להסתיר את סשן המדיה?"</string> +    <string name="controls_media_active_session" msgid="3146882316024153337">"לא ניתן להסתיר את סשן המדיה הנוכחי."</string>      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"סגירה"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"המשך"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"הגדרות"</string> @@ -1168,6 +1166,5 @@      <string name="accessibility_udfps_disabled_button" msgid="4284034245130239384">"חיישן טביעות האצבע מושבת"</string>      <string name="accessibility_authenticate_hint" msgid="798914151813205721">"אימות"</string>      <string name="accessibility_enter_hint" msgid="2617864063504824834">"הזנת מכשיר"</string> -    <!-- no translation found for keyguard_try_fingerprint (2825130772993061165) --> -    <skip /> +    <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"שימוש בטביעת אצבע כדי לפתוח"</string>  </resources> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index c3475017a066..97d94ab4d41c 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"右下に移動"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"端に移動して非表示"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"端から移動して表示"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"切り替え"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"デバイス コントロール"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"コネクテッド デバイスのコントロールを追加します"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"デバイス コントロールの設定"</string> @@ -1092,8 +1091,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"閉じる"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"再開"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"設定"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"再生"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"無効: アプリをご確認ください"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"エラー。再試行しています…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"見つかりませんでした"</string> diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml index bc8abd42c929..0a181b43d1e7 100644 --- a/packages/SystemUI/res/values-kk/strings.xml +++ b/packages/SystemUI/res/values-kk/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Төменгі оң жаққа жылжыту"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Шетке жылжыту және жасыру"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Шетке жылжыту және көрсету"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ауыстыру"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"Құрылғыны басқару элементтері"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"Жалғанған құрылғылар үшін басқару элементтерін қосу"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"Құрылғыны басқару элементтерін реттеу"</string> @@ -1092,8 +1091,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Жабу"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"Жалғастыру"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"Параметрлер"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Ойнату"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"Өшірулі. Қолданба тексеріңіз."</string>      <string name="controls_error_retryable" msgid="864025882878378470">"Қате, әрекет қайталануда…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"Табылмады"</string> diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml index 48b80f684471..f872660aa1c8 100644 --- a/packages/SystemUI/res/values-km/strings.xml +++ b/packages/SystemUI/res/values-km/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"ផ្លាស់ទីទៅខាងក្រោមផ្នែកខាងស្ដាំ"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"ផ្លាស់ទីទៅផ្នែកខាងចុង រួចលាក់"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"ផ្លាស់ទីចេញពីផ្នែកខាងចុង រួចបង្ហាញ"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"បិទ/បើក"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"ផ្ទាំងគ្រប់គ្រងឧបករណ៍"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"បញ្ចូលផ្ទាំងគ្រប់គ្រងសម្រាប់ឧបករណ៍ដែលអ្នកបានភ្ជាប់"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"រៀបចំផ្ទាំងគ្រប់គ្រងឧបករណ៍"</string> @@ -1094,8 +1093,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"ច្រានចោល"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"បន្ត"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"ការកំណត់"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"ចាក់"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"អសកម្ម ពិនិត្យមើលកម្មវិធី"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"បញ្ហា កំពុងព្យាយាមម្ដងទៀត…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"រកមិនឃើញទេ"</string> diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml index f35c3b28b103..ffc634adbe4f 100644 --- a/packages/SystemUI/res/values-kn/strings.xml +++ b/packages/SystemUI/res/values-kn/strings.xml @@ -137,8 +137,7 @@      <string name="accessibility_phone_button" msgid="4256353121703100427">"ಫೋನ್"</string>      <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"ಧ್ವನಿ ಸಹಾಯಕ"</string>      <string name="accessibility_unlock_button" msgid="122785427241471085">"ಅನ್ಲಾಕ್"</string> -    <!-- no translation found for accessibility_lock_icon (661492842417875775) --> -    <skip /> +    <string name="accessibility_lock_icon" msgid="661492842417875775">"ಸಾಧನ ಲಾಕ್ ಆಗಿದೆ"</string>      <string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"ಫಿಂಗರ್ಪ್ರಿಂಟ್ಗಾಗಿ ನಿರೀಕ್ಷಿಸಲಾಗುತ್ತಿದೆ"</string>      <string name="accessibility_unlock_without_fingerprint" msgid="1811563723195375298">"ನಿಮ್ಮ ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಬಳಸದೆಯೇ ಅನ್ಲಾಕ್ ಮಾಡಿ"</string>      <string name="accessibility_scanning_face" msgid="3093828357921541387">"ಮುಖವನ್ನು ಸ್ಕ್ಯಾನ್ ಮಾಡಲಾಗುತ್ತಿದೆ"</string> @@ -1153,14 +1152,10 @@      <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"ನಿಮ್ಮ ಬ್ಯಾಟರಿ ಮೀಟರ್ ಓದುವಾಗ ಸಮಸ್ಯೆ ಎದುರಾಗಿದೆ"</string>      <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"ಇನ್ನಷ್ಟು ಮಾಹಿತಿಗಾಗಿ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>      <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"ಅಲಾರಾಂ ಸೆಟ್ ಆಗಿಲ್ಲ"</string> -    <!-- no translation found for accessibility_fingerprint_label (5255731221854153660) --> -    <skip /> -    <!-- no translation found for accessibility_udfps_disabled_button (4284034245130239384) --> -    <skip /> -    <!-- no translation found for accessibility_authenticate_hint (798914151813205721) --> -    <skip /> -    <!-- no translation found for accessibility_enter_hint (2617864063504824834) --> -    <skip /> +    <string name="accessibility_fingerprint_label" msgid="5255731221854153660">"ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಸೆನ್ಸರ್"</string> +    <string name="accessibility_udfps_disabled_button" msgid="4284034245130239384">"ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಸೆನ್ಸರ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string> +    <string name="accessibility_authenticate_hint" msgid="798914151813205721">"ದೃಢೀಕರಿಸಿ"</string> +    <string name="accessibility_enter_hint" msgid="2617864063504824834">"ಸಾಧನವನ್ನು ಪ್ರವೇಶಿಸಿ"</string>      <!-- no translation found for keyguard_try_fingerprint (2825130772993061165) -->      <skip />  </resources> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index 3c61f44beff2..7d27acba2fd0 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"오른쪽 하단으로 이동"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"가장자리로 옮겨서 숨기기"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"가장자리 바깥으로 옮겨서 표시"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"전환"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"기기 컨트롤"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"연결된 기기의 컨트롤을 추가하세요."</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"기기 컨트롤 설정"</string> @@ -1092,8 +1091,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"닫기"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"다시 시작"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"설정"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"재생"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"비활성. 앱을 확인하세요."</string>      <string name="controls_error_retryable" msgid="864025882878378470">"오류 발생, 다시 시도 중…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"찾을 수 없음"</string> diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml index a0d460b40599..54310c102821 100644 --- a/packages/SystemUI/res/values-mn/strings.xml +++ b/packages/SystemUI/res/values-mn/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Баруун доош зөөх"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Ирмэг рүү зөөж, нуух"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Ирмэгээс гаргаж, харуулах"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"асаах/унтраах"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"Төхөөрөмжийн хяналт"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"Холбогдсон төхөөрөмжүүд дээрээ хяналт нэмэх"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"Төхөөрөмжийн хяналтыг тохируулах"</string> @@ -1092,8 +1091,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Хаах"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"Үргэлжлүүлэх"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"Тохиргоо"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Тоглуулах"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"Идэвхгүй байна, аппыг шалгана уу"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"Алдаа, дахин оролдож байна…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"Олдсонгүй"</string> diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index 6bbeb52da831..3945370ca7b7 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Alihkan ke bawah sebelah kanan"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Alihkan ke tepi dan sorokkan"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Alihkan ke tepi dan tunjukkan"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"togol"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"Kawalan peranti"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"Tambah kawalan untuk peranti yang disambungkan"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"Sediakan kawalan peranti"</string> @@ -1092,8 +1091,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Tolak"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"Sambung semula"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"Tetapan"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Main"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"Tidak aktif, semak apl"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"Ralat, mencuba semula…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"Tidak ditemukan"</string> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index 649d7c509c65..3dcea65e7701 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Flytt til nederst til høyre"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Flytt til kanten og skjul"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Flytt ut kanten og vis"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"slå av/på"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"Enhetsstyring"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"Legg til kontroller for de tilkoblede enhetene dine"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"Konfigurer enhetsstyring"</string> @@ -1092,8 +1091,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Lukk"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"Gjenoppta"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"Innstillinger"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Spill av"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv. Sjekk appen"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"Feil. Prøver igjen …"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"Ikke funnet"</string> diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index 6258e4590a71..cd87cd5401d6 100644 --- a/packages/SystemUI/res/values-ne/strings.xml +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -137,8 +137,7 @@      <string name="accessibility_phone_button" msgid="4256353121703100427">"फोन"</string>      <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"आवाज सहायता"</string>      <string name="accessibility_unlock_button" msgid="122785427241471085">"खोल्नुहोस्"</string> -    <!-- no translation found for accessibility_lock_icon (661492842417875775) --> -    <skip /> +    <string name="accessibility_lock_icon" msgid="661492842417875775">"यन्त्र लक गरिएको छ"</string>      <string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"फिंगरप्रिन्ट कुर्दै"</string>      <string name="accessibility_unlock_without_fingerprint" msgid="1811563723195375298">"आफ्नो फिंगरप्रिन्ट बिना नै अनलक गर्नुहोस्"</string>      <string name="accessibility_scanning_face" msgid="3093828357921541387">"अनुहार स्क्यान गर्दै"</string> @@ -1153,14 +1152,10 @@      <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"डिभाइसको ब्याट्रीको मिटर रिडिङ क्रममा समस्या भयो"</string>      <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"थप जानकारी प्राप्त गर्न ट्याप गर्नुहोस्"</string>      <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"अलार्म राखिएको छैन"</string> -    <!-- no translation found for accessibility_fingerprint_label (5255731221854153660) --> -    <skip /> -    <!-- no translation found for accessibility_udfps_disabled_button (4284034245130239384) --> -    <skip /> -    <!-- no translation found for accessibility_authenticate_hint (798914151813205721) --> -    <skip /> -    <!-- no translation found for accessibility_enter_hint (2617864063504824834) --> -    <skip /> +    <string name="accessibility_fingerprint_label" msgid="5255731221854153660">"फिंगरप्रिन्ट सेन्सर"</string> +    <string name="accessibility_udfps_disabled_button" msgid="4284034245130239384">"फिंगरप्रिन्ट सेन्सर असक्षम पारिएको छ"</string> +    <string name="accessibility_authenticate_hint" msgid="798914151813205721">"प्रमाणित गर्नुहोस्"</string> +    <string name="accessibility_enter_hint" msgid="2617864063504824834">"डिभाइस हाल्नुहोस्"</string>      <!-- no translation found for keyguard_try_fingerprint (2825130772993061165) -->      <skip />  </resources> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index 0bd3cd589401..d5d094684dd0 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Naar rechtsonder verplaatsen"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Naar rand verplaatsen en verbergen"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Over rand verplaatsen en tonen"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"schakelen"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"Apparaatbediening"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"Voeg bedieningselementen voor je gekoppelde apparaten toe"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"Apparaatbediening instellen"</string> @@ -1092,8 +1091,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Sluiten"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"Hervatten"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"Instellingen"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Afspelen"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"Inactief, check de app"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"Fout. Opnieuw proberen…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"Niet gevonden"</string> diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml index e9371c60af14..95f1d3589ca4 100644 --- a/packages/SystemUI/res/values-or/strings.xml +++ b/packages/SystemUI/res/values-or/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"ନିମ୍ନ ଡାହାଣକୁ ମୁଭ୍ କରନ୍ତୁ"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"ଧାରକୁ ମୁଭ୍ କରି ଲୁଚାନ୍ତୁ"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"ଧାର ବାହାରକୁ ମୁଭ୍ କରି ଦେଖାନ୍ତୁ"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ଟୋଗଲ୍ କରନ୍ତୁ"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"ଡିଭାଇସ୍ ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"ଆପଣଙ୍କ ସଂଯୁକ୍ତ ଡିଭାଇସଗୁଡ଼ିକ ପାଇଁ ନିୟନ୍ତ୍ରଣ ଯୋଗ କରନ୍ତୁ"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"ଡିଭାଇସ୍ ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକୁ ସେଟ୍ ଅପ୍ କରନ୍ତୁ"</string> @@ -1087,15 +1086,12 @@      <string name="controls_structure_tooltip" msgid="4355922222944447867">"ଅଧିକ ଦେଖିବାକୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ"</string>      <string name="controls_seeding_in_progress" msgid="3033855341410264148">"ସୁପାରିଶଗୁଡ଼ିକ ଲୋଡ୍ କରାଯାଉଛି"</string>      <string name="controls_media_title" msgid="1746947284862928133">"ମିଡିଆ"</string> -    <!-- no translation found for controls_media_close_session (1193000643003066508) --> -    <skip /> -    <!-- no translation found for controls_media_active_session (3146882316024153337) --> -    <skip /> +    <string name="controls_media_close_session" msgid="1193000643003066508">"ଏହି ମିଡିଆ ସେସନକୁ ଲୁଚାଇବେ?"</string> +    <string name="controls_media_active_session" msgid="3146882316024153337">"ବର୍ତ୍ତମାନର ମିଡିଆ ସେସନକୁ ଲୁଚାଯାଇପାରିବ ନାହିଁ।"</string>      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"ଖାରଜ କରନ୍ତୁ"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"ପୁଣି ଆରମ୍ଭ କରନ୍ତୁ"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"ସେଟିଂସ୍"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"ଚଲାନ୍ତୁ"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"ନିଷ୍କ୍ରିୟ ଅଛି, ଆପ ଯାଞ୍ଚ କରନ୍ତୁ"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"ତ୍ରୁଟି, ପୁଣି ଚେଷ୍ଟା କରୁଛି…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"ମିଳିଲା ନାହିଁ"</string> @@ -1156,6 +1152,5 @@      <string name="accessibility_udfps_disabled_button" msgid="4284034245130239384">"ଟିପଚିହ୍ନ ସେନ୍ସରକୁ ଅକ୍ଷମ କରାଯାଇଛି"</string>      <string name="accessibility_authenticate_hint" msgid="798914151813205721">"ପ୍ରମାଣୀକରଣ କରନ୍ତୁ"</string>      <string name="accessibility_enter_hint" msgid="2617864063504824834">"ଡିଭାଇସ୍ ବିଷୟରେ ସୂଚନା ଲେଖନ୍ତୁ"</string> -    <!-- no translation found for keyguard_try_fingerprint (2825130772993061165) --> -    <skip /> +    <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ଖୋଲିବାକୁ ଟିପଚିହ୍ନ ବ୍ୟବହାର କରନ୍ତୁ"</string>  </resources> diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml index fdc20266c18a..e0e1b4f2f119 100644 --- a/packages/SystemUI/res/values-pa/strings.xml +++ b/packages/SystemUI/res/values-pa/strings.xml @@ -1087,10 +1087,8 @@      <string name="controls_structure_tooltip" msgid="4355922222944447867">"ਹੋਰ ਦੇਖਣ ਲਈ ਸਵਾਈਪ ਕਰੋ"</string>      <string name="controls_seeding_in_progress" msgid="3033855341410264148">"ਸਿਫ਼ਾਰਸ਼ਾਂ ਲੋਡ ਹੋ ਰਹੀਆਂ ਹਨ"</string>      <string name="controls_media_title" msgid="1746947284862928133">"ਮੀਡੀਆ"</string> -    <!-- no translation found for controls_media_close_session (1193000643003066508) --> -    <skip /> -    <!-- no translation found for controls_media_active_session (3146882316024153337) --> -    <skip /> +    <string name="controls_media_close_session" msgid="1193000643003066508">"ਕੀ ਇਹ ਮੀਡੀਆ ਸੈਸ਼ਨ ਲੁਕਾਉਣਾ ਹੈ?"</string> +    <string name="controls_media_active_session" msgid="3146882316024153337">"ਮੌਜੂਦਾ ਮੀਡੀਆ ਸੈਸ਼ਨ ਲੁਕਾਇਆ ਨਹੀਂ ਜਾ ਸਕਦਾ।"</string>      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"ਖਾਰਜ ਕਰੋ"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"ਮੁੜ-ਚਾਲੂ ਕਰੋ"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"ਸੈਟਿੰਗਾਂ"</string> @@ -1156,6 +1154,5 @@      <string name="accessibility_udfps_disabled_button" msgid="4284034245130239384">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਸੈਂਸਰ ਨੂੰ ਬੰਦ ਕੀਤਾ ਗਿਆ"</string>      <string name="accessibility_authenticate_hint" msgid="798914151813205721">"ਪ੍ਰਮਾਣਿਤ ਕਰੋ"</string>      <string name="accessibility_enter_hint" msgid="2617864063504824834">"ਡੀਵਾਈਸ ਵਿੱਚ ਦਾਖਲ ਹੋਵੋ"</string> -    <!-- no translation found for keyguard_try_fingerprint (2825130772993061165) --> -    <skip /> +    <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ਖੋਲ੍ਹਣ ਲਈ ਫਿੰਗਰਪ੍ਰਿੰਟ ਵਰਤੋ"</string>  </resources> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index 4c6c15911a59..d95eabc8c35a 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -1165,6 +1165,6 @@      <string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Czytnik linii papilarnych"</string>      <string name="accessibility_udfps_disabled_button" msgid="4284034245130239384">"Czytnik linii papilarnych został wyłączony"</string>      <string name="accessibility_authenticate_hint" msgid="798914151813205721">"uwierzytelnij"</string> -    <string name="accessibility_enter_hint" msgid="2617864063504824834">"dodaj urządzenie"</string> +    <string name="accessibility_enter_hint" msgid="2617864063504824834">"otwórz urządzenie"</string>      <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"By otworzyć, użyj odcisku palca"</string>  </resources> diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index cc60b6a3719f..b786dfb46b03 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Mover para o canto inferior direito"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Mover para a borda e ocultar"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Mover para fora da borda e exibir"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"alternar"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"Controles do dispositivo"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"Adiciona controles aos dispositivos conectados"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"Configurar controles do dispositivo"</string> @@ -1092,8 +1091,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Dispensar"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"Retomar"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"Configurações"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Iniciar"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"Inativo, verifique o app"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"Erro. Tentando novamente…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"Não encontrado"</string> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index c38388d42b9b..496fcb21f838 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Mover parte inferior direita"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Mover p/ extremidade e ocultar"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Retirar extremidade e mostrar"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ativar/desativar"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"Controlos de dispositivos"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"Adicione controlos para os dispositivos associados."</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"Configure os controlos de dispositivos"</string> @@ -1092,8 +1091,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Ignorar"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"Retomar"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"Definições"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Reproduzir"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"Inativa. Consulte a app."</string>      <string name="controls_error_retryable" msgid="864025882878378470">"Erro. A tentar novamente…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"Não encontrado."</string> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index cc60b6a3719f..b786dfb46b03 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Mover para o canto inferior direito"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Mover para a borda e ocultar"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Mover para fora da borda e exibir"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"alternar"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"Controles do dispositivo"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"Adiciona controles aos dispositivos conectados"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"Configurar controles do dispositivo"</string> @@ -1092,8 +1091,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Dispensar"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"Retomar"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"Configurações"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Iniciar"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"Inativo, verifique o app"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"Erro. Tentando novamente…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"Não encontrado"</string> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index 4e3fb127ee37..2100466e2cdf 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -1049,8 +1049,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Mutați în dreapta jos"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Mutați în afară și ascundeți"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Mutați în afară și afișați"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"Activați / dezactivați"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"Comenzile dispozitivelor"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"Adăugați comenzi pentru dispozitivele conectate"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"Configurați comenzile dispozitivelor"</string> @@ -1098,8 +1097,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Închideți"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"Reia"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"Setări"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Redați"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"Inactiv, verificați aplicația"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"Eroare, se încearcă din nou…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"Nu s-a găsit"</string> diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml index fe834484ab56..45abf9550ff3 100644 --- a/packages/SystemUI/res/values-si/strings.xml +++ b/packages/SystemUI/res/values-si/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"පහළ දකුණට ගෙන යන්න"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"මායිමට ගෙන යන්න සහ සඟවන්න"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"මායිමෙන් පිටට ගන්න සහ පෙන්වන්න"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ටොගල් කරන්න"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"උපාංග පාලන"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"ඔබේ සම්බන්ධිත උපාංග සඳහා පාලන එක් කරන්න"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"උපාංග පාලන පිහිටුවන්න"</string> @@ -1092,8 +1091,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"ඉවත ලන්න"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"නැවත පටන් ගන්න"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"සැකසීම්"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"වාදනය කරන්න"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"අක්රියයි, යෙදුම පරීක්ෂා කරන්න"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"දෝෂයකි, නැවත උත්සාහ කරමින්…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"හමු නොවිණි"</string> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index d947376d1429..63c3b8bc5876 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -1054,8 +1054,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Presunúť doprava nadol"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Presunúť k okraju a skryť"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Presunúť z okraja a zobraziť"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"prepínač"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"Ovládanie zariadení"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"Pridajte si ovládače pripojených zariadení"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"Nastavenie ovládania zariadení"</string> @@ -1104,8 +1103,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Zavrieť"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"Pokračovať"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"Nastavenia"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Prehrať"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"Neaktívne, preverte aplikáciu"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"Chyba, skúša sa znova…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"Nenájdené"</string> diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml index a0b5081c84ae..f1f7a7a63ff7 100644 --- a/packages/SystemUI/res/values-sq/strings.xml +++ b/packages/SystemUI/res/values-sq/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Zhvendos poshtë djathtas"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Zhvendose te skaji dhe fshihe"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Zhvendose jashtë skajit dhe shfaqe"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"aktivizo/çaktivizo"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"Kontrollet e pajisjes"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"Shto kontrolle për pajisjet e tua të lidhura"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"Konfiguro kontrollet e pajisjes"</string> @@ -1092,8 +1091,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Hiq"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"Vazhdo"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"Cilësimet"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Luaj"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"Joaktive, kontrollo aplikacionin"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"Gabim, po provohet përsëri"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"Nuk u gjet"</string> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index de323ecbffd1..22af16a5e242 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -1049,8 +1049,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Премести доле десно"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Премести до ивице и сакриј"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Премести изван ивице и прикажи"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"укључите/искључите"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"Контроле уређаја"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"Додајте контроле за повезане уређаје"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"Подесите контроле уређаја"</string> @@ -1098,8 +1097,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Одбаци"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"Настави"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"Подешавања"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Пусти"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"Неактивно. Видите апликацију"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"Грешка, покушава се поново…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"Није пронађено"</string> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index cc7adf5bd078..ebcae0f3ade8 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Flytta längst ned till höger"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Flytta till kanten och dölj"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Flytta från kanten och visa"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"aktivera och inaktivera"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"Enhetsstyrning"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"Lägg till snabbkontroller för anslutna enheter"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"Konfigurera enhetsstyrning"</string> @@ -1092,8 +1091,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Stäng"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"Återuppta"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"Inställningar"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Spela upp"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv, kolla appen"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"Fel, försöker igen …"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"Hittades inte"</string> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index afa23984d9e8..2a45ce5a0a33 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Sogeza chini kulia"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Sogeza kwenye ukingo kisha ufiche"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Sogeza nje ya ukingo kisha uonyeshe"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"geuza"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"Vidhibiti vya vifaa"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"Weka vidhibiti vya vifaa ulivyounganisha"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"Weka mipangilio ya vidhibiti vya vifaa"</string> @@ -1092,8 +1091,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Ondoa"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"Endelea"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"Mipangilio"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Cheza"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"Haitumiki, angalia programu"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"Hitilafu, inajaribu tena…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"Hakipatikani"</string> diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml index ad0e4c751900..63b4c3b8560d 100644 --- a/packages/SystemUI/res/values-ta/strings.xml +++ b/packages/SystemUI/res/values-ta/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"கீழே வலதுபுறத்திற்கு நகர்த்து"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"ஓரத்திற்கு நகர்த்தி மறை"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"ஓரத்திற்கு நகர்த்தி, காட்டு"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"நிலைமாற்று"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"சாதனக் கட்டுப்பாடுகள்"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"இணைக்கப்பட்ட சாதனங்களில் கட்டுப்பாடுகளைச் சேர்க்கலாம்"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"சாதனக் கட்டுப்பாடுகளை அமைத்தல்"</string> @@ -1092,8 +1091,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"மூடுக"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"தொடர்க"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"அமைப்புகள்"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"இயக்குதல்"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"செயலில் இல்லை , சரிபார்க்கவும்"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"பிழை, மீண்டும் முயல்கிறது…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"இல்லை"</string> diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml index 0b030faa82e7..7b05e3620d9b 100644 --- a/packages/SystemUI/res/values-te/strings.xml +++ b/packages/SystemUI/res/values-te/strings.xml @@ -1087,10 +1087,8 @@      <string name="controls_structure_tooltip" msgid="4355922222944447867">"మరిన్నింటిని చూడటం కోసం స్వైప్ చేయండి"</string>      <string name="controls_seeding_in_progress" msgid="3033855341410264148">"సిఫార్సులు లోడ్ అవుతున్నాయి"</string>      <string name="controls_media_title" msgid="1746947284862928133">"మీడియా"</string> -    <!-- no translation found for controls_media_close_session (1193000643003066508) --> -    <skip /> -    <!-- no translation found for controls_media_active_session (3146882316024153337) --> -    <skip /> +    <string name="controls_media_close_session" msgid="1193000643003066508">"ఈ మీడియా సెషన్ను దాచాలా?"</string> +    <string name="controls_media_active_session" msgid="3146882316024153337">"ప్రస్తుత మీడియా సెషన్ను దాచడం సాధ్యం కాదు."</string>      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"విస్మరించు"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"కొనసాగించండి"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"సెట్టింగ్లు"</string> @@ -1156,6 +1154,5 @@      <string name="accessibility_udfps_disabled_button" msgid="4284034245130239384">"వేలిముద్ర సెన్సార్ డిజేబుల్ చేయబడింది"</string>      <string name="accessibility_authenticate_hint" msgid="798914151813205721">"ప్రామాణీకరించండి"</string>      <string name="accessibility_enter_hint" msgid="2617864063504824834">"పరికరాన్ని ఎంటర్ చేయండి"</string> -    <!-- no translation found for keyguard_try_fingerprint (2825130772993061165) --> -    <skip /> +    <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"తెరవడానికి వేలిముద్రను ఉపయోగించండి"</string>  </resources> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index 578f8a11bf39..171ecd449b06 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"ย้ายไปด้านขาวล่าง"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"ย้ายไปที่ขอบและซ่อน"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"ย้ายออกจากขอบและแสดง"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"สลับ"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"ระบบควบคุมอุปกรณ์"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"เพิ่มตัวควบคุมของอุปกรณ์ที่เชื่อมต่อ"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"ตั้งค่าระบบควบคุมอุปกรณ์"</string> @@ -1092,8 +1091,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"ปิด"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"เล่นต่อ"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"การตั้งค่า"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"เล่น"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"ไม่มีการใช้งาน โปรดตรวจสอบแอป"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"มีข้อผิดพลาด กำลังลองอีกครั้ง…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"ไม่พบ"</string> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index 896eeade63fc..0490ff7ce286 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Ilipat sa kanan sa ibaba"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Ilipat sa sulok at itago"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Alisin sa sulok at ipakita"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"i-toggle"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"Mga kontrol ng device"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"Magdagdag ng kontrol para sa mga nakakonektang device"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"I-set up ang mga kontrol ng device"</string> @@ -1092,8 +1091,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"I-dismiss"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"Ituloy"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"Mga Setting"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"I-play"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"Hindi aktibo, tingnan ang app"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"Nagka-error, sinusubukan ulit…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"Hindi nahanap"</string> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index c584d31438b4..12cae9b93216 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Sağ alta taşı"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Kenara taşıyıp gizle"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Kenarın dışına taşıyıp göster"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"değiştir"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"Cihaz denetimleri"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"Bağlı cihazlarınız için denetimler ekleyin"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"Cihaz denetimlerini kur"</string> @@ -1092,8 +1091,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Kapat"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"Devam ettir"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"Ayarlar"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Oynat"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"Devre dışı, uygulamaya bakın"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"Hata, yeniden deneniyor…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"Bulunamadı"</string> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index 73d5e935a973..4e7de7110672 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -1165,6 +1165,6 @@      <string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Сканер відбитків пальців"</string>      <string name="accessibility_udfps_disabled_button" msgid="4284034245130239384">"Сканер відбитків пальців вимкнено"</string>      <string name="accessibility_authenticate_hint" msgid="798914151813205721">"пройти автентифікацію"</string> -    <string name="accessibility_enter_hint" msgid="2617864063504824834">"виконати вхід на пристрої"</string> +    <string name="accessibility_enter_hint" msgid="2617864063504824834">"відкрити пристрій"</string>      <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Щоб відкрити, використайте відбиток пальця"</string>  </resources> diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml index 7e9cf556a9c8..702bc7efd36b 100644 --- a/packages/SystemUI/res/values-ur/strings.xml +++ b/packages/SystemUI/res/values-ur/strings.xml @@ -137,8 +137,7 @@      <string name="accessibility_phone_button" msgid="4256353121703100427">"فون"</string>      <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"صوتی معاون"</string>      <string name="accessibility_unlock_button" msgid="122785427241471085">"غیر مقفل کریں"</string> -    <!-- no translation found for accessibility_lock_icon (661492842417875775) --> -    <skip /> +    <string name="accessibility_lock_icon" msgid="661492842417875775">"آلہ مقفل کر دیا گیا"</string>      <string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"فنگر پرنٹ کا انتظار ہے"</string>      <string name="accessibility_unlock_without_fingerprint" msgid="1811563723195375298">"فنگر پرنٹ استعمال کیے بغیرغیر مقفل کریں"</string>      <string name="accessibility_scanning_face" msgid="3093828357921541387">"اسکیننگ چہرہ"</string> @@ -1088,10 +1087,8 @@      <string name="controls_structure_tooltip" msgid="4355922222944447867">"مزید دیکھنے کیلئے سوائپ کریں"</string>      <string name="controls_seeding_in_progress" msgid="3033855341410264148">"تجاویز لوڈ ہو رہی ہیں"</string>      <string name="controls_media_title" msgid="1746947284862928133">"میڈیا"</string> -    <!-- no translation found for controls_media_close_session (1193000643003066508) --> -    <skip /> -    <!-- no translation found for controls_media_active_session (3146882316024153337) --> -    <skip /> +    <string name="controls_media_close_session" msgid="1193000643003066508">"اس میڈیا سیشن کو چھپائیں؟"</string> +    <string name="controls_media_active_session" msgid="3146882316024153337">"میڈیا کے موجودہ سیشن کو چھپایا نہیں جا سکتا۔"</string>      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"برخاست کریں"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"دوبارہ شروع کریں"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"ترتیبات"</string> @@ -1153,14 +1150,9 @@      <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"آپ کے بیٹری میٹر کو پڑھنے میں دشواری"</string>      <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"مزید معلومات کے لیے تھپتھپائیں"</string>      <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"کوئی الارم سیٹ نہیں ہے"</string> -    <!-- no translation found for accessibility_fingerprint_label (5255731221854153660) --> -    <skip /> -    <!-- no translation found for accessibility_udfps_disabled_button (4284034245130239384) --> -    <skip /> -    <!-- no translation found for accessibility_authenticate_hint (798914151813205721) --> -    <skip /> -    <!-- no translation found for accessibility_enter_hint (2617864063504824834) --> -    <skip /> -    <!-- no translation found for keyguard_try_fingerprint (2825130772993061165) --> -    <skip /> +    <string name="accessibility_fingerprint_label" msgid="5255731221854153660">"فنگر پرنٹ سینسر"</string> +    <string name="accessibility_udfps_disabled_button" msgid="4284034245130239384">"فنگر پرنٹ سینسر غیر فعال ہے"</string> +    <string name="accessibility_authenticate_hint" msgid="798914151813205721">"تصدیق کریں"</string> +    <string name="accessibility_enter_hint" msgid="2617864063504824834">"آلہ درج کریں"</string> +    <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"کھولنے کے لیے فنگر پرنٹ کا استعمال کریں"</string>  </resources> diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml index eb6a27214556..216a0944fcad 100644 --- a/packages/SystemUI/res/values-uz/strings.xml +++ b/packages/SystemUI/res/values-uz/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Quyi oʻngga surish"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Chetiga olib borish va yashirish"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Chetidan qaytarish va koʻrsatish"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"oʻzgartirish"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"Qurilmalarni boshqarish"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"Ulangan qurilmalar uchun boshqaruv elementlari"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"Qurilma boshqaruv elementlarini sozlash"</string> @@ -1092,8 +1091,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Yopish"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"Davom etish"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"Sozlamalar"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Ijro"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"Nofaol. Ilovani tekshiring"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"Xato, qayta urinilmoqda…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"Topilmadi"</string> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index 237036f725c8..a6a9ace99e4c 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Chuyển tới dưới cùng bên phải"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Chuyển đến cạnh và ẩn"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Chuyển ra xa cạnh và hiển thị"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"bật/tắt"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"Điều khiển thiết bị"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"Thêm các nút điều khiển cho các thiết bị đã kết nối"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"Thiết lập các tùy chọn điều khiển thiết bị"</string> @@ -1092,8 +1091,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Đóng"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"Tiếp tục"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"Cài đặt"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Phát"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"Không hoạt động, hãy kiểm tra ứng dụng"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"Lỗi, đang thử lại…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"Không tìm thấy"</string> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index aa5e4e2b1824..51b9a545721e 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"移去右下方"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"移到邊緣並隱藏"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"從邊緣移出並顯示"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"切換"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"裝置控制"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"為連接的裝置新增控制選項"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"設定裝置控制"</string> @@ -1092,8 +1091,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"關閉"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"繼續播放"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"設定"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"播放"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"已停用,請檢查應用程式"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"發生錯誤,正在重試…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"找不到"</string> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index ed44b087f0f8..8a93729c1e34 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"移到右下方"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"移到邊緣並隱藏"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"從邊緣移出並顯示"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"切換"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"裝置控制"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"新增已連結裝置的控制項"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"設定裝置控制項"</string> @@ -1092,8 +1091,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"關閉"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"繼續播放"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"設定"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"播放"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"無效,請查看應用程式"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"發生錯誤,正在重試…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"找不到控制項"</string> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index 01e0fca3a89e..674a7c843f5f 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -1044,8 +1044,7 @@      <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Hamba phansi ngakwesokudla"</string>      <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Hamba onqenqemeni ufihle"</string>      <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Phuma onqenqemeni ubonise"</string> -    <!-- no translation found for accessibility_floating_button_action_double_tap_to_toggle (7976492639670692037) --> -    <skip /> +    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"guqula"</string>      <string name="quick_controls_title" msgid="6839108006171302273">"Izilawuli zezinsiza"</string>      <string name="quick_controls_subtitle" msgid="1667408093326318053">"Engeza izilawuli zedivayisi yakho exhunyiwe"</string>      <string name="quick_controls_setup_title" msgid="8901436655997849822">"Setha izilawuli zezinsiza"</string> @@ -1092,8 +1091,7 @@      <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Cashisa"</string>      <string name="controls_media_resume" msgid="1933520684481586053">"Qalisa kabusha"</string>      <string name="controls_media_settings_button" msgid="5815790345117172504">"Izilungiselelo"</string> -    <!-- no translation found for controls_media_smartspace_rec_title (1699818353932537407) --> -    <skip /> +    <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Dlala"</string>      <string name="controls_error_timeout" msgid="794197289772728958">"Akusebenzi, hlola uhlelo lokusebenza"</string>      <string name="controls_error_retryable" msgid="864025882878378470">"Iphutha, iyazama futhi…"</string>      <string name="controls_error_removed" msgid="6675638069846014366">"Ayitholakali"</string> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 13c285f12393..edd8486379a2 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1279,9 +1279,10 @@      <dimen name="qs_media_disabled_seekbar_vertical_padding">36dp</dimen>      <!-- Size of Smartspace media recommendations cards in the QSPanel carousel --> -    <dimen name="qs_aa_media_rec_header_icon_padding">10dp</dimen> +    <dimen name="qs_aa_media_rec_header_icon_start_margin">10dp</dimen>      <dimen name="qs_aa_media_rec_header_icon_size">18dp</dimen>      <dimen name="qs_aa_media_rec_album_size">72dp</dimen> +    <dimen name="qs_aa_media_rec_album_vertical_margin">8dp</dimen>      <dimen name="qq_aa_media_rec_header_text_size">16sp</dimen>      <!-- Window magnification --> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 673a03ddac4e..d9cc24fa38ef 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1897,13 +1897,16 @@      <string name="notification_channel_summary_automatic_demoted"><b>Status:</b> Ranked Lower</string>      <!-- [CHAR LIMIT=150] Notification Importance title: important conversation level summary --> -    <string name="notification_channel_summary_priority">Always shown at the top of your notifications, even when Priority mode is on</string> +    <string name="notification_channel_summary_priority_baseline">Shows at the top of conversation notifications and as a profile picture on lock screen</string> +    <string name="notification_channel_summary_priority_bubble">Shows at the top of conversation notifications and as a profile picture on lock screen, appears as a bubble</string> +    <string name="notification_channel_summary_priority_dnd">Shows at the top of conversation notifications and as a profile picture on lock screen, interrupts Do Not Disturb</string> +    <string name="notification_channel_summary_priority_all">Shows at the top of conversation notifications and as a profile picture on lock screen, appears as a bubble, interrupts Do Not Disturb</string>      <!--[CHAR LIMIT=30] Linkable text to Settings app -->      <string name="notification_conversation_channel_settings">Settings</string>      <!-- [CHAR LIMIT=150] Notification Importance title: important conversation level --> -    <string name="notification_priority_title">Priority conversations</string> +    <string name="notification_priority_title">Priority</string>      <!-- Text shown in notification guts for conversation notifications that don't implement the full feature -->      <string name="no_shortcut"><xliff:g id="app_name" example="YouTube">%1$s</xliff:g> doesn\u2019t support conversation features</string> @@ -2667,25 +2670,6 @@      <!-- Title of the overlay warning the user to interact with the device or it will go to sleep. [CHAR LIMIT=25] -->      <string name="inattentive_sleep_warning_title">Standby</string> -    <!-- Priority conversation onboarding screen --> -    <!--  title of priority onboarding [CHAR LIMIT=75]  --> -    <string name="priority_onboarding_title">Conversation set to priority</string> -    <!--  Text explaining that the following actions are the behaviors of priority conversations. -    E.g. priority conversations will show at the top of the conversation section [CHAR LIMIT=75]  --> -    <string name="priority_onboarding_behavior">Priority conversations</string> -    <!--  Text explaining that priority conversations show at the top of the conversation section [CHAR LIMIT=120]  --> -    <string name="priority_onboarding_show_at_top_text">These conversations are shown at the top of your list and can always reach you when Priority mode is on</string> -    <!--  Text explaining that priority conversations show an avatar on the lock screen [CHAR LIMIT=120]  --> -    <string name="priority_onboarding_show_avatar_text">Profile pictures are shown on the lock screen</string> -    <!--  Text explaining that priority conversations will appear as a bubble [CHAR LIMIT=120]  --> -    <string name="priority_onboarding_appear_as_bubble_text">You can easily find these conversations in bubbles on your Home screen</string> -    <!--  Text explaining that priority conversations can interrupt DnD settings [CHAR LIMIT=120]  --> -    <string name="priority_onboarding_ignores_dnd_text">Interrupt Do Not Disturb</string> -    <!--  Title for the affirmative button [CHAR LIMIT=50]  --> -    <string name="priority_onboarding_done_button_title">Got it</string> -    <!--  Title for the settings button button [CHAR LIMIT=50]  --> -    <string name="priority_onboarding_settings_button_title">Settings</string> -      <!-- Window Magnification strings -->      <!-- Title for Magnification Window [CHAR LIMIT=NONE] -->      <string name="magnification_window_title">Magnification Window</string> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index ac9ced93f2df..aa1f954cb27a 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -14,7 +14,8 @@       limitations under the License.  --> -<resources xmlns:android="http://schemas.android.com/apk/res/android"> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +           xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">      <style name="ClearAllButtonDefaultMargins">          <item name="android:layout_marginStart">0dp</item>          <item name="android:layout_marginTop">0dp</item> @@ -609,12 +610,54 @@          <item name="android:elevation">10dp</item>      </style> -    <style name="MediaPlayer.Button" parent="@android:style/Widget.Material.Button.Borderless.Small"> +    <!-- Media controls always have light background --> +    <style name="MediaPlayer" parent="@*android:style/Theme.DeviceDefault.Light"> +        <item name="android:textColor">?android:attr/textColorPrimary</item> +        <item name="android:backgroundTint">@android:color/system_accent2_50</item> +    </style> + +    <style name="MediaPlayer.ProgressBar" parent="@android:style/Widget.ProgressBar.Horizontal"> +        <item name="android:thumbTint">?android:attr/textColorPrimary</item> +        <item name="android:progressTint">?android:attr/textColorPrimary</item> +        <item name="android:progressBackgroundTint">?android:attr/textColorTertiary</item> +        <item name="android:clickable">true</item> +        <item name="android:splitTrack">false</item> +    </style> + +    <style name="MediaPlayer.Subtitle" parent="MediaPlayer"> +        <item name="android:textColor">?android:attr/textColorSecondary</item> +    </style> + +    <style name="MediaPlayer.Action" parent="@android:style/Widget.Material.Button.Borderless.Small">          <item name="android:background">@drawable/qs_media_light_source</item>          <item name="android:tint">?android:attr/textColorPrimary</item>          <item name="android:stateListAnimator">@anim/media_button_state_list_animator</item>      </style> +    <style name="MediaPlayer.OutlineButton"> +        <item name="android:background">@drawable/qs_media_button_background</item> +        <item name="android:textColor">?android:attr/textColorPrimary</item> +        <item name="android:backgroundTint">?androidprv:attr/colorAccentPrimaryVariant</item> +        <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item> +    </style> + +    <style name="MediaPlayer.SolidButton"> +        <item name="android:backgroundTint">?android:attr/colorAccent</item> +        <item name="android:tint">?android:attr/colorPrimary</item> +        <item name="android:textColor">?android:attr/colorPrimary</item> +    </style> + +    <style name="MediaPlayer.AppIcon"> +        <item name="android:background">@drawable/qs_media_icon_background</item> +        <item name="android:backgroundTint">?android:attr/colorPrimary</item> +        <item name="android:tint">?android:attr/colorAccent</item> +    </style> + +    <style name="MediaPlayer.Album"> +        <item name="android:backgroundTint">?androidprv:attr/colorAccentSecondary</item> + +    </style> +      <!-- Used to style charging animation AVD animation -->      <style name="ChargingAnim" /> diff --git a/packages/SystemUI/res/xml/media_recommendation_collapsed.xml b/packages/SystemUI/res/xml/media_recommendation_collapsed.xml index afd800b106c3..31a924cf4892 100644 --- a/packages/SystemUI/res/xml/media_recommendation_collapsed.xml +++ b/packages/SystemUI/res/xml/media_recommendation_collapsed.xml @@ -22,8 +22,8 @@          android:id="@+id/recommendation_card_icon"          android:layout_width="@dimen/qs_aa_media_rec_header_icon_size"          android:layout_height="@dimen/qs_aa_media_rec_header_icon_size" -        android:layout_marginTop="@dimen/qs_aa_media_rec_header_icon_padding" -        android:layout_marginStart="@dimen/qs_aa_media_rec_header_icon_padding" +        android:layout_marginTop="@dimen/qs_media_padding" +        android:layout_marginStart="@dimen/qs_aa_media_rec_header_icon_start_margin"          app:layout_constraintTop_toTopOf="parent"          app:layout_constraintStart_toStartOf="parent"          app:layout_constraintEnd_toStartOf="@id/media_vertical_start_guideline" @@ -33,7 +33,7 @@          android:id="@+id/recommendation_card_text"          android:layout_width="wrap_content"          android:layout_height="wrap_content" -        android:layout_marginStart="@dimen/qs_aa_media_rec_header_icon_padding" +        android:layout_marginStart="@dimen/qs_aa_media_rec_header_icon_start_margin"          app:layout_constraintTop_toBottomOf="@id/recommendation_card_icon"          app:layout_constraintStart_toStartOf="parent"          app:layout_constraintEnd_toStartOf="@id/media_vertical_start_guideline" @@ -45,9 +45,12 @@          android:layout_height="@dimen/qs_aa_media_rec_album_size"          app:layout_constraintTop_toTopOf="parent"          app:layout_constraintBottom_toBottomOf="parent" +        android:layout_marginTop="@dimen/qs_media_padding" +        android:layout_marginBottom="@dimen/qs_media_padding"          app:layout_constraintStart_toEndOf="@id/media_vertical_start_guideline"          app:layout_constraintEnd_toStartOf="@id/media_cover2"          app:layout_constraintHorizontal_chainStyle="spread" +        app:layout_constraintVertical_chainStyle="spread"          android:visibility="gone" />      <Constraint @@ -64,6 +67,8 @@          android:id="@+id/media_cover2"          android:layout_width="@dimen/qs_aa_media_rec_album_size"          android:layout_height="@dimen/qs_aa_media_rec_album_size" +        android:layout_marginTop="@dimen/qs_media_padding" +        android:layout_marginBottom="@dimen/qs_media_padding"          app:layout_constraintTop_toTopOf="parent"          app:layout_constraintBottom_toBottomOf="parent"          app:layout_constraintStart_toEndOf="@id/media_cover1" @@ -85,6 +90,8 @@          android:id="@+id/media_cover3"          android:layout_width="@dimen/qs_aa_media_rec_album_size"          android:layout_height="@dimen/qs_aa_media_rec_album_size" +        android:layout_marginTop="@dimen/qs_media_padding" +        android:layout_marginBottom="@dimen/qs_media_padding"          app:layout_constraintTop_toTopOf="parent"          app:layout_constraintBottom_toBottomOf="parent"          app:layout_constraintStart_toEndOf="@id/media_cover2" @@ -112,7 +119,6 @@          app:layout_constraintStart_toEndOf="@id/media_vertical_start_guideline"          app:layout_constraintEnd_toStartOf="@id/media_cover5"          app:layout_constraintHorizontal_chainStyle="spread" -        app:layout_constraintHorizontal_bias="1"          android:visibility="gone" />      <Constraint @@ -134,7 +140,6 @@          app:layout_constraintStart_toEndOf="@+id/media_cover4"          app:layout_constraintEnd_toStartOf="@+id/media_cover6"          app:layout_constraintHorizontal_chainStyle="spread" -        app:layout_constraintHorizontal_bias="1"          android:visibility="gone" />      <Constraint diff --git a/packages/SystemUI/res/xml/media_recommendation_expanded.xml b/packages/SystemUI/res/xml/media_recommendation_expanded.xml index 04a4877f8660..1411030a7431 100644 --- a/packages/SystemUI/res/xml/media_recommendation_expanded.xml +++ b/packages/SystemUI/res/xml/media_recommendation_expanded.xml @@ -23,7 +23,7 @@          android:layout_width="@dimen/qs_aa_media_rec_header_icon_size"          android:layout_height="@dimen/qs_aa_media_rec_header_icon_size"          android:layout_marginTop="@dimen/qs_media_padding" -        android:layout_marginStart="@dimen/qs_aa_media_rec_header_icon_padding" +        android:layout_marginStart="@dimen/qs_aa_media_rec_header_icon_start_margin"          app:layout_constraintTop_toTopOf="parent"          app:layout_constraintStart_toStartOf="parent"          app:layout_constraintEnd_toStartOf="@id/media_vertical_start_guideline" @@ -33,7 +33,7 @@          android:id="@+id/recommendation_card_text"          android:layout_width="wrap_content"          android:layout_height="wrap_content" -        android:layout_marginStart="@dimen/qs_aa_media_rec_header_icon_padding" +        android:layout_marginStart="@dimen/qs_aa_media_rec_header_icon_start_margin"          app:layout_constraintTop_toBottomOf="@id/recommendation_card_icon"          app:layout_constraintStart_toStartOf="parent"          app:layout_constraintEnd_toStartOf="@id/media_vertical_start_guideline" @@ -44,11 +44,14 @@          android:layout_width="@dimen/qs_aa_media_rec_album_size"          android:layout_height="@dimen/qs_aa_media_rec_album_size"          android:layout_marginTop="@dimen/qs_media_padding" +        android:layout_marginBottom="@dimen/qs_aa_media_rec_album_vertical_margin"          app:layout_constraintTop_toTopOf="parent" -        app:layout_constraintBottom_toTopOf="@+id/media_cover4" +        app:layout_constraintBottom_toTopOf="@+id/media_horizontal_center_guideline"          app:layout_constraintStart_toEndOf="@id/media_vertical_start_guideline"          app:layout_constraintEnd_toStartOf="@id/media_cover2"          app:layout_constraintHorizontal_chainStyle="spread" +        app:layout_constraintVertical_chainStyle="spread" +        app:layout_constraintVertical_bias="0"          android:visibility="gone" />      <Constraint @@ -66,11 +69,14 @@          android:layout_width="@dimen/qs_aa_media_rec_album_size"          android:layout_height="@dimen/qs_aa_media_rec_album_size"          android:layout_marginTop="@dimen/qs_media_padding" +        android:layout_marginBottom="@dimen/qs_aa_media_rec_album_vertical_margin"          app:layout_constraintTop_toTopOf="parent" -        app:layout_constraintBottom_toTopOf="@+id/media_cover5" +        app:layout_constraintBottom_toTopOf="@+id/media_horizontal_center_guideline"          app:layout_constraintStart_toEndOf="@id/media_cover1"          app:layout_constraintEnd_toStartOf="@id/media_cover3"          app:layout_constraintHorizontal_chainStyle="spread" +        app:layout_constraintVertical_chainStyle="spread" +        app:layout_constraintVertical_bias="0"          android:visibility="gone" />      <Constraint @@ -88,12 +94,15 @@          android:layout_width="@dimen/qs_aa_media_rec_album_size"          android:layout_height="@dimen/qs_aa_media_rec_album_size"          android:layout_marginTop="@dimen/qs_media_padding" +        android:layout_marginBottom="@dimen/qs_aa_media_rec_album_vertical_margin"          app:layout_constraintTop_toTopOf="parent" -        app:layout_constraintBottom_toTopOf="@+id/media_cover6" +        app:layout_constraintBottom_toTopOf="@+id/media_horizontal_center_guideline"          app:layout_constraintStart_toEndOf="@id/media_cover2"          app:layout_constraintEnd_toEndOf="parent"          app:layout_constraintHorizontal_chainStyle="spread"          app:layout_constraintHorizontal_bias="1" +        app:layout_constraintVertical_chainStyle="spread" +        app:layout_constraintVertical_bias="0"          android:visibility="gone" />      <Constraint @@ -110,14 +119,15 @@          android:id="@+id/media_cover4"          android:layout_width="@dimen/qs_aa_media_rec_album_size"          android:layout_height="@dimen/qs_aa_media_rec_album_size" -        android:layout_marginTop="@dimen/qs_media_padding" +        android:layout_marginTop="@dimen/qs_aa_media_rec_album_vertical_margin"          android:layout_marginBottom="@dimen/qs_media_padding" -        app:layout_constraintTop_toBottomOf="@+id/media_cover1" +        app:layout_constraintTop_toBottomOf="@+id/media_horizontal_center_guideline"          app:layout_constraintBottom_toBottomOf="parent"          app:layout_constraintStart_toEndOf="@id/media_vertical_start_guideline"          app:layout_constraintEnd_toStartOf="@id/media_cover5"          app:layout_constraintHorizontal_chainStyle="spread" -        app:layout_constraintHorizontal_bias="1" +        app:layout_constraintVertical_chainStyle="spread" +        app:layout_constraintVertical_bias="1"          android:visibility="gone" />      <Constraint @@ -134,14 +144,15 @@          android:id="@+id/media_cover5"          android:layout_width="@dimen/qs_aa_media_rec_album_size"          android:layout_height="@dimen/qs_aa_media_rec_album_size" -        android:layout_marginTop="@dimen/qs_media_padding" +        android:layout_marginTop="@dimen/qs_aa_media_rec_album_vertical_margin"          android:layout_marginBottom="@dimen/qs_media_padding" -        app:layout_constraintTop_toBottomOf="@+id/media_cover2" +        app:layout_constraintTop_toBottomOf="@+id/media_horizontal_center_guideline"          app:layout_constraintBottom_toBottomOf="parent"          app:layout_constraintStart_toEndOf="@+id/media_cover4"          app:layout_constraintEnd_toStartOf="@+id/media_cover6"          app:layout_constraintHorizontal_chainStyle="spread" -        app:layout_constraintHorizontal_bias="1" +        app:layout_constraintVertical_chainStyle="spread" +        app:layout_constraintVertical_bias="1"          android:visibility="gone" />      <Constraint @@ -158,14 +169,16 @@          android:id="@+id/media_cover6"          android:layout_width="@dimen/qs_aa_media_rec_album_size"          android:layout_height="@dimen/qs_aa_media_rec_album_size" -        android:layout_marginTop="@dimen/qs_media_padding" +        android:layout_marginTop="@dimen/qs_aa_media_rec_album_vertical_margin"          android:layout_marginBottom="@dimen/qs_media_padding" -        app:layout_constraintTop_toBottomOf="@id/media_cover3" +        app:layout_constraintTop_toBottomOf="@id/media_horizontal_center_guideline"          app:layout_constraintBottom_toBottomOf="parent"          app:layout_constraintStart_toEndOf="@id/media_cover5"          app:layout_constraintEnd_toEndOf="parent"          app:layout_constraintHorizontal_chainStyle="spread"          app:layout_constraintHorizontal_bias="1" +        app:layout_constraintVertical_chainStyle="spread" +        app:layout_constraintVertical_bias="1"          android:visibility="gone" />      <Constraint diff --git a/packages/SystemUI/res/xml/people_space_widget_info.xml b/packages/SystemUI/res/xml/people_space_widget_info.xml index cce27e71dbd2..aa24bb49d868 100644 --- a/packages/SystemUI/res/xml/people_space_widget_info.xml +++ b/packages/SystemUI/res/xml/people_space_widget_info.xml @@ -26,5 +26,5 @@      android:previewLayout="@layout/people_space_placeholder_layout"      android:resizeMode="horizontal|vertical"      android:configure="com.android.systemui.people.PeopleSpaceActivity" -    android:initialLayout="@layout/people_space_initial_layout"> +    android:initialLayout="@layout/people_tile_empty_layout">  </appwidget-provider> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java index b7a2c64dd107..2325b554d507 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java @@ -76,7 +76,7 @@ public class KeyguardPINView extends KeyguardPinBasedInputView {      protected void onFinishInflate() {          super.onFinishInflate(); -        mContainer = findViewById(R.id.container); +        mContainer = findViewById(R.id.pin_container);          mRow0 = findViewById(R.id.row0);          mRow1 = findViewById(R.id.row1);          mRow2 = findViewById(R.id.row2); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java index d4513384c569..98e7fb48b7a6 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java @@ -97,7 +97,7 @@ public class KeyguardPatternView extends KeyguardInputView          mLockPatternView = findViewById(R.id.lockPatternView);          mEcaView = findViewById(R.id.keyguard_selector_fade_container); -        mContainer = findViewById(R.id.container); +        mContainer = findViewById(R.id.pattern_container);      }      @Override diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java index f28d1137f3e7..7f183798709c 100644 --- a/packages/SystemUI/src/com/android/systemui/Prefs.java +++ b/packages/SystemUI/src/com/android/systemui/Prefs.java @@ -73,8 +73,7 @@ public final class Prefs {              Key.TOUCHED_RINGER_TOGGLE,              Key.HAS_SEEN_ODI_CAPTIONS_TOOLTIP,              Key.HAS_SEEN_REVERSE_BOTTOM_SHEET, -            Key.CONTROLS_STRUCTURE_SWIPE_TOOLTIP_COUNT, -            Key.HAS_SEEN_PRIORITY_ONBOARDING_IN_S +            Key.CONTROLS_STRUCTURE_SWIPE_TOOLTIP_COUNT      })      // TODO: annotate these with their types so {@link PrefsCommandLine} can know how to set them      public @interface Key { @@ -123,8 +122,6 @@ public final class Prefs {          String HAS_SEEN_ODI_CAPTIONS_TOOLTIP = "HasSeenODICaptionsTooltip";          String HAS_SEEN_REVERSE_BOTTOM_SHEET = "HasSeenReverseBottomSheet";          String CONTROLS_STRUCTURE_SWIPE_TOOLTIP_COUNT = "ControlsStructureSwipeTooltipCount"; -        /** Tracks whether the user has seen the onboarding screen for priority conversations */ -        String HAS_SEEN_PRIORITY_ONBOARDING_IN_S = "HasUserSeenPriorityOnboardingInS";      }      public static boolean getBoolean(Context context, @Key String key, boolean defaultValue) { diff --git a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java index 58881d9a33f4..c821d100f553 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java @@ -35,7 +35,6 @@ import com.android.systemui.dagger.qualifiers.TestHarness;  import com.android.systemui.dock.DockManager;  import com.android.systemui.plugins.FalsingManager;  import com.android.systemui.statusbar.policy.KeyguardStateController; -import com.android.systemui.util.sensors.ThresholdSensor;  import java.io.FileDescriptor;  import java.io.PrintWriter; @@ -317,7 +316,7 @@ public class BrightLineFalsingManager implements FalsingManager {      }      @Override -    public void onProximityEvent(ThresholdSensor.ThresholdSensorEvent proximityEvent) { +    public void onProximityEvent(ProximityEvent proximityEvent) {          // TODO: some of these classifiers might allow us to abort early, meaning we don't have to          // make these calls.          mClassifiers.forEach((classifier) -> classifier.onProximityEvent(proximityEvent)); diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingClassifier.java index 81b9f66e9bc3..d75752841023 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingClassifier.java @@ -18,7 +18,7 @@ package com.android.systemui.classifier;  import android.view.MotionEvent; -import com.android.systemui.util.sensors.ProximitySensor; +import com.android.systemui.plugins.FalsingManager;  import java.util.List; @@ -110,7 +110,7 @@ public abstract class FalsingClassifier {      /**       * Called when a ProximityEvent occurs (change in near/far).       */ -    void onProximityEvent(ProximitySensor.ThresholdSensorEvent proximityEvent) {} +    void onProximityEvent(FalsingManager.ProximityEvent proximityEvent) {}      /**       * The phone screen has turned on and we need to begin falsing detection. diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java index 94e5c8ad1536..0f202b085851 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java @@ -361,7 +361,7 @@ class FalsingCollectorImpl implements FalsingCollector {      private void onProximityEvent(ThresholdSensor.ThresholdSensorEvent proximityEvent) {          // TODO: some of these classifiers might allow us to abort early, meaning we don't have to          // make these calls. -        mFalsingManager.onProximityEvent(proximityEvent); +        mFalsingManager.onProximityEvent(new ProximityEventImpl(proximityEvent));      } @@ -374,4 +374,21 @@ class FalsingCollectorImpl implements FalsingCollector {              Log.d(TAG, msg, throwable);          }      } + +    private static class ProximityEventImpl implements FalsingManager.ProximityEvent { +        private ThresholdSensor.ThresholdSensorEvent mThresholdSensorEvent; + +        ProximityEventImpl(ThresholdSensor.ThresholdSensorEvent thresholdSensorEvent) { +            mThresholdSensorEvent = thresholdSensorEvent; +        } +        @Override +        public boolean getCovered() { +            return mThresholdSensorEvent.getBelow(); +        } + +        @Override +        public long getTimestampNs() { +            return mThresholdSensorEvent.getTimestampNs(); +        } +    }  } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java index e8445d40836e..ee69e277cc46 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java @@ -20,7 +20,6 @@ import android.net.Uri;  import com.android.internal.annotations.VisibleForTesting;  import com.android.systemui.plugins.FalsingManager; -import com.android.systemui.util.sensors.ThresholdSensor;  import java.io.FileDescriptor;  import java.io.PrintWriter; @@ -133,7 +132,7 @@ public class FalsingManagerFake implements FalsingManager {      }      @Override -    public void onProximityEvent(ThresholdSensor.ThresholdSensorEvent proximityEvent) { +    public void onProximityEvent(ProximityEvent proximityEvent) {      } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java index 6b819fbbbcf1..ee0dba0a5087 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java @@ -31,7 +31,6 @@ import com.android.systemui.plugins.FalsingPlugin;  import com.android.systemui.plugins.PluginListener;  import com.android.systemui.shared.plugins.PluginManager;  import com.android.systemui.util.DeviceConfigProxy; -import com.android.systemui.util.sensors.ThresholdSensor;  import java.io.FileDescriptor;  import java.io.PrintWriter; @@ -186,7 +185,7 @@ public class FalsingManagerProxy implements FalsingManager, Dumpable {      }      @Override -    public void onProximityEvent(ThresholdSensor.ThresholdSensorEvent proximityEvent) { +    public void onProximityEvent(ProximityEvent proximityEvent) {          mInternalFalsingManager.onProximityEvent(proximityEvent);      } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java index 72d4303dc0ef..32d9ca59951d 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java @@ -25,8 +25,8 @@ import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;  import android.provider.DeviceConfig;  import android.view.MotionEvent; +import com.android.systemui.plugins.FalsingManager;  import com.android.systemui.util.DeviceConfigProxy; -import com.android.systemui.util.sensors.ProximitySensor;  import java.util.Locale; @@ -107,11 +107,11 @@ class ProximityClassifier extends FalsingClassifier {      @Override      public void onProximityEvent( -            ProximitySensor.ThresholdSensorEvent proximityEvent) { -        boolean near = proximityEvent.getBelow(); +            FalsingManager.ProximityEvent proximityEvent) { +        boolean covered = proximityEvent.getCovered();          long timestampNs = proximityEvent.getTimestampNs(); -        logDebug("Sensor is: " + near + " at time " + timestampNs); -        update(near, timestampNs); +        logDebug("Sensor is: " + covered + " at time " + timestampNs); +        update(covered, timestampNs);      }      @Override diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DefaultBroadcastReceiverBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultBroadcastReceiverBinder.java index 2a7023a58637..0cf3333d12a6 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/DefaultBroadcastReceiverBinder.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultBroadcastReceiverBinder.java @@ -20,6 +20,7 @@ import android.content.BroadcastReceiver;  import com.android.systemui.media.dialog.MediaOutputDialogReceiver;  import com.android.systemui.people.widget.PeopleSpaceWidgetPinnedReceiver; +import com.android.systemui.people.widget.PeopleSpaceWidgetProvider;  import com.android.systemui.screenshot.ActionProxyReceiver;  import com.android.systemui.screenshot.DeleteScreenshotReceiver;  import com.android.systemui.screenshot.SmartActionsReceiver; @@ -79,4 +80,13 @@ public abstract class DefaultBroadcastReceiverBinder {      public abstract BroadcastReceiver bindPeopleSpaceWidgetPinnedReceiver(              PeopleSpaceWidgetPinnedReceiver broadcastReceiver); +    /** +     * +     */ +    @Binds +    @IntoMap +    @ClassKey(PeopleSpaceWidgetProvider.class) +    public abstract BroadcastReceiver bindPeopleSpaceWidgetProvider( +            PeopleSpaceWidgetProvider broadcastReceiver); +  } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java index 8e4e3081aff2..c04201caa182 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java @@ -23,6 +23,7 @@ import com.android.systemui.InitController;  import com.android.systemui.SystemUIAppComponentFactory;  import com.android.systemui.dump.DumpManager;  import com.android.systemui.keyguard.KeyguardSliceProvider; +import com.android.systemui.people.PeopleProvider;  import com.android.systemui.statusbar.policy.ConfigurationController;  import com.android.systemui.util.InjectionInflationController;  import com.android.wm.shell.ShellCommandHandler; @@ -156,4 +157,9 @@ public interface SysUIComponent {       * Member injection into the supplied argument.       */      void inject(ClockOptionsProvider clockOptionsProvider); + +    /** +     * Member injection into the supplied argument. +     */ +    void inject(PeopleProvider peopleProvider);  } diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt index 8d9a4be30ab6..24503675ae36 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt @@ -3,7 +3,6 @@ package com.android.systemui.media  import android.app.smartspace.SmartspaceTarget  import android.content.Context  import android.content.Intent -import android.content.res.ColorStateList  import android.content.res.Configuration  import android.provider.Settings.ACTION_MEDIA_CONTROLS_SETTINGS  import android.util.Log @@ -20,6 +19,7 @@ import com.android.systemui.dagger.qualifiers.Main  import com.android.systemui.plugins.ActivityStarter  import com.android.systemui.plugins.FalsingManager  import com.android.systemui.qs.PageIndicator +import com.android.systemui.shared.system.SysUiStatsLog  import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager  import com.android.systemui.statusbar.policy.ConfigurationController  import com.android.systemui.util.Utils @@ -115,7 +115,6 @@ class MediaCarouselController @Inject constructor(      private var needsReordering: Boolean = false      private var keysNeedRemoval = mutableSetOf<String>()      private var bgColor = getBackgroundColor() -    private var fgColor = getForegroundColor()      private var isRtl: Boolean = false          set(value) {              if (value != field) { @@ -156,6 +155,13 @@ class MediaCarouselController @Inject constructor(          }      } +    var visibleToUser: Boolean = false +        set(value) { +            if (field != value) { +                field = value +            } +        } +      init {          mediaFrame = inflateMediaCarousel()          mediaCarousel = mediaFrame.requireViewById(R.id.media_carousel_scroller) @@ -203,6 +209,9 @@ class MediaCarouselController @Inject constructor(              override fun onSmartspaceMediaDataLoaded(key: String, data: SmartspaceTarget) {                  Log.d(TAG, "My Smartspace media update is here")                  addSmartspaceMediaRecommendations(key, data) +                if (visibleToUser) { +                    logSmartspaceImpression() +                }              }              override fun onMediaDataRemoved(key: String) { @@ -265,10 +274,6 @@ class MediaCarouselController @Inject constructor(      }      private fun addOrUpdatePlayer(key: String, oldKey: String?, data: MediaData) { -        data.actions.forEach { -            it.icon?.setTintList(ColorStateList.valueOf(fgColor)) -        } -        data.appIcon?.setTintList(ColorStateList.valueOf(fgColor))          val dataCopy = data.copy(backgroundColor = bgColor)          val existingPlayer = MediaPlayerData.getMediaPlayer(key, oldKey)          if (existingPlayer == null) { @@ -317,7 +322,7 @@ class MediaCarouselController @Inject constructor(          val lp = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,              ViewGroup.LayoutParams.WRAP_CONTENT)          newRecs.recommendationViewHolder?.recommendations?.setLayoutParams(lp) -        newRecs.bindRecommendation(data, fgColor, bgColor) +        newRecs.bindRecommendation(data, bgColor)          MediaPlayerData.addMediaPlayer(key, newRecs)          updatePlayerToState(newRecs, noAnimation = true)          reorderAllPlayers() @@ -357,8 +362,6 @@ class MediaCarouselController @Inject constructor(      private fun recreatePlayers() {          bgColor = getBackgroundColor() -        fgColor = getForegroundColor() -        pageIndicator.tintList = ColorStateList.valueOf(fgColor)          MediaPlayerData.mediaData().forEach { (key, data) ->              removePlayer(key, dismissMediaData = false) @@ -370,11 +373,6 @@ class MediaCarouselController @Inject constructor(          return context.getColor(android.R.color.system_accent2_50)      } -    private fun getForegroundColor(): Int { -        return com.android.settingslib.Utils.getColorAttr(context, -                com.android.internal.R.attr.textColorPrimary).defaultColor -    } -      private fun updatePageIndicator() {          val numPages = mediaContent.getChildCount()          pageIndicator.setNumPages(numPages) @@ -567,6 +565,29 @@ class MediaCarouselController @Inject constructor(              mediaCarouselScrollHandler.playerWidthPlusPadding = playerWidthPlusPadding          }      } + +    /** +     * Log the user impression for media card. +     */ +    fun logSmartspaceImpression() { +        MediaPlayerData.players().forEach { +            // Log every impression of media recommendation card since it will only be shown +            // for 1 minute after each connection. +            if (it.recommendationViewHolder?.recommendations?.visibility == View.VISIBLE) { +                /* ktlint-disable max-line-length */ +                SysUiStatsLog.write(SysUiStatsLog.SMARTSPACE_CARD_REPORTED, +                        800, // SMARTSPACE_CARD_SEEN +                        it.getInstanceId(), +                        SysUiStatsLog.SMART_SPACE_CARD_REPORTED__CARD_TYPE__HEADPHONE_MEDIA_RECOMMENDATIONS, +                        it.getSurfaceForSmartspaceLogging(), +                        /* rank */ 0, +                        /* cardinality */ 1) +                /* ktlint-disable max-line-length */ +            } + +            // TODO(shijieru): add logging for media control card +        } +    }  }  @VisibleForTesting diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java index c713b229670d..1e9cc8cb08cc 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java +++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java @@ -55,6 +55,7 @@ import com.android.systemui.shared.system.SysUiStatsLog;  import com.android.systemui.statusbar.phone.KeyguardDismissUtil;  import com.android.systemui.util.animation.TransitionLayout; +import java.net.URISyntaxException;  import java.util.List;  import java.util.concurrent.Executor; @@ -69,6 +70,9 @@ public class MediaControlPanel {      private static final String TAG = "MediaControlPanel";      private static final float DISABLED_ALPHA = 0.38f;      private static final String EXTRAS_MEDIA_SOURCE_PACKAGE_NAME = "package_name"; +    private static final String EXTRAS_SMARTSPACE_INTENT = +            "com.google.android.apps.gsa.smartspace.extra.SMARTSPACE_INTENT"; +    private static final String KEY_SMARTSPACE_OPEN_IN_FOREGROUND = "KEY_OPEN_IN_FOREGROUND";      private static final int MEDIA_RECOMMENDATION_ITEMS_PER_ROW = 3;      private static final int MEDIA_RECOMMENDATION_MAX_NUM = 6; @@ -100,6 +104,8 @@ public class MediaControlPanel {      private int mBackgroundColor;      private int mDevicePadding;      private int mAlbumArtSize; +    // Instance id for logging purpose. +    private int mInstanceId;      private final MediaOutputDialogFactory mMediaOutputDialogFactory;      /** @@ -259,9 +265,6 @@ public class MediaControlPanel {          ConstraintSet expandedSet = mMediaViewController.getExpandedLayout();          ConstraintSet collapsedSet = mMediaViewController.getCollapsedLayout(); -        mPlayerViewHolder.getPlayer().setBackgroundTintList( -                ColorStateList.valueOf(mBackgroundColor)); -          // Click action          PendingIntent clickIntent = data.getClickIntent();          if (clickIntent != null) { @@ -459,15 +462,12 @@ public class MediaControlPanel {      /** Bind this recommendation view based on the data given. */      public void bindRecommendation(              @NonNull SmartspaceTarget target, -            @NonNull int primaryColor,              @NonNull int backgroundColor) {          if (mRecommendationViewHolder == null) {              return;          } -        mRecommendationViewHolder.getCardIcon().setColorFilter(primaryColor); -        mRecommendationViewHolder.getCardText().setTextColor(primaryColor); - +        mInstanceId = target.getSmartspaceTargetId().hashCode();          mRecommendationViewHolder.getRecommendations()                  .setBackgroundTintList(ColorStateList.valueOf(backgroundColor));          mBackgroundColor = backgroundColor; @@ -486,8 +486,10 @@ public class MediaControlPanel {          ConstraintSet collapsedSet = mMediaViewController.getCollapsedLayout();          int mediaRecommendationNum = Math.min(mediaRecommendationList.size(),                  MEDIA_RECOMMENDATION_MAX_NUM); -        for (int i = 0; i < mediaRecommendationNum; i++) { -            SmartspaceAction recommendation = mediaRecommendationList.get(i); +        for (int itemIndex = 0, uiComponentIndex = 0; +                itemIndex < mediaRecommendationNum && uiComponentIndex < mediaRecommendationNum; +                itemIndex++) { +            SmartspaceAction recommendation = mediaRecommendationList.get(itemIndex);              if (recommendation.getIcon() == null) {                  Log.w(TAG, "No media cover is provided. Skipping this item...");                  continue; @@ -511,31 +513,38 @@ public class MediaControlPanel {              }              // Set up media source app's logo. -            ImageView mediaSourceLogoImageView = mediaLogoItems.get(i); +            ImageView mediaSourceLogoImageView = mediaLogoItems.get(uiComponentIndex);              mediaSourceLogoImageView.setImageDrawable(icon);              // TODO(b/186699032): Tint the app logo using the accent color.              mediaSourceLogoImageView.setColorFilter(backgroundColor, PorterDuff.Mode.XOR);              // Set up media item cover. -            ImageView mediaCoverImageView = mediaCoverItems.get(i); +            ImageView mediaCoverImageView = mediaCoverItems.get(uiComponentIndex);              mediaCoverImageView.setImageIcon(recommendation.getIcon());              // Set up the click listener if applicable.              setSmartspaceRecItemOnClickListener(                      mediaCoverImageView,                      recommendation, -                    target.getSmartspaceTargetId(),                      null); -            if (i < MEDIA_RECOMMENDATION_ITEMS_PER_ROW) { -                setVisibleAndAlpha(collapsedSet, mediaCoverItemsResIds.get(i), true); -                setVisibleAndAlpha(collapsedSet, mediaLogoItemsResIds.get(i), true); +            if (uiComponentIndex < MEDIA_RECOMMENDATION_ITEMS_PER_ROW) { +                setVisibleAndAlpha(collapsedSet, +                        mediaCoverItemsResIds.get(uiComponentIndex), true); +                setVisibleAndAlpha(collapsedSet, +                        mediaLogoItemsResIds.get(uiComponentIndex), true);              } else { -                setVisibleAndAlpha(collapsedSet, mediaCoverItemsResIds.get(i), false); -                setVisibleAndAlpha(collapsedSet, mediaLogoItemsResIds.get(i), false); +                setVisibleAndAlpha(collapsedSet, +                        mediaCoverItemsResIds.get(uiComponentIndex), false); +                setVisibleAndAlpha(collapsedSet, +                        mediaLogoItemsResIds.get(uiComponentIndex), false);              } -            setVisibleAndAlpha(expandedSet, mediaCoverItemsResIds.get(i), true); -            setVisibleAndAlpha(expandedSet, mediaLogoItemsResIds.get(i), true); +            setVisibleAndAlpha(expandedSet, +                    mediaCoverItemsResIds.get(uiComponentIndex), true); +            setVisibleAndAlpha(expandedSet, +                    mediaLogoItemsResIds.get(uiComponentIndex), true); + +            uiComponentIndex++;          }          // Set up long press to show guts setting panel. @@ -635,7 +644,6 @@ public class MediaControlPanel {      private void setSmartspaceRecItemOnClickListener(              @NonNull View view,              @NonNull SmartspaceAction action, -            @NonNull String targetId,              @Nullable View.OnClickListener callback) {          if (view == null || action == null || action.getIntent() == null) {              Log.e(TAG, "No tap action can be set up"); @@ -646,24 +654,60 @@ public class MediaControlPanel {              // When media recommendation card is shown, there could be only one card.              SysUiStatsLog.write(SysUiStatsLog.SMARTSPACE_CARD_REPORTED,                      760, // SMARTSPACE_CARD_CLICK -                    targetId.hashCode(), +                    mInstanceId,                      SysUiStatsLog                              .SMART_SPACE_CARD_REPORTED__CARD_TYPE__HEADPHONE_MEDIA_RECOMMENDATIONS, -                    getSurfaceForSmartspaceLogging(mMediaViewController.getCurrentEndLocation()), -                    /* rank */ 1, +                    getSurfaceForSmartspaceLogging(), +                    /* rank */ 0,                      /* cardinality */ 1); -            mActivityStarter.postStartActivityDismissingKeyguard( -                    action.getIntent(), -                    0 /* delay */, -                    buildLaunchAnimatorController(mRecommendationViewHolder.getRecommendations())); +            if (shouldSmartspaceRecItemOpenInForeground(action)) { +                // Request to unlock the device if the activity needs to be opened in foreground. +                mActivityStarter.postStartActivityDismissingKeyguard( +                        action.getIntent(), +                        0 /* delay */, +                        buildLaunchAnimatorController( +                                mRecommendationViewHolder.getRecommendations())); +            } else { +                // Otherwise, open the activity in background directly. +                view.getContext().startActivity(action.getIntent()); +            } +              if (callback != null) {                  callback.onClick(v);              }          });      } -    private int getSurfaceForSmartspaceLogging(int currentEndLocation) { +    /** Returns if the Smartspace action will open the activity in foreground. */ +    private boolean shouldSmartspaceRecItemOpenInForeground(SmartspaceAction action) { +        if (action == null || action.getIntent() == null +                || action.getIntent().getExtras() == null) { +            return false; +        } + +        String intentString = action.getIntent().getExtras().getString(EXTRAS_SMARTSPACE_INTENT); +        if (intentString == null) { +            return false; +        } + +        try { +            Intent wrapperIntent = Intent.parseUri(intentString, Intent.URI_INTENT_SCHEME); +            return wrapperIntent.getBooleanExtra(KEY_SMARTSPACE_OPEN_IN_FOREGROUND, false); +        } catch (URISyntaxException e) { +            Log.wtf(TAG, "Failed to create intent from URI: " + intentString); +            e.printStackTrace(); +        } + +        return false; +    } + +    /** +     * Get the surface given the current end location for MediaViewController +     * @return surface used for Smartspace logging +     */ +    protected int getSurfaceForSmartspaceLogging() { +        int currentEndLocation = mMediaViewController.getCurrentEndLocation();          if (currentEndLocation == MediaHierarchyManager.LOCATION_QQS                  || currentEndLocation == MediaHierarchyManager.LOCATION_QS) {              return SysUiStatsLog.SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__SHADE; @@ -672,4 +716,8 @@ public class MediaControlPanel {          }          return SysUiStatsLog.SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__DEFAULT_SURFACE;      } + +    protected int getInstanceId() { +        return mInstanceId; +    }  } diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt index 30bc8c1733bc..a80a410d32db 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt @@ -38,6 +38,7 @@ import com.android.systemui.statusbar.phone.KeyguardBypassController  import com.android.systemui.statusbar.policy.KeyguardStateController  import com.android.systemui.util.animation.UniqueObjectHostView  import javax.inject.Inject +import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager  /**   * Similarly to isShown but also excludes views that have 0 alpha @@ -73,7 +74,8 @@ class MediaHierarchyManager @Inject constructor(      private val bypassController: KeyguardBypassController,      private val mediaCarouselController: MediaCarouselController,      private val notifLockscreenUserManager: NotificationLockscreenUserManager, -    wakefulnessLifecycle: WakefulnessLifecycle +    wakefulnessLifecycle: WakefulnessLifecycle, +    private val statusBarKeyguardViewManager: StatusBarKeyguardViewManager  ) {      /**       * The root overlay of the hierarchy. This is where the media notification is attached to @@ -162,6 +164,26 @@ class MediaHierarchyManager @Inject constructor(          }      /** +     * Is quick setting expanded? +     */ +    var qsExpanded: Boolean = false +        set(value) { +            if (field != value) { +                field = value +            } +            // Pull down shade from lock screen (exclude the case when shade is brought out by +            // tapping twice on lock screen) +            if (value && isLockScreenShadeVisibleToUser()) { +                mediaCarouselController.logSmartspaceImpression() +            } +            // Release shade and back to lock screen +            if (isLockScreenVisibleToUser()) { +                mediaCarouselController.logSmartspaceImpression() +            } +            mediaCarouselController.visibleToUser = isVisibleToUser() +        } + +    /**       * Is the shade currently collapsing from the expanded qs? If we're on the lockscreen and in qs,       * we wouldn't want to transition in that case.       */ @@ -231,6 +253,11 @@ class MediaHierarchyManager @Inject constructor(              override fun onStateChanged(newState: Int) {                  updateTargetState() +                // Enters shade from lock screen +                if (newState == StatusBarState.SHADE_LOCKED && isLockScreenShadeVisibleToUser()) { +                    mediaCarouselController.logSmartspaceImpression() +                } +                mediaCarouselController.visibleToUser = isVisibleToUser()              }              override fun onDozeAmountChanged(linear: Float, eased: Float) { @@ -240,9 +267,27 @@ class MediaHierarchyManager @Inject constructor(              override fun onDozingChanged(isDozing: Boolean) {                  if (!isDozing) {                      dozeAnimationRunning = false +                    // Enters lock screen from screen off +                    if (isLockScreenVisibleToUser()) { +                        mediaCarouselController.logSmartspaceImpression() +                    }                  } else {                      updateDesiredLocation() +                    qsExpanded = false                  } +                mediaCarouselController.visibleToUser = isVisibleToUser() +            } + +            override fun onExpandedChanged(isExpanded: Boolean) { +                // Enters shade from home screen +                if (isHomeScreenShadeVisibleToUser()) { +                    mediaCarouselController.logSmartspaceImpression() +                } +                // Back to lock screen from bouncer +                if (isLockScreenVisibleToUser()) { +                    mediaCarouselController.logSmartspaceImpression() +                } +                mediaCarouselController.visibleToUser = isVisibleToUser()              }          }) @@ -622,6 +667,36 @@ class MediaHierarchyManager @Inject constructor(          return location      } +    /** +     * Returns true when the media card could be visible to the user if existed. +     */ +    private fun isVisibleToUser(): Boolean { +        return isLockScreenVisibleToUser() || isLockScreenShadeVisibleToUser() || +                isHomeScreenShadeVisibleToUser() +    } + +    private fun isLockScreenVisibleToUser(): Boolean { +        return !statusBarStateController.isDozing && +                !statusBarKeyguardViewManager.isBouncerShowing && +                statusBarStateController.state == StatusBarState.KEYGUARD && +                notifLockscreenUserManager.shouldShowLockscreenNotifications() && +                statusBarStateController.isExpanded && +                !qsExpanded +    } + +    private fun isLockScreenShadeVisibleToUser(): Boolean { +        return !statusBarStateController.isDozing && +                !statusBarKeyguardViewManager.isBouncerShowing && +                (statusBarStateController.state == StatusBarState.SHADE_LOCKED || +                        (statusBarStateController.state == StatusBarState.KEYGUARD && qsExpanded)) +    } + +    private fun isHomeScreenShadeVisibleToUser(): Boolean { +        return !statusBarStateController.isDozing && +                statusBarStateController.state == StatusBarState.SHADE && +                statusBarStateController.isExpanded +    } +      companion object {          /**           * Attached in expanded quick settings diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java index 4e41d75e3f43..56375adb3d4e 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java @@ -101,7 +101,6 @@ import android.view.WindowManager;  import android.view.accessibility.AccessibilityEvent;  import android.view.accessibility.AccessibilityManager;  import android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener; -import android.view.inputmethod.InputMethodManager;  import androidx.annotation.VisibleForTesting; @@ -1176,9 +1175,6 @@ public class NavigationBar implements View.OnAttachStateChangeListener,          accessibilityButton.setOnLongClickListener(this::onAccessibilityLongClick);          updateAccessibilityServicesState(mAccessibilityManager); -        ButtonDispatcher imeSwitcherButton = mNavigationBarView.getImeSwitchButton(); -        imeSwitcherButton.setOnClickListener(this::onImeSwitcherClick); -          updateScreenPinningGestures();      } @@ -1278,11 +1274,6 @@ public class NavigationBar implements View.OnAttachStateChangeListener,          mCommandQueue.toggleRecentApps();      } -    private void onImeSwitcherClick(View v) { -        mContext.getSystemService(InputMethodManager.class).showInputMethodPickerFromSystem( -                true /* showAuxiliarySubtypes */, mDisplayId); -    }; -      private boolean onLongPressBackHome(View v) {          return onLongPressNavigationButtons(v, R.id.back, R.id.home);      } @@ -1291,6 +1282,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,          return onLongPressNavigationButtons(v, R.id.back, R.id.recent_apps);      } +      /**       * This handles long-press of both back and recents/home. Back is the common button with       * combination of recents if it is visible or home if recents is invisible. diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java index 66cfae4315d8..3544f60601a8 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java @@ -217,9 +217,6 @@ public class NavigationBarController implements Callbacks,      @Override      public void onNavigationModeChanged(int mode) { -        if (mNavMode == mode) { -            return; -        }          final int oldMode = mNavMode;          mNavMode = mode;          mHandler.post(() -> { diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarInflaterView.java index 4d9175b8db68..7342f91a8108 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarInflaterView.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarInflaterView.java @@ -158,6 +158,7 @@ public class NavigationBarInflaterView extends FrameLayout      }      public void onLikelyDefaultLayoutChange() { +          // Reevaluate new layout          final String newValue = getDefaultLayout();          if (!Objects.equals(mCurrentLayout, newValue)) { diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java index bdd273515619..0ed4d861c712 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java @@ -166,7 +166,6 @@ public class NavigationBarView extends FrameLayout implements      private NavigationBarInflaterView mNavigationInflaterView;      private RecentsOnboarding mRecentsOnboarding;      private NotificationPanelViewController mPanelView; -    private RotationContextButton mRotationContextButton;      private FloatingRotationButton mFloatingRotationButton;      private RotationButtonController mRotationButtonController;      private NavigationBarOverlayController mNavBarOverlayController; @@ -234,6 +233,14 @@ public class NavigationBarView extends FrameLayout implements          }      } +    private final OnClickListener mImeSwitcherClickListener = new OnClickListener() { +        @Override +        public void onClick(View view) { +            mContext.getSystemService(InputMethodManager.class).showInputMethodPickerFromSystem( +                    true /* showAuxiliarySubtypes */, getContext().getDisplayId()); +        } +    }; +      private final AccessibilityDelegate mQuickStepAccessibilityDelegate =              new AccessibilityDelegate() {                  private AccessibilityAction mToggleOverviewAction; @@ -304,26 +311,32 @@ public class NavigationBarView extends FrameLayout implements          mIsVertical = false;          mLongClickableAccessibilityButton = false;          mNavBarMode = Dependency.get(NavigationModeController.class).addListener(this); +        boolean isGesturalMode = isGesturalMode(mNavBarMode);          mSysUiFlagContainer = Dependency.get(SysUiState.class);          // Set up the context group of buttons          mContextualButtonGroup = new ContextualButtonGroup(R.id.menu_container);          final ContextualButton imeSwitcherButton = new ContextualButton(R.id.ime_switcher,                  mLightContext, R.drawable.ic_ime_switcher_default); +        final RotationContextButton rotateSuggestionButton = new RotationContextButton( +                R.id.rotate_suggestion, mLightContext, +                R.drawable.ic_sysbar_rotate_button_ccw_start_0);          final ContextualButton accessibilityButton =                  new ContextualButton(R.id.accessibility_button, mLightContext,                          R.drawable.ic_sysbar_accessibility_button);          mContextualButtonGroup.addButton(imeSwitcherButton); +        if (!isGesturalMode) { +            mContextualButtonGroup.addButton(rotateSuggestionButton); +        }          mContextualButtonGroup.addButton(accessibilityButton);          mOverviewProxyService = Dependency.get(OverviewProxyService.class); -        mRotationContextButton = new RotationContextButton(R.id.rotate_suggestion, -                mLightContext, R.drawable.ic_sysbar_rotate_button_ccw_start_0);          mFloatingRotationButton = new FloatingRotationButton(context);          mRecentsOnboarding = new RecentsOnboarding(context, mOverviewProxyService);          mRotationButtonController = new RotationButtonController(mLightContext, -                mLightIconColor, mDarkIconColor); -        updateRotationButton(); +                mLightIconColor, mDarkIconColor, +                isGesturalMode ? mFloatingRotationButton : rotateSuggestionButton, +                mRotationButtonListener);          mNavBarOverlayController = Dependency.get(NavigationBarOverlayController.class);          if (mNavBarOverlayController.isNavigationBarOverlayEnabled()) { @@ -344,6 +357,7 @@ public class NavigationBarView extends FrameLayout implements          mButtonDispatchers.put(R.id.recent_apps, new ButtonDispatcher(R.id.recent_apps));          mButtonDispatchers.put(R.id.ime_switcher, imeSwitcherButton);          mButtonDispatchers.put(R.id.accessibility_button, accessibilityButton); +        mButtonDispatchers.put(R.id.rotate_suggestion, rotateSuggestionButton);          mButtonDispatchers.put(R.id.menu_container, mContextualButtonGroup);          mDeadZone = new DeadZone(this); @@ -541,23 +555,6 @@ public class NavigationBarView extends FrameLayout implements          }      } -    /** -     * Updates the rotation button based on the current navigation mode. -     */ -    private void updateRotationButton() { -        if (isGesturalMode(mNavBarMode)) { -            mContextualButtonGroup.removeButton(R.id.rotate_suggestion); -            mButtonDispatchers.remove(R.id.rotate_suggestion); -            mRotationButtonController.setRotationButton(mFloatingRotationButton, -                    mRotationButtonListener); -        } else if (mContextualButtonGroup.getContextButton(R.id.rotate_suggestion) == null) { -            mContextualButtonGroup.addButton(mRotationContextButton); -            mButtonDispatchers.put(R.id.rotate_suggestion, mRotationContextButton); -            mRotationButtonController.setRotationButton(mRotationContextButton, -                    mRotationButtonListener); -        } -    } -      public KeyButtonDrawable getBackDrawable() {          KeyButtonDrawable drawable = getDrawable(getBackDrawableRes());          orientBackButton(drawable); @@ -911,7 +908,6 @@ public class NavigationBarView extends FrameLayout implements          mBarTransitions.onNavigationModeChanged(mNavBarMode);          mEdgeBackGestureHandler.onNavigationModeChanged(mNavBarMode);          mRecentsOnboarding.onNavigationModeChanged(mNavBarMode); -        updateRotationButton();          if (isGesturalMode(mNavBarMode)) {              mRegionSamplingHelper.start(mSamplingBounds); @@ -936,6 +932,7 @@ public class NavigationBarView extends FrameLayout implements          mNavigationInflaterView = findViewById(R.id.navigation_inflater);          mNavigationInflaterView.setButtonDispatchers(mButtonDispatchers); +        getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);          updateOrientationViews();          reloadNavIcons();      } @@ -1030,9 +1027,6 @@ public class NavigationBarView extends FrameLayout implements      private void updateButtonLocation(ButtonDispatcher button, boolean inScreenSpace,              boolean useNearestRegion) { -        if (button == null) { -            return; -        }          View view = button.getCurrentView();          if (view == null || !button.isVisible()) {              return; diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java index ddf089bac25e..4bcb0193c7d0 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java @@ -66,10 +66,10 @@ public class RotationButtonController {      private static final int NUM_ACCEPTED_ROTATION_SUGGESTIONS_FOR_INTRODUCTION = 3;      private final Context mContext; +    private final RotationButton mRotationButton;      private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());      private final UiEventLogger mUiEventLogger = new UiEventLoggerImpl();      private final ViewRippler mViewRippler = new ViewRippler(); -    private RotationButton mRotationButton;      private int mLastRotationSuggestion;      private boolean mPendingRotationSuggestion; @@ -125,21 +125,20 @@ public class RotationButtonController {      }      RotationButtonController(Context context, @ColorInt int lightIconColor, -            @ColorInt int darkIconColor) { +            @ColorInt int darkIconColor, RotationButton rotationButton, +            Consumer<Boolean> visibilityChangedCallback) {          mContext = context;          mLightIconColor = lightIconColor;          mDarkIconColor = darkIconColor; +        mRotationButton = rotationButton; +        mRotationButton.setRotationButtonController(this);          mIsNavigationBarShowing = true;          mRotationLockController = Dependency.get(RotationLockController.class);          mAccessibilityManagerWrapper = Dependency.get(AccessibilityManagerWrapper.class); -        mTaskStackListener = new TaskStackListenerImpl(); -    } -    void setRotationButton(RotationButton rotationButton, -            Consumer<Boolean> visibilityChangedCallback) { -        mRotationButton = rotationButton; -        mRotationButton.setRotationButtonController(this); +        // Register the task stack listener +        mTaskStackListener = new TaskStackListenerImpl();          mRotationButton.setOnClickListener(this::onRotateSuggestionClick);          mRotationButton.setOnHoverListener(this::onRotateSuggestionHover);          mRotationButton.setVisibilityChangedCallback(visibilityChangedCallback); diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ContextualButtonGroup.java b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ContextualButtonGroup.java index 2ace303986fe..50b638bcc903 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ContextualButtonGroup.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ContextualButtonGroup.java @@ -41,23 +41,10 @@ public class ContextualButtonGroup extends ButtonDispatcher {       * @param button the button added to the group       */      public void addButton(@NonNull ContextualButton button) { -        // By default buttons in the context group are not visible until -        // {@link #setButtonVisibility()) is called to show one of the buttons -        button.setVisibility(View.INVISIBLE);          button.attachToGroup(this);          mButtonData.add(new ButtonData(button));      } -    /** -     * Removes a contextual button from the group. -     */ -    public void removeButton(@IdRes int buttonResId) { -        int index = getContextButtonIndex(buttonResId); -        if (index != INVALID_INDEX) { -            mButtonData.remove(index); -        } -    } -      public ContextualButton getContextButton(@IdRes int buttonResId) {          int index = getContextButtonIndex(buttonResId);          if (index != INVALID_INDEX) { diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleProvider.java b/packages/SystemUI/src/com/android/systemui/people/PeopleProvider.java index a9640566d531..0f6645641dda 100644 --- a/packages/SystemUI/src/com/android/systemui/people/PeopleProvider.java +++ b/packages/SystemUI/src/com/android/systemui/people/PeopleProvider.java @@ -30,12 +30,15 @@ import android.widget.RemoteViews;  import com.android.systemui.people.widget.PeopleSpaceWidgetManager;  import com.android.systemui.shared.system.PeopleProviderUtils; +import javax.inject.Inject; +  /** API that returns a People Tile preview. */  public class PeopleProvider extends ContentProvider {      private static final String TAG = "PeopleProvider";      private static final boolean DEBUG = PeopleSpaceUtils.DEBUG;      private static final String EMPTY_STRING = ""; +    @Inject      PeopleSpaceWidgetManager mPeopleSpaceWidgetManager;      @Override @@ -76,7 +79,8 @@ public class PeopleProvider extends ContentProvider {          }          if (mPeopleSpaceWidgetManager == null) { -            mPeopleSpaceWidgetManager = new PeopleSpaceWidgetManager(getContext()); +            Log.e(TAG, "Could not initialize people widget manager"); +            return null;          }          RemoteViews view =                  mPeopleSpaceWidgetManager.getPreview(shortcutId, userHandle, packageName, extras); diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java index 99a17ffbe77a..a6c6103ae4c5 100644 --- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java +++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java @@ -23,11 +23,11 @@ import static com.android.systemui.people.NotificationHelper.hasReadContactsPerm  import static com.android.systemui.people.NotificationHelper.isMissedCall;  import static com.android.systemui.people.NotificationHelper.shouldMatchNotificationByUri; +import android.annotation.Nullable;  import android.app.Notification;  import android.app.people.ConversationChannel;  import android.app.people.IPeopleManager;  import android.app.people.PeopleSpaceTile; -import android.appwidget.AppWidgetManager;  import android.content.Context;  import android.content.SharedPreferences;  import android.content.pm.LauncherApps; @@ -40,13 +40,11 @@ import android.graphics.Canvas;  import android.graphics.drawable.BitmapDrawable;  import android.graphics.drawable.Drawable;  import android.net.Uri; -import android.os.Bundle;  import android.os.UserManager;  import android.provider.ContactsContract;  import android.service.notification.StatusBarNotification;  import android.text.TextUtils;  import android.util.Log; -import android.widget.RemoteViews;  import androidx.preference.PreferenceManager; @@ -56,7 +54,7 @@ import com.android.internal.logging.UiEventLogger;  import com.android.internal.util.ArrayUtils;  import com.android.settingslib.utils.ThreadUtils;  import com.android.systemui.R; -import com.android.systemui.people.widget.AppWidgetOptionsHelper; +import com.android.systemui.people.widget.PeopleSpaceWidgetManager;  import com.android.systemui.people.widget.PeopleTileKey;  import com.android.systemui.statusbar.notification.collection.NotificationEntry; @@ -76,45 +74,17 @@ import java.util.stream.Stream;  public class PeopleSpaceUtils {      /** Turns on debugging information about People Space. */      public static final boolean DEBUG = true; -    private static final String TAG = "PeopleSpaceUtils";      public static final String PACKAGE_NAME = "package_name";      public static final String USER_ID = "user_id";      public static final String SHORTCUT_ID = "shortcut_id"; -      public static final String EMPTY_STRING = "";      public static final int INVALID_USER_ID = -1; -      public static final PeopleTileKey EMPTY_KEY =              new PeopleTileKey(EMPTY_STRING, INVALID_USER_ID, EMPTY_STRING); - -    /** Represents whether {@link StatusBarNotification} was posted or removed. */ -    public enum NotificationAction { -        POSTED, -        REMOVED -    } - -    /** -     * The UiEvent enums that this class can log. -     */ -    public enum PeopleSpaceWidgetEvent implements UiEventLogger.UiEventEnum { -        @UiEvent(doc = "People space widget deleted") -        PEOPLE_SPACE_WIDGET_DELETED(666), -        @UiEvent(doc = "People space widget added") -        PEOPLE_SPACE_WIDGET_ADDED(667), -        @UiEvent(doc = "People space widget clicked to launch conversation") -        PEOPLE_SPACE_WIDGET_CLICKED(668); - -        private final int mId; - -        PeopleSpaceWidgetEvent(int id) { -            mId = id; -        } - -        @Override -        public int getId() { -            return mId; -        } -    } +    static final float STARRED_CONTACT = 1f; +    static final float VALID_CONTACT = .5f; +    static final float DEFAULT_AFFINITY = 0f; +    private static final String TAG = "PeopleSpaceUtils";      /** Returns stored widgets for the conversation specified. */      public static Set<String> getStoredWidgetIds(SharedPreferences sp, PeopleTileKey key) { @@ -127,6 +97,10 @@ public class PeopleSpaceUtils {      /** Sets all relevant storage for {@code appWidgetId} association to {@code tile}. */      public static void setSharedPreferencesStorageForTile(Context context, PeopleTileKey key,              int appWidgetId, Uri contactUri) { +        if (!key.isValid()) { +            Log.e(TAG, "Not storing for invalid key"); +            return; +        }          // Write relevant persisted storage.          SharedPreferences widgetSp = context.getSharedPreferences(String.valueOf(appWidgetId),                  Context.MODE_PRIVATE); @@ -201,7 +175,7 @@ public class PeopleSpaceUtils {                  .collect(Collectors.toList());      } -    /** Returns the total messages in {@code notificationEntries}.*/ +    /** Returns the total messages in {@code notificationEntries}. */      public static int getMessagesCount(Set<NotificationEntry> notificationEntries) {          if (DEBUG) {              Log.d(TAG, "Calculating messages count from " + notificationEntries.size() @@ -247,19 +221,34 @@ public class PeopleSpaceUtils {       * {@code messagesCount}.       */      public static PeopleSpaceTile augmentTileFromNotification(Context context, PeopleSpaceTile tile, -            PeopleTileKey key, NotificationEntry notificationEntry, int messagesCount) { +            PeopleTileKey key, NotificationEntry notificationEntry, int messagesCount, +            Optional<Integer> appWidgetId) {          if (notificationEntry == null || notificationEntry.getSbn().getNotification() == null) {              if (DEBUG) Log.d(TAG, "Tile key: " + key.toString() + ". Notification is null");              return removeNotificationFields(tile);          }          Notification notification = notificationEntry.getSbn().getNotification(); + +        PeopleSpaceTile.Builder updatedTile = tile.toBuilder(); +        String uriFromNotification = getContactUri(notificationEntry.getSbn()); +        if (appWidgetId.isPresent() && tile.getContactUri() == null && !TextUtils.isEmpty( +                uriFromNotification)) { +            if (DEBUG) Log.d(TAG, "Add uri from notification to tile: " + uriFromNotification); +            Uri contactUri = Uri.parse(uriFromNotification); +            // Update storage. +            setSharedPreferencesStorageForTile(context, new PeopleTileKey(tile), appWidgetId.get(), +                    contactUri); +            // Update cached tile in-memory. +            updatedTile.setContactUri(contactUri); +        } +          boolean isMissedCall = isMissedCall(notification);          List<Notification.MessagingStyle.Message> messages =                  getMessagingStyleMessages(notification);          if (!isMissedCall && ArrayUtils.isEmpty(messages)) {              if (DEBUG) Log.d(TAG, "Tile key: " + key.toString() + ". Notification has no content"); -            return removeNotificationFields(tile); +            return removeNotificationFields(updatedTile.build());          }          // messages are in chronological order from most recent to least. @@ -276,8 +265,7 @@ public class PeopleSpaceUtils {          }          CharSequence sender = getSenderIfGroupConversation(notification, message); -        return tile -                .toBuilder() +        return updatedTile                  .setNotificationKey(notificationEntry.getSbn().getKey())                  .setNotificationCategory(notification.category)                  .setNotificationContent(content) @@ -378,17 +366,18 @@ public class PeopleSpaceUtils {                  context.getString(R.string.birthday_status));      } -    /** Calls to retrieve birthdays on a background thread. */ -    public static void getBirthdaysOnBackgroundThread(Context context, -            AppWidgetManager appWidgetManager, +    /** Calls to retrieve birthdays & contact affinity on a background thread. */ +    public static void getDataFromContactsOnBackgroundThread(Context context, +            PeopleSpaceWidgetManager manager,              Map<Integer, PeopleSpaceTile> peopleSpaceTiles, int[] appWidgetIds) {          ThreadUtils.postOnBackgroundThread( -                () -> getBirthdays(context, appWidgetManager, peopleSpaceTiles, appWidgetIds)); +                () -> getDataFromContacts(context, manager, peopleSpaceTiles, appWidgetIds));      } -    /** Queries the Contacts DB for any birthdays today. */ +    /** Queries the Contacts DB for any birthdays today & updates contact affinity. */      @VisibleForTesting -    public static void getBirthdays(Context context, AppWidgetManager appWidgetManager, +    public static void getDataFromContacts(Context context, +            PeopleSpaceWidgetManager peopleSpaceWidgetManager,              Map<Integer, PeopleSpaceTile> widgetIdToTile, int[] appWidgetIds) {          if (DEBUG) Log.d(TAG, "Get birthdays");          if (appWidgetIds.length == 0) return; @@ -397,28 +386,37 @@ public class PeopleSpaceUtils {              PeopleSpaceTile storedTile = widgetIdToTile.get(appWidgetId);              if (storedTile == null || storedTile.getContactUri() == null) {                  if (DEBUG) Log.d(TAG, "No contact uri for: " + storedTile); -                removeBirthdayStatusIfPresent(appWidgetManager, context, storedTile, appWidgetId); -                continue; -            } -            if (lookupKeysWithBirthdaysToday.isEmpty()) { -                if (DEBUG) Log.d(TAG, "No birthdays today"); -                removeBirthdayStatusIfPresent(appWidgetManager, context, storedTile, appWidgetId); +                updateTileContactFields(peopleSpaceWidgetManager, context, storedTile, +                        appWidgetId, DEFAULT_AFFINITY, /* birthdayString= */ null);                  continue;              } -            updateTileWithBirthday(context, appWidgetManager, lookupKeysWithBirthdaysToday, +            updateTileWithBirthdayAndUpdateAffinity(context, peopleSpaceWidgetManager, +                    lookupKeysWithBirthdaysToday,                      storedTile,                      appWidgetId);          }      } -    /** Removes the birthday status if present in {@code storedTile} and pushes the update. */ -    private static void removeBirthdayStatusIfPresent(AppWidgetManager appWidgetManager, -            Context context, PeopleSpaceTile storedTile, int appWidgetId) { -        if (hasBirthdayStatus(storedTile, context)) { -            if (DEBUG) Log.d(TAG, "Remove " + storedTile.getUserName() + "'s birthday"); -            updateAppWidgetOptionsAndView(appWidgetManager, context, appWidgetId, +    /** +     * Updates the {@code storedTile} with {@code affinity} & {@code birthdayString} if +     * necessary. +     */ +    private static void updateTileContactFields(PeopleSpaceWidgetManager manager, +            Context context, PeopleSpaceTile storedTile, int appWidgetId, float affinity, +            @Nullable String birthdayString) { +        boolean outdatedBirthdayStatus = hasBirthdayStatus(storedTile, context) +                && birthdayString == null; +        boolean addBirthdayStatus = !hasBirthdayStatus(storedTile, context) +                && birthdayString != null; +        boolean shouldUpdate = +                storedTile.getContactAffinity() != affinity || outdatedBirthdayStatus +                        || addBirthdayStatus; +        if (shouldUpdate) { +            if (DEBUG) Log.d(TAG, "Update " + storedTile.getUserName() + " from contacts"); +            manager.updateAppWidgetOptionsAndView(appWidgetId,                      storedTile.toBuilder() -                            .setBirthdayText(null) +                            .setBirthdayText(birthdayString) +                            .setContactAffinity(affinity)                              .build());          }      } @@ -427,7 +425,8 @@ public class PeopleSpaceUtils {       * Update {@code storedTile} if the contact has a lookup key matched to any {@code       * lookupKeysWithBirthdays}.       */ -    private static void updateTileWithBirthday(Context context, AppWidgetManager appWidgetManager, +    private static void updateTileWithBirthdayAndUpdateAffinity(Context context, +            PeopleSpaceWidgetManager manager,              List<String> lookupKeysWithBirthdaysToday, PeopleSpaceTile storedTile,              int appWidgetId) {          Cursor cursor = null; @@ -437,14 +436,16 @@ public class PeopleSpaceUtils {              while (cursor != null && cursor.moveToNext()) {                  String storedLookupKey = cursor.getString(                          cursor.getColumnIndex(ContactsContract.CommonDataKinds.Event.LOOKUP_KEY)); +                float affinity = getContactAffinity(cursor);                  if (!storedLookupKey.isEmpty() && lookupKeysWithBirthdaysToday.contains(                          storedLookupKey)) {                      if (DEBUG) Log.d(TAG, storedTile.getUserName() + "'s birthday today!"); -                    updateAppWidgetOptionsAndView(appWidgetManager, context, appWidgetId, -                            storedTile.toBuilder() -                                    .setBirthdayText(context.getString(R.string.birthday_status)) -                                    .build()); -                    return; +                    updateTileContactFields(manager, context, storedTile, appWidgetId, +                            affinity, /* birthdayString= */ +                            context.getString(R.string.birthday_status)); +                } else { +                    updateTileContactFields(manager, context, storedTile, appWidgetId, +                            affinity, /* birthdayString= */ null);                  }              }          } catch (SQLException e) { @@ -454,51 +455,20 @@ public class PeopleSpaceUtils {                  cursor.close();              }          } -        removeBirthdayStatusIfPresent(appWidgetManager, context, storedTile, appWidgetId); -    } - -    /** Updates the current widget view with provided {@link PeopleSpaceTile}. */ -    public static void updateAppWidgetViews(AppWidgetManager appWidgetManager, -            Context context, int appWidgetId, PeopleSpaceTile tile, Bundle options) { -        if (tile == null) { -            if (DEBUG) Log.d(TAG, "Widget: " + appWidgetId + ". Tile is null, skipping update"); -            return; -        } -        if (DEBUG) { -            Log.d(TAG, "Widget: " + appWidgetId + ", " + tile.getUserName() + ", " -                    + tile.getPackageName() + ". Updating app widget view."); -        } -        RemoteViews views = new PeopleTileViewHelper(context, tile, appWidgetId, -                options).getViews(); - -        // Tell the AppWidgetManager to perform an update on the current app widget. -        appWidgetManager.updateAppWidget(appWidgetId, views); -    } - -    /** Updates tile in app widget options and the current view. */ -    public static void updateAppWidgetOptionsAndView(AppWidgetManager appWidgetManager, -            Context context, int appWidgetId, PeopleSpaceTile tile) { -        if (tile == null) { -            if (DEBUG) { -                Log.w(TAG, "Widget: " + appWidgetId + "Tile is null, skipping storage and update."); -            } -            return; -        } -        Bundle options = AppWidgetOptionsHelper.setPeopleTile(appWidgetManager, appWidgetId, tile); -        updateAppWidgetViews(appWidgetManager, context, appWidgetId, tile, options);      } -    /** Wrapper around {@link #updateAppWidgetOptionsAndView} with optional tile as a parameter. */ -    public static void updateAppWidgetOptionsAndView(AppWidgetManager appWidgetManager, -            Context context, int appWidgetId, Optional<PeopleSpaceTile> optionalTile) { -        if (!optionalTile.isPresent()) { -            if (DEBUG) { -                Log.w(TAG, "Widget: " + appWidgetId -                        + "Optional tile is not present, skipping storage and update."); +    /** Pulls the contact affinity from {@code cursor}. */ +    private static float getContactAffinity(Cursor cursor) { +        float affinity = VALID_CONTACT; +        int starIdx = cursor.getColumnIndex(ContactsContract.Contacts.STARRED); +        if (starIdx >= 0) { +            boolean isStarred = cursor.getInt(starIdx) != 0; +            if (isStarred) { +                affinity = Math.max(affinity, STARRED_CONTACT);              } -            return;          } -        updateAppWidgetOptionsAndView(appWidgetManager, context, appWidgetId, optionalTile.get()); +        if (DEBUG) Log.d(TAG, "Affinity is: " + affinity); +        return affinity;      }      /** @@ -546,4 +516,33 @@ public class PeopleSpaceUtils {      public static int getUserId(PeopleSpaceTile tile) {          return tile.getUserHandle().getIdentifier();      } + +    /** Represents whether {@link StatusBarNotification} was posted or removed. */ +    public enum NotificationAction { +        POSTED, +        REMOVED +    } + +    /** +     * The UiEvent enums that this class can log. +     */ +    public enum PeopleSpaceWidgetEvent implements UiEventLogger.UiEventEnum { +        @UiEvent(doc = "People space widget deleted") +        PEOPLE_SPACE_WIDGET_DELETED(666), +        @UiEvent(doc = "People space widget added") +        PEOPLE_SPACE_WIDGET_ADDED(667), +        @UiEvent(doc = "People space widget clicked to launch conversation") +        PEOPLE_SPACE_WIDGET_CLICKED(668); + +        private final int mId; + +        PeopleSpaceWidgetEvent(int id) { +            mId = id; +        } + +        @Override +        public int getId() { +            return mId; +        } +    }  }
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java b/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java index a23db63a70fc..6980d723583b 100644 --- a/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java +++ b/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java @@ -30,6 +30,8 @@ import static android.appwidget.AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH;  import static android.appwidget.AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT;  import static android.appwidget.AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH; +import static com.android.systemui.people.PeopleSpaceUtils.STARRED_CONTACT; +import static com.android.systemui.people.PeopleSpaceUtils.VALID_CONTACT;  import static com.android.systemui.people.PeopleSpaceUtils.convertDrawableToBitmap;  import static com.android.systemui.people.PeopleSpaceUtils.getUserId; @@ -39,6 +41,8 @@ import android.app.people.ConversationStatus;  import android.app.people.PeopleSpaceTile;  import android.content.Context;  import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager;  import android.content.res.Configuration;  import android.graphics.Bitmap;  import android.graphics.drawable.Drawable; @@ -48,6 +52,7 @@ import android.icu.util.Measure;  import android.icu.util.MeasureUnit;  import android.net.Uri;  import android.os.Bundle; +import android.os.UserHandle;  import android.text.TextUtils;  import android.util.IconDrawableFactory;  import android.util.Log; @@ -57,6 +62,8 @@ import android.widget.RemoteViews;  import android.widget.TextView;  import com.android.internal.annotations.VisibleForTesting; +import com.android.launcher3.icons.FastBitmapDrawable; +import com.android.settingslib.Utils;  import com.android.systemui.R;  import com.android.systemui.people.widget.LaunchConversationActivity;  import com.android.systemui.people.widget.PeopleSpaceWidgetProvider; @@ -142,7 +149,9 @@ public class PeopleTileViewHelper {      private int mMediumVerticalPadding;      private Context mContext; +    @Nullable      private PeopleSpaceTile mTile; +    private PeopleTileKey mKey;      private float mDensity;      private int mAppWidgetId;      private int mWidth; @@ -152,10 +161,11 @@ public class PeopleTileViewHelper {      private Locale mLocale;      private NumberFormat mIntegerFormat; -    public PeopleTileViewHelper(Context context, PeopleSpaceTile tile, -            int appWidgetId, Bundle options) { +    public PeopleTileViewHelper(Context context, @Nullable PeopleSpaceTile tile, +            int appWidgetId, Bundle options, PeopleTileKey key) {          mContext = context;          mTile = tile; +        mKey = key;          mAppWidgetId = appWidgetId;          mDensity = mContext.getResources().getDisplayMetrics().density;          int display = mContext.getResources().getConfiguration().orientation; @@ -184,8 +194,19 @@ public class PeopleTileViewHelper {       * content, then birthdays, then the most recent status, and finally last interaction.       */      private RemoteViews getViewForTile() { -        PeopleTileKey key = new PeopleTileKey(mTile); -        if (DEBUG) Log.d(TAG, "Creating view for tile key: " + key.toString()); +        if (DEBUG) Log.d(TAG, "Creating view for tile key: " + mKey.toString()); +        if (mTile == null || mTile.isPackageSuspended() || mTile.isUserQuieted()) { +            if (DEBUG) Log.d(TAG, "Create empty view: " + mTile); +            return createEmptyView(); +        } + +        boolean dndBlockingTileData = isDndBlockingTileData(mTile); +        if (dndBlockingTileData) { +            if (DEBUG) Log.d(TAG, "Create DND view: " + mTile.getNotificationPolicyState()); +            // TODO: Create DND view. +            return createEmptyView(); +        } +          if (Objects.equals(mTile.getNotificationCategory(), CATEGORY_MISSED_CALL)) {              if (DEBUG) Log.d(TAG, "Create missed call view");              return createMissedCallRemoteViews(); @@ -217,6 +238,58 @@ public class PeopleTileViewHelper {          return createLastInteractionRemoteViews();      } +    private boolean isDndBlockingTileData(PeopleSpaceTile tile) { +        int notificationPolicyState = tile.getNotificationPolicyState(); +        if ((notificationPolicyState & PeopleSpaceTile.SHOW_CONVERSATIONS) != 0) { +            // Not in DND, or all conversations +            if (DEBUG) Log.d(TAG, "Tile can show all data: " + tile.getUserName()); +            return false; +        } +        if ((notificationPolicyState & PeopleSpaceTile.SHOW_IMPORTANT_CONVERSATIONS) != 0 +                && tile.isImportantConversation()) { +            if (DEBUG) Log.d(TAG, "Tile can show important: " + tile.getUserName()); +            return false; +        } +        if ((notificationPolicyState & PeopleSpaceTile.SHOW_STARRED_CONTACTS) != 0 +                && tile.getContactAffinity() == STARRED_CONTACT) { +            if (DEBUG) Log.d(TAG, "Tile can show starred: " + tile.getUserName()); +            return false; +        } +        if ((notificationPolicyState & PeopleSpaceTile.SHOW_CONTACTS) != 0 +                && (tile.getContactAffinity() == VALID_CONTACT +                || tile.getContactAffinity() == STARRED_CONTACT)) { +            if (DEBUG) Log.d(TAG, "Tile can show contacts: " + tile.getUserName()); +            return false; +        } +        if (DEBUG) Log.d(TAG, "Tile can show if can bypass DND: " + tile.getUserName()); +        return !tile.canBypassDnd(); +    } + +    private RemoteViews createEmptyView() { +        RemoteViews views = new RemoteViews(mContext.getPackageName(), +                R.layout.people_tile_empty_layout); +        Drawable appIcon = getAppBadge(mKey.getPackageName(), mKey.getUserId()); +        Bitmap appIconAsBitmap = convertDrawableToBitmap(appIcon); +        FastBitmapDrawable drawable = new FastBitmapDrawable( +                appIconAsBitmap); +        drawable.setIsDisabled(true); +        Bitmap convertedBitmap = convertDrawableToBitmap(drawable); +        views.setImageViewBitmap(R.id.item, convertedBitmap); +        return views; +    } + +    private Drawable getAppBadge(String packageName, int userId) { +        Drawable badge = null; +        try { +            final ApplicationInfo appInfo = mContext.getPackageManager().getApplicationInfoAsUser( +                    packageName, PackageManager.GET_META_DATA, userId); +            badge = Utils.getBadgedIcon(mContext, appInfo); +        } catch (PackageManager.NameNotFoundException e) { +            badge = mContext.getPackageManager().getDefaultActivityIcon(); +        } +        return badge; +    } +      private void setMaxLines(RemoteViews views, boolean showSender) {          int textSize = mLayoutSize == LAYOUT_LARGE ? getSizeInDp(                  R.dimen.content_text_size_for_medium) @@ -337,6 +410,9 @@ public class PeopleTileViewHelper {      private RemoteViews setCommonRemoteViewsFields(RemoteViews views,              int maxAvatarSize) {          try { +            if (mTile == null) { +                return views; +            }              boolean isAvailable =                      mTile.getStatuses() != null && mTile.getStatuses().stream().anyMatch(                              c -> c.getAvailability() == AVAILABILITY_AVAILABLE); @@ -367,13 +443,16 @@ public class PeopleTileViewHelper {                              | Intent.FLAG_ACTIVITY_CLEAR_TASK                              | Intent.FLAG_ACTIVITY_NO_HISTORY                              | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); -            activityIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_TILE_ID, mTile.getId()); +            activityIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_TILE_ID, mKey.getShortcutId());              activityIntent.putExtra( -                    PeopleSpaceWidgetProvider.EXTRA_PACKAGE_NAME, mTile.getPackageName()); +                    PeopleSpaceWidgetProvider.EXTRA_PACKAGE_NAME, mKey.getPackageName());              activityIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_USER_HANDLE, -                    mTile.getUserHandle()); -            activityIntent.putExtra( -                    PeopleSpaceWidgetProvider.EXTRA_NOTIFICATION_KEY, mTile.getNotificationKey()); +                    new UserHandle(mKey.getUserId())); +            if (mTile != null) { +                activityIntent.putExtra( +                        PeopleSpaceWidgetProvider.EXTRA_NOTIFICATION_KEY, +                        mTile.getNotificationKey()); +            }              views.setOnClickPendingIntent(R.id.item, PendingIntent.getActivity(                      mContext,                      mAppWidgetId, @@ -727,6 +806,9 @@ public class PeopleTileViewHelper {                          c -> c.getActivity() == ACTIVITY_NEW_STORY);          Icon icon = tile.getUserIcon(); +        if (icon == null) { +            return null; +        }          PeopleStoryIconFactory storyIcon = new PeopleStoryIconFactory(context,                  context.getPackageManager(),                  IconDrawableFactory.newInstance(context, false), diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java index 64a6509ea0aa..ea1724f96669 100644 --- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java +++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java @@ -17,6 +17,12 @@  package com.android.systemui.people.widget;  import static android.Manifest.permission.READ_CONTACTS; +import static android.app.NotificationManager.INTERRUPTION_FILTER_ALARMS; +import static android.app.NotificationManager.INTERRUPTION_FILTER_ALL; +import static android.app.NotificationManager.INTERRUPTION_FILTER_NONE; +import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY; +import static android.content.Intent.ACTION_BOOT_COMPLETED; +import static android.service.notification.ZenPolicy.CONVERSATION_SENDERS_ANYONE;  import static com.android.systemui.people.NotificationHelper.getContactUri;  import static com.android.systemui.people.NotificationHelper.getHighestPriorityNotification; @@ -30,13 +36,12 @@ import static com.android.systemui.people.PeopleSpaceUtils.augmentTileFromNotifi  import static com.android.systemui.people.PeopleSpaceUtils.getMessagesCount;  import static com.android.systemui.people.PeopleSpaceUtils.getNotificationsByUri;  import static com.android.systemui.people.PeopleSpaceUtils.removeNotificationFields; -import static com.android.systemui.people.PeopleSpaceUtils.updateAppWidgetOptionsAndView; -import static com.android.systemui.people.PeopleSpaceUtils.updateAppWidgetViews;  import android.annotation.NonNull;  import android.annotation.Nullable;  import android.app.INotificationManager;  import android.app.NotificationChannel; +import android.app.NotificationManager;  import android.app.PendingIntent;  import android.app.Person;  import android.app.people.ConversationChannel; @@ -44,8 +49,11 @@ import android.app.people.IPeopleManager;  import android.app.people.PeopleManager;  import android.app.people.PeopleSpaceTile;  import android.appwidget.AppWidgetManager; +import android.content.BroadcastReceiver;  import android.content.ComponentName;  import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter;  import android.content.SharedPreferences;  import android.content.pm.LauncherApps;  import android.content.pm.PackageManager; @@ -60,6 +68,8 @@ import android.preference.PreferenceManager;  import android.service.notification.ConversationChannelWrapper;  import android.service.notification.NotificationListenerService;  import android.service.notification.StatusBarNotification; +import android.service.notification.ZenModeConfig; +import android.text.TextUtils;  import android.util.Log;  import android.widget.RemoteViews; @@ -67,8 +77,9 @@ import com.android.internal.annotations.GuardedBy;  import com.android.internal.annotations.VisibleForTesting;  import com.android.internal.logging.UiEventLogger;  import com.android.internal.logging.UiEventLoggerImpl; -import com.android.settingslib.utils.ThreadUtils; -import com.android.systemui.Dependency; +import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.dagger.qualifiers.Background;  import com.android.systemui.people.NotificationHelper;  import com.android.systemui.people.PeopleSpaceUtils;  import com.android.systemui.people.PeopleTileViewHelper; @@ -85,15 +96,15 @@ import java.util.List;  import java.util.Map;  import java.util.Optional;  import java.util.Set; +import java.util.concurrent.Executor;  import java.util.function.Function;  import java.util.stream.Collectors;  import java.util.stream.Stream;  import javax.inject.Inject; -import javax.inject.Singleton;  /** Manager for People Space widget. */ -@Singleton +@SysUISingleton  public class PeopleSpaceWidgetManager {      private static final String TAG = "PeopleSpaceWidgetMgr";      private static final boolean DEBUG = PeopleSpaceUtils.DEBUG; @@ -107,12 +118,15 @@ public class PeopleSpaceWidgetManager {      private PeopleManager mPeopleManager;      private NotificationEntryManager mNotificationEntryManager;      private PackageManager mPackageManager; -    private PeopleSpaceWidgetProvider mPeopleSpaceWidgetProvider;      private INotificationManager mINotificationManager;      private UserManager mUserManager; +    private PeopleSpaceWidgetManager mManager;      public UiEventLogger mUiEventLogger = new UiEventLoggerImpl(); +    private NotificationManager mNotificationManager; +    private BroadcastDispatcher mBroadcastDispatcher; +    private Executor mBgExecutor;      @GuardedBy("mLock") -    public static Map<PeopleTileKey, PeopleSpaceWidgetProvider.TileConversationListener> +    public static Map<PeopleTileKey, TileConversationListener>              mListeners = new HashMap<>();      @GuardedBy("mLock") @@ -120,46 +134,91 @@ public class PeopleSpaceWidgetManager {      // This is required because on notification removal, the contact Uri field is stripped and we      // only have the notification key to determine which widget IDs should be updated.      private Map<String, Set<String>> mNotificationKeyToWidgetIdsMatchedByUri = new HashMap<>(); -    private boolean mIsForTesting; +    private boolean mRegisteredReceivers;      @Inject -    public PeopleSpaceWidgetManager(Context context) { +    public PeopleSpaceWidgetManager(Context context, LauncherApps launcherApps, +            NotificationEntryManager notificationEntryManager, +            PackageManager packageManager, UserManager userManager, +            NotificationManager notificationManager, BroadcastDispatcher broadcastDispatcher, +            @Background Executor bgExecutor) {          if (DEBUG) Log.d(TAG, "constructor");          mContext = context;          mAppWidgetManager = AppWidgetManager.getInstance(context);          mIPeopleManager = IPeopleManager.Stub.asInterface(                  ServiceManager.getService(Context.PEOPLE_SERVICE)); -        mLauncherApps = context.getSystemService(LauncherApps.class); +        mLauncherApps = launcherApps;          mSharedPrefs = PreferenceManager.getDefaultSharedPreferences(mContext); -        mPeopleManager = mContext.getSystemService(PeopleManager.class); -        mNotificationEntryManager = Dependency.get(NotificationEntryManager.class); -        mPackageManager = mContext.getPackageManager(); -        mPeopleSpaceWidgetProvider = new PeopleSpaceWidgetProvider(); +        mPeopleManager = context.getSystemService(PeopleManager.class); +        mNotificationEntryManager = notificationEntryManager; +        mPackageManager = packageManager;          mINotificationManager = INotificationManager.Stub.asInterface(                  ServiceManager.getService(Context.NOTIFICATION_SERVICE)); -        mUserManager = context.getSystemService(UserManager.class); +        mUserManager = userManager; +        mNotificationManager = notificationManager; +        mManager = this; +        mBroadcastDispatcher = broadcastDispatcher; +        mBgExecutor = bgExecutor; +    } + +    /** Initializes {@PeopleSpaceWidgetManager}. */ +    public void init() { +        synchronized (mLock) { +            if (!mRegisteredReceivers) { +                IntentFilter filter = new IntentFilter(); +                filter.addAction(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED); +                filter.addAction(ACTION_BOOT_COMPLETED); +                filter.addAction(Intent.ACTION_LOCALE_CHANGED); +                filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE); +                filter.addAction(Intent.ACTION_PACKAGES_SUSPENDED); +                filter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED); +                filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE); +                filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE); +                filter.addAction(Intent.ACTION_USER_UNLOCKED); +                mBroadcastDispatcher.registerReceiver(mBaseBroadcastReceiver, filter, +                        null /* executor */, UserHandle.ALL); +                mRegisteredReceivers = true; +            } +        } +    } + +    /** Listener for the shortcut data changes. */ +    public class TileConversationListener implements PeopleManager.ConversationListener { + +        @Override +        public void onConversationUpdate(@NonNull ConversationChannel conversation) { +            if (DEBUG) { +                Log.d(TAG, +                        "Received updated conversation: " +                                + conversation.getShortcutInfo().getLabel()); +            } +            updateWidgetsWithConversationChanged(conversation); +        }      }      /** -     * AppWidgetManager setter used for testing. +     * PeopleSpaceWidgetManager setter used for testing.       */      @VisibleForTesting -    public void setAppWidgetManager( +    PeopleSpaceWidgetManager(Context context,              AppWidgetManager appWidgetManager, IPeopleManager iPeopleManager,              PeopleManager peopleManager, LauncherApps launcherApps,              NotificationEntryManager notificationEntryManager, PackageManager packageManager, -            boolean isForTesting, PeopleSpaceWidgetProvider peopleSpaceWidgetProvider, -            UserManager userManager, INotificationManager notificationManager) { +            UserManager userManager, INotificationManager iNotificationManager, +            NotificationManager notificationManager, @Background Executor executor) { +        mContext = context;          mAppWidgetManager = appWidgetManager;          mIPeopleManager = iPeopleManager;          mPeopleManager = peopleManager;          mLauncherApps = launcherApps;          mNotificationEntryManager = notificationEntryManager;          mPackageManager = packageManager; -        mIsForTesting = isForTesting; -        mPeopleSpaceWidgetProvider = peopleSpaceWidgetProvider;          mUserManager = userManager; -        mINotificationManager = notificationManager; +        mINotificationManager = iNotificationManager; +        mNotificationManager = notificationManager; +        mManager = this; +        mSharedPrefs = PreferenceManager.getDefaultSharedPreferences(context); +        mBgExecutor = executor;      }      /** @@ -173,7 +232,7 @@ public class PeopleSpaceWidgetManager {                  return;              } -            if (DEBUG) Log.d(TAG, "updating " + widgetIds.length + " widgets"); +            if (DEBUG) Log.d(TAG, "updating " + widgetIds.length + " widgets: " + widgetIds);              synchronized (mLock) {                  updateSingleConversationWidgets(widgetIds);              } @@ -191,16 +250,47 @@ public class PeopleSpaceWidgetManager {          for (int appWidgetId : appWidgetIds) {              PeopleSpaceTile tile = getTileForExistingWidget(appWidgetId);              if (tile == null) { -                if (DEBUG) Log.d(TAG, "Matching conversation not found for shortcut ID"); -                //TODO: Delete app widget id when crash is fixed (b/172932636) -                continue; +                Log.e(TAG, "Matching conversation not found for shortcut ID");              }              Bundle options = mAppWidgetManager.getAppWidgetOptions(appWidgetId); -            updateAppWidgetViews(mAppWidgetManager, mContext, appWidgetId, tile, options); +            updateAppWidgetViews(appWidgetId, tile, options);              widgetIdToTile.put(appWidgetId, tile); +            if (tile != null) { +                registerConversationListenerIfNeeded(appWidgetId, +                        new PeopleTileKey(tile)); +            } +        } +        PeopleSpaceUtils.getDataFromContactsOnBackgroundThread( +                mContext, mManager, widgetIdToTile, appWidgetIds); +    } + +    /** Updates the current widget view with provided {@link PeopleSpaceTile}. */ +    private void updateAppWidgetViews(int appWidgetId, PeopleSpaceTile tile, Bundle options) { +        PeopleTileKey key = getKeyFromStorageByWidgetId(appWidgetId); +        if (DEBUG) Log.d(TAG, "Widget: " + appWidgetId + " for: " + key.toString()); +        if (!key.isValid()) { +            Log.e(TAG, "Cannot update invalid widget"); +            return; +        } +        RemoteViews views = new PeopleTileViewHelper(mContext, tile, appWidgetId, +                options, key).getViews(); + +        // Tell the AppWidgetManager to perform an update on the current app widget. +        mAppWidgetManager.updateAppWidget(appWidgetId, views); +    } + +    /** Updates tile in app widget options and the current view. */ +    public void updateAppWidgetOptionsAndViewOptional(int appWidgetId, +            Optional<PeopleSpaceTile> tile) { +        if (tile.isPresent()) { +            updateAppWidgetOptionsAndView(appWidgetId, tile.get());          } -        PeopleSpaceUtils.getBirthdaysOnBackgroundThread( -                mContext, mAppWidgetManager, widgetIdToTile, appWidgetIds); +    } + +    /** Updates tile in app widget options and the current view. */ +    public void updateAppWidgetOptionsAndView(int appWidgetId, PeopleSpaceTile tile) { +        Bundle options = AppWidgetOptionsHelper.setPeopleTile(mAppWidgetManager, appWidgetId, tile); +        updateAppWidgetViews(appWidgetId, tile, options);      }      /** @@ -226,7 +316,7 @@ public class PeopleSpaceWidgetManager {                  widgetSp.getInt(USER_ID, INVALID_USER_ID),                  widgetSp.getString(PACKAGE_NAME, EMPTY_STRING)); -        return getTileFromPersistentStorage(key); +        return getTileFromPersistentStorage(key, appWidgetId);      }      /** @@ -234,7 +324,7 @@ public class PeopleSpaceWidgetManager {       * If a {@link PeopleTileKey} is not provided, fetch one from {@link SharedPreferences}.       */      @Nullable -    public PeopleSpaceTile getTileFromPersistentStorage(PeopleTileKey key) { +    public PeopleSpaceTile getTileFromPersistentStorage(PeopleTileKey key, int appWidgetId) {          if (!key.isValid()) {              Log.e(TAG, "PeopleTileKey invalid: " + key.toString());              return null; @@ -254,7 +344,22 @@ public class PeopleSpaceWidgetManager {                  return null;              } -            return new PeopleSpaceTile.Builder(channel, mLauncherApps).build(); +            // Get tile from shortcut & conversation storage. +            PeopleSpaceTile.Builder storedTile = new PeopleSpaceTile.Builder(channel, +                    mLauncherApps); +            if (storedTile == null) { +                return storedTile.build(); +            } + +            // Supplement with our storage. +            String contactUri = mSharedPrefs.getString(String.valueOf(appWidgetId), null); +            if (contactUri != null && storedTile.build().getContactUri() == null) { +                if (DEBUG) Log.d(TAG, "Restore contact uri from storage: " + contactUri); +                storedTile.setContactUri(Uri.parse(contactUri)); +            } + +            // Add current state. +            return updateWithCurrentState(storedTile.build(), ACTION_BOOT_COMPLETED);          } catch (Exception e) {              Log.e(TAG, "Failed to retrieve conversation for tile: " + e);              return null; @@ -275,11 +380,7 @@ public class PeopleSpaceWidgetManager {                  Log.d(TAG, "Notification removed, key: " + sbn.getKey());              }          } -        if (mIsForTesting) { -            updateWidgetsWithNotificationChangedInBackground(sbn, notificationAction); -            return; -        } -        ThreadUtils.postOnBackgroundThread( +        mBgExecutor.execute(                  () -> updateWidgetsWithNotificationChangedInBackground(sbn, notificationAction));      } @@ -331,8 +432,7 @@ public class PeopleSpaceWidgetManager {                      .collect(Collectors.toMap(                              Function.identity(),                              id -> getAugmentedTileForExistingWidget(id, groupedNotifications))) -                    .forEach((id, tile) -> -                            updateAppWidgetOptionsAndView(mAppWidgetManager, mContext, id, tile)); +                    .forEach((id, tile) -> updateAppWidgetOptionsAndViewOptional(id, tile));          } catch (Exception e) {              Log.e(TAG, "Exception updating widgets: " + e);          } @@ -341,16 +441,20 @@ public class PeopleSpaceWidgetManager {      /**       * Augments {@code tile} based on notifications returned from {@code notificationEntryManager}.       */ -    public PeopleSpaceTile augmentTileFromNotificationEntryManager(PeopleSpaceTile tile) { +    public PeopleSpaceTile augmentTileFromNotificationEntryManager(PeopleSpaceTile tile, +            Optional<Integer> appWidgetId) {          PeopleTileKey key = new PeopleTileKey(tile); -        Log.d(TAG, "Augmenting tile from NotificationEntryManager widget: " + key.toString()); +        if (DEBUG) { +            Log.d(TAG, +                    "Augmenting tile from NotificationEntryManager widget: " + key.toString()); +        }          Map<PeopleTileKey, Set<NotificationEntry>> notifications =                  getGroupedConversationNotifications();          String contactUri = null;          if (tile.getContactUri() != null) {              contactUri = tile.getContactUri().toString();          } -        return augmentTileFromNotifications(tile, key, contactUri, notifications); +        return augmentTileFromNotifications(tile, key, contactUri, notifications, appWidgetId);      }      /** Returns active and pending notifications grouped by {@link PeopleTileKey}. */ @@ -380,9 +484,11 @@ public class PeopleSpaceWidgetManager {      /** Augments {@code tile} based on {@code notifications}, matching {@code contactUri}. */      public PeopleSpaceTile augmentTileFromNotifications(PeopleSpaceTile tile, PeopleTileKey key, -            String contactUri, Map<PeopleTileKey, Set<NotificationEntry>> notifications) { +            String contactUri, +            Map<PeopleTileKey, Set<NotificationEntry>> notifications, +            Optional<Integer> appWidgetId) {          if (DEBUG) Log.d(TAG, "Augmenting tile from notifications. Tile key: " + key.toString()); -        boolean hasReadContactsPermission =  mPackageManager.checkPermission(READ_CONTACTS, +        boolean hasReadContactsPermission = mPackageManager.checkPermission(READ_CONTACTS,                  tile.getPackageName()) == PackageManager.PERMISSION_GRANTED;          List<NotificationEntry> notificationsByUri = new ArrayList<>(); @@ -413,7 +519,8 @@ public class PeopleSpaceWidgetManager {          NotificationEntry highestPriority = getHighestPriorityNotification(allNotifications);          if (DEBUG) Log.d(TAG, "Augmenting tile from notification, key: " + key.toString()); -        return augmentTileFromNotification(mContext, tile, key, highestPriority, messagesCount); +        return augmentTileFromNotification(mContext, tile, key, highestPriority, messagesCount, +                appWidgetId);      }      /** Returns an augmented tile for an existing widget. */ @@ -434,7 +541,8 @@ public class PeopleSpaceWidgetManager {          PeopleTileKey key = new PeopleTileKey(tile);          if (DEBUG) Log.d(TAG, "Existing widget: " + widgetId + ". Tile key: " + key.toString());          return Optional.ofNullable( -                augmentTileFromNotifications(tile, key, contactUriString, notifications)); +                augmentTileFromNotifications(tile, key, contactUriString, notifications, +                        Optional.of(widgetId)));      }      /** Returns stored widgets for the conversation specified. */ @@ -552,10 +660,8 @@ public class PeopleSpaceWidgetManager {                  .setStatuses(conversation.getStatuses())                  .setLastInteractionTimestamp(conversation.getLastEventTimestamp())                  .setIsImportantConversation(conversation.getParentNotificationChannel() != null -                        && conversation.getParentNotificationChannel().isImportantConversation()) -                .build(); -        updateAppWidgetOptionsAndView(mAppWidgetManager, mContext, appWidgetId, -                updatedTile.build()); +                        && conversation.getParentNotificationChannel().isImportantConversation()); +        updateAppWidgetOptionsAndView(appWidgetId, updatedTile.build());      }      /** @@ -640,11 +746,11 @@ public class PeopleSpaceWidgetManager {      /** Adds a widget based on {@code key} mapped to {@code appWidgetId}. */      public void addNewWidget(int appWidgetId, PeopleTileKey key) {          if (DEBUG) Log.d(TAG, "addNewWidget called with key for appWidgetId: " + appWidgetId); -        PeopleSpaceTile tile = getTileFromPersistentStorage(key); +        PeopleSpaceTile tile = getTileFromPersistentStorage(key, appWidgetId);          if (tile == null) {              return;          } -        tile = augmentTileFromNotificationEntryManager(tile); +        tile = augmentTileFromNotificationEntryManager(tile, Optional.of(appWidgetId));          PeopleTileKey existingKeyIfStored;          synchronized (mLock) { @@ -665,6 +771,8 @@ public class PeopleSpaceWidgetManager {              PeopleSpaceUtils.setSharedPreferencesStorageForTile(mContext, key, appWidgetId,                      tile.getContactUri());          } +        if (DEBUG) Log.d(TAG, "Ensure listener is registered for widget: " + appWidgetId); +        registerConversationListenerIfNeeded(appWidgetId, key);          try {              if (DEBUG) Log.d(TAG, "Caching shortcut for PeopleTile: " + key.toString());              mLauncherApps.cacheShortcuts(tile.getPackageName(), @@ -674,23 +782,17 @@ public class PeopleSpaceWidgetManager {              Log.w(TAG, "Exception caching shortcut:" + e);          } -        PeopleSpaceUtils.updateAppWidgetOptionsAndView( -                mAppWidgetManager, mContext, appWidgetId, tile); -        mPeopleSpaceWidgetProvider.onUpdate(mContext, mAppWidgetManager, new int[]{appWidgetId}); +        updateAppWidgetOptionsAndView(appWidgetId, tile);      }      /** Registers a conversation listener for {@code appWidgetId} if not already registered. */ -    public void registerConversationListenerIfNeeded(int widgetId, -            PeopleSpaceWidgetProvider.TileConversationListener newListener) { +    public void registerConversationListenerIfNeeded(int widgetId, PeopleTileKey key) {          // Retrieve storage needed for registration. -        PeopleTileKey key; -        synchronized (mLock) { -            key = getKeyFromStorageByWidgetId(widgetId); -            if (!key.isValid()) { -                if (DEBUG) Log.w(TAG, "Could not register listener for widget: " + widgetId); -                return; -            } +        if (!key.isValid()) { +            if (DEBUG) Log.w(TAG, "Could not register listener for widget: " + widgetId); +            return;          } +        TileConversationListener newListener = new TileConversationListener();          synchronized (mListeners) {              if (mListeners.containsKey(key)) {                  if (DEBUG) Log.d(TAG, "Already registered listener"); @@ -760,7 +862,7 @@ public class PeopleSpaceWidgetManager {      /** Unregisters the conversation listener for {@code appWidgetId}. */      private void unregisterConversationListener(PeopleTileKey key, int appWidgetId) { -        PeopleSpaceWidgetProvider.TileConversationListener registeredListener; +        TileConversationListener registeredListener;          synchronized (mListeners) {              registeredListener = mListeners.get(key);              if (registeredListener == null) { @@ -875,9 +977,153 @@ public class PeopleSpaceWidgetManager {              return null;          } -        PeopleSpaceTile augmentedTile = augmentTileFromNotificationEntryManager(tile); +        PeopleSpaceTile augmentedTile = augmentTileFromNotificationEntryManager(tile, +                Optional.empty());          if (DEBUG) Log.i(TAG, "Returning tile preview for shortcutId: " + shortcutId); -        return new PeopleTileViewHelper(mContext, augmentedTile, 0, options).getViews(); +        return new PeopleTileViewHelper(mContext, augmentedTile, 0, options, +                new PeopleTileKey(augmentedTile)).getViews(); +    } + +    protected final BroadcastReceiver mBaseBroadcastReceiver = new BroadcastReceiver() { + +        @Override +        public void onReceive(Context context, Intent intent) { +            String action = intent.getAction(); +            if (DEBUG) Log.d(TAG, "Update widgets from: " + action); +            mBgExecutor.execute(() -> updateWidgetsOnStateChange(action)); +        } +    }; + +    /** Updates any app widget based on the current state. */ +    @VisibleForTesting +    void updateWidgetsOnStateChange(String entryPoint) { +        int[] appWidgetIds = mAppWidgetManager.getAppWidgetIds( +                new ComponentName(mContext, PeopleSpaceWidgetProvider.class)); +        if (appWidgetIds == null) { +            return; +        } +        synchronized (mLock) { +            for (int appWidgetId : appWidgetIds) { +                PeopleSpaceTile tile = getTileForExistingWidget(appWidgetId); +                if (tile == null) { +                    Log.e(TAG, "Matching conversation not found for shortcut ID"); +                } else { +                    tile = updateWithCurrentState(tile, entryPoint); +                } +                updateAppWidgetOptionsAndView(appWidgetId, tile); +            } +        } +    } + +    /** Checks the current state of {@code tile} dependencies, updating fields as necessary. */ +    @Nullable +    private PeopleSpaceTile updateWithCurrentState(PeopleSpaceTile tile, +            String entryPoint) { +        PeopleSpaceTile.Builder updatedTile = tile.toBuilder(); +        try { +            switch (entryPoint) { +                case NotificationManager +                        .ACTION_INTERRUPTION_FILTER_CHANGED: +                    updatedTile.setNotificationPolicyState(getNotificationPolicyState()); +                    break; +                case Intent.ACTION_PACKAGES_SUSPENDED: +                case Intent.ACTION_PACKAGES_UNSUSPENDED: +                    updatedTile.setIsPackageSuspended(getPackageSuspended(tile)); +                    break; +                case Intent.ACTION_MANAGED_PROFILE_AVAILABLE: +                case Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE: +                case Intent.ACTION_USER_UNLOCKED: +                    updatedTile.setIsUserQuieted(getUserQuieted(tile)); +                    break; +                case Intent.ACTION_LOCALE_CHANGED: +                    break; +                case ACTION_BOOT_COMPLETED: +                default: +                    updatedTile.setIsUserQuieted(getUserQuieted(tile)).setIsPackageSuspended( +                            getPackageSuspended(tile)).setNotificationPolicyState( +                            getNotificationPolicyState()); +            } +        } catch (Exception e) { +            Log.e(TAG, "Package no longer found for tile: " + tile.toString() + e); +            return null; +        } +        return updatedTile.build(); +    } + +    private boolean getPackageSuspended(PeopleSpaceTile tile) throws Exception { +        boolean packageSuspended = !TextUtils.isEmpty(tile.getPackageName()) +                && mPackageManager.isPackageSuspended(tile.getPackageName()); +        if (DEBUG) Log.d(TAG, "Package suspended: " + packageSuspended); +        return packageSuspended; +    } + +    private boolean getUserQuieted(PeopleSpaceTile tile) { +        boolean workProfileQuieted = +                tile.getUserHandle() != null && mUserManager.isQuietModeEnabled( +                        tile.getUserHandle()); +        if (DEBUG) Log.d(TAG, "Work profile quiet: " + workProfileQuieted); +        return workProfileQuieted; +    } + +    private int getNotificationPolicyState() { +        NotificationManager.Policy policy = mNotificationManager.getNotificationPolicy(); +        boolean suppressVisualEffects = +                NotificationManager.Policy.areAllVisualEffectsSuppressed( +                        policy.suppressedVisualEffects); +        int notificationPolicyState = 0; +        switch (mNotificationManager.getCurrentInterruptionFilter()) { +            case INTERRUPTION_FILTER_ALL: +                if (DEBUG) Log.d(TAG, "All interruptions allowed"); +                return PeopleSpaceTile.SHOW_CONVERSATIONS; +            case INTERRUPTION_FILTER_PRIORITY: +                if (policy.allowConversations()) { +                    // If the user sees notifications in DND, show notifications in tiles in DND. +                    if (!suppressVisualEffects) { +                        if (DEBUG) Log.d(TAG, "Visual effects not suppressed."); +                        return PeopleSpaceTile.SHOW_CONVERSATIONS; +                    } +                    if (policy.priorityConversationSenders == CONVERSATION_SENDERS_ANYONE) { +                        if (DEBUG) Log.d(TAG, "All conversations allowed"); +                        // We only show conversations, so we can show everything. +                        return PeopleSpaceTile.SHOW_CONVERSATIONS; +                    } else if (policy.priorityConversationSenders +                            == NotificationManager.Policy.CONVERSATION_SENDERS_IMPORTANT) { +                        if (DEBUG) Log.d(TAG, "Important conversations allowed"); +                        notificationPolicyState |= PeopleSpaceTile.SHOW_IMPORTANT_CONVERSATIONS; +                    } +                } +                if (policy.allowMessages()) { +                    switch (policy.allowMessagesFrom()) { +                        case ZenModeConfig.SOURCE_CONTACT: +                            if (DEBUG) Log.d(TAG, "All contacts allowed"); +                            notificationPolicyState |= PeopleSpaceTile.SHOW_CONTACTS; +                            return notificationPolicyState; +                        case ZenModeConfig.SOURCE_STAR: +                            if (DEBUG) Log.d(TAG, "Starred contacts allowed"); +                            notificationPolicyState |= PeopleSpaceTile.SHOW_STARRED_CONTACTS; +                            return notificationPolicyState; +                        case ZenModeConfig.SOURCE_ANYONE: +                        default: +                            if (DEBUG) Log.d(TAG, "All messages allowed"); +                            return PeopleSpaceTile.SHOW_CONVERSATIONS; +                    } +                } +                if (notificationPolicyState != 0) { +                    if (DEBUG) Log.d(TAG, "Return block state: " + notificationPolicyState); +                    return notificationPolicyState; +                } +                // If only alarms or nothing can bypass DND, the tile shouldn't show conversations. +            case INTERRUPTION_FILTER_NONE: +            case INTERRUPTION_FILTER_ALARMS: +            default: +                // If the user sees notifications in DND, show notifications in tiles in DND. +                if (!suppressVisualEffects) { +                    if (DEBUG) Log.d(TAG, "Visual effects not suppressed."); +                    return PeopleSpaceTile.SHOW_CONVERSATIONS; +                } +                if (DEBUG) Log.d(TAG, "Block conversations"); +                return PeopleSpaceTile.BLOCK_CONVERSATIONS; +        }      }  } diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetProvider.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetProvider.java index 3bc5b29bd05d..3522b76e6460 100644 --- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetProvider.java +++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetProvider.java @@ -16,9 +16,6 @@  package com.android.systemui.people.widget; -import android.annotation.NonNull; -import android.app.people.ConversationChannel; -import android.app.people.PeopleManager;  import android.appwidget.AppWidgetManager;  import android.appwidget.AppWidgetProvider;  import android.content.Context; @@ -28,6 +25,8 @@ import android.util.Log;  import com.android.internal.annotations.VisibleForTesting;  import com.android.systemui.people.PeopleSpaceUtils; +import javax.inject.Inject; +  /** People Space Widget Provider class. */  public class PeopleSpaceWidgetProvider extends AppWidgetProvider {      private static final String TAG = "PeopleSpaceWidgetPvd"; @@ -38,25 +37,11 @@ public class PeopleSpaceWidgetProvider extends AppWidgetProvider {      public static final String EXTRA_USER_HANDLE = "extra_user_handle";      public static final String EXTRA_NOTIFICATION_KEY = "extra_notification_key"; -    public PeopleSpaceWidgetManager peopleSpaceWidgetManager; - -    /** Listener for the shortcut data changes. */ -    public class TileConversationListener implements PeopleManager.ConversationListener { +    public PeopleSpaceWidgetManager mPeopleSpaceWidgetManager; -        @Override -        public void onConversationUpdate(@NonNull ConversationChannel conversation) { -            if (DEBUG) { -                Log.d(TAG, -                        "Received updated conversation: " -                                + conversation.getShortcutInfo().getLabel()); -            } -            if (peopleSpaceWidgetManager == null) { -                // This shouldn't happen since onUpdate is called at reboot. -                Log.e(TAG, "Skipping conversation update: WidgetManager uninitialized"); -                return; -            } -            peopleSpaceWidgetManager.updateWidgetsWithConversationChanged(conversation); -        } +    @Inject +    PeopleSpaceWidgetProvider(PeopleSpaceWidgetManager peopleSpaceWidgetManager) { +        mPeopleSpaceWidgetManager = peopleSpaceWidgetManager;      }      /** Called when widget updates. */ @@ -65,15 +50,8 @@ public class PeopleSpaceWidgetProvider extends AppWidgetProvider {          super.onUpdate(context, appWidgetManager, appWidgetIds);          if (DEBUG) Log.d(TAG, "onUpdate called"); -        ensurePeopleSpaceWidgetManagerInitialized(context); -        peopleSpaceWidgetManager.updateWidgets(appWidgetIds); -        for (int appWidgetId : appWidgetIds) { -            if (DEBUG) Log.d(TAG, "Ensure listener is registered for widget: " + appWidgetId); -            PeopleSpaceWidgetProvider.TileConversationListener -                    newListener = new PeopleSpaceWidgetProvider.TileConversationListener(); -            peopleSpaceWidgetManager.registerConversationListenerIfNeeded(appWidgetId, -                    newListener); -        } +        ensurePeopleSpaceWidgetManagerInitialized(); +        mPeopleSpaceWidgetManager.updateWidgets(appWidgetIds);      }      /** Called when widget updates. */ @@ -81,25 +59,23 @@ public class PeopleSpaceWidgetProvider extends AppWidgetProvider {      public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager,              int appWidgetId, Bundle newOptions) {          super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions); -        ensurePeopleSpaceWidgetManagerInitialized(context); -        peopleSpaceWidgetManager.onAppWidgetOptionsChanged(appWidgetId, newOptions); +        ensurePeopleSpaceWidgetManagerInitialized(); +        mPeopleSpaceWidgetManager.onAppWidgetOptionsChanged(appWidgetId, newOptions);      }      @Override      public void onDeleted(Context context, int[] appWidgetIds) {          super.onDeleted(context, appWidgetIds); -        ensurePeopleSpaceWidgetManagerInitialized(context); -        peopleSpaceWidgetManager.deleteWidgets(appWidgetIds); +        ensurePeopleSpaceWidgetManagerInitialized(); +        mPeopleSpaceWidgetManager.deleteWidgets(appWidgetIds);      } -    private void ensurePeopleSpaceWidgetManagerInitialized(Context context) { -        if (peopleSpaceWidgetManager == null) { -            peopleSpaceWidgetManager = new PeopleSpaceWidgetManager(context); -        } +    private void ensurePeopleSpaceWidgetManagerInitialized() { +        mPeopleSpaceWidgetManager.init();      }      @VisibleForTesting      public void setPeopleSpaceWidgetManager(PeopleSpaceWidgetManager manager) { -        peopleSpaceWidgetManager = manager; +        mPeopleSpaceWidgetManager = manager;      }  } diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java index c552e89a3625..aa4fb712090b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java +++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java @@ -7,7 +7,6 @@ import android.animation.ObjectAnimator;  import android.animation.PropertyValuesHolder;  import android.content.Context;  import android.content.res.Configuration; -import android.content.res.Resources;  import android.os.Bundle;  import android.util.AttributeSet;  import android.util.Log; @@ -333,11 +332,6 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {      @Override      public boolean updateResources() { -        // Update bottom padding, useful for removing extra space once the panel page indicator is -        // hidden. -        Resources res = getContext().getResources(); -        setPageMargin(res.getDimensionPixelOffset(R.dimen.qs_tile_margin_horizontal)); -          setPadding(0, 0, 0,                  getContext().getResources().getDimensionPixelSize(                          R.dimen.qs_paged_tile_layout_padding_bottom)); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java index f486c535d9e2..3b436769a456 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java @@ -207,11 +207,12 @@ public class QSContainerImpl extends FrameLayout {                  mContext.getResources().getDimensionPixelSize(R.dimen.qs_container_bottom_padding)          ); -        mSideMargins = getResources().getDimensionPixelSize(R.dimen.notification_side_paddings); +        int sideMargins = getResources().getDimensionPixelSize(R.dimen.notification_side_paddings);          int padding = getResources().getDimensionPixelSize(                  R.dimen.notification_shade_content_margin_horizontal); -        boolean marginsChanged = padding != mContentPadding; +        boolean marginsChanged = padding != mContentPadding || sideMargins != mSideMargins;          mContentPadding = padding; +        mSideMargins = sideMargins;          if (marginsChanged) {              updatePaddingsAndMargins(qsPanelController, quickStatusBarHeaderController);          } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java index e3f00f42d2ca..c69956f90c67 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java @@ -55,9 +55,13 @@ public class QuickStatusBarHeader extends FrameLayout {      private TouchAnimator mAlphaAnimator;      private TouchAnimator mTranslationAnimator; +    private TouchAnimator mIconsAlphaAnimator; +    private TouchAnimator mIconsAlphaAnimatorFixed;      protected QuickQSPanel mHeaderQsPanel;      private View mDatePrivacyView; +    private View mDateView; +    private View mSecurityHeaderView;      private View mClockIconsView;      private View mContainer; @@ -66,7 +70,7 @@ public class QuickStatusBarHeader extends FrameLayout {      private Space mSpace;      private BatteryMeterView mBatteryRemainingIcon;      private StatusIconContainer mIconContainer; - +    private View mPrivacyChip;      private TintedIconManager mTintedIconManager;      private QSExpansionPathInterpolator mQSExpansionPathInterpolator; @@ -79,7 +83,6 @@ public class QuickStatusBarHeader extends FrameLayout {      private int mCutOutPaddingLeft;      private int mCutOutPaddingRight;      private float mClockIconsAlpha = 1.0f; -    private float mDatePrivacyAlpha = 1.0f;      private float mKeyguardExpansionFraction;      private int mTextColorPrimary = Color.TRANSPARENT;      private int mTopViewMeasureHeight; @@ -111,8 +114,11 @@ public class QuickStatusBarHeader extends FrameLayout {          mDatePrivacyView = findViewById(R.id.quick_status_bar_date_privacy);          mClockIconsView = findViewById(R.id.quick_qs_status_icons);          mQSCarriers = findViewById(R.id.carrier_group); -        mContainer = findViewById(R.id.container); +        mContainer = findViewById(R.id.qs_container);          mIconContainer = findViewById(R.id.statusIcons); +        mPrivacyChip = findViewById(R.id.privacy_chip); +        mDateView = findViewById(R.id.date); +        mSecurityHeaderView = findViewById(R.id.header_text_container);          mClockView = findViewById(R.id.clock);          mSpace = findViewById(R.id.space); @@ -126,6 +132,11 @@ public class QuickStatusBarHeader extends FrameLayout {          // QS will always show the estimate, and BatteryMeterView handles the case where          // it's unavailable or charging          mBatteryRemainingIcon.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE); + +        mIconsAlphaAnimatorFixed = new TouchAnimator.Builder() +                .addFloat(mIconContainer, "alpha", 0, 1) +                .addFloat(mBatteryRemainingIcon, "alpha", 0, 1) +                .build();      }      void onAttach(TintedIconManager iconManager, @@ -226,8 +237,12 @@ public class QuickStatusBarHeader extends FrameLayout {          StatusBarIconView callStrengthIcon =                  ((StatusBarIconView) mIconContainer.getViewForSlot(mCallStrengthSlotName));          TouchAnimator.Builder builder = new TouchAnimator.Builder() -                .addFloat(mQSCarriers, "alpha", 0, 1) -                .addFloat(mDatePrivacyView, "alpha", 0, mDatePrivacyAlpha); +                // The following two views have to be hidden manually, so as not to hide the +                // Privacy chip in QQS +                .addFloat(mDateView, "alpha", 0, 1) +                .addFloat(mSecurityHeaderView, "alpha", 0, 1) +                .addFloat(mQSCarriers, "alpha", 0, 1); +          if (noCallingIcon != null || callStrengthIcon != null) {              if (noCallingIcon != null) {                  builder.addFloat(noCallingIcon, "alpha", 1, 0); @@ -259,6 +274,20 @@ public class QuickStatusBarHeader extends FrameLayout {          mAlphaAnimator = builder.build();      } +    void setChipVisibility(boolean visibility) { +        mPrivacyChip.setVisibility(visibility ? View.VISIBLE : View.GONE); +        if (visibility) { +            // Animates the icons and battery indicator from alpha 0 to 1, when the chip is visible +            mIconsAlphaAnimator = mIconsAlphaAnimatorFixed; +            mIconsAlphaAnimator.setPosition(mKeyguardExpansionFraction); +        } else { +            mIconsAlphaAnimator = null; +            mIconContainer.setAlpha(1); +            mBatteryRemainingIcon.setAlpha(1); +        } + +    } +      /** */      public void setExpanded(boolean expanded, QuickQSPanelController quickQSPanelController) {          if (mExpanded == expanded) return; @@ -285,6 +314,9 @@ public class QuickStatusBarHeader extends FrameLayout {          if (mTranslationAnimator != null) {              mTranslationAnimator.setPosition(keyguardExpansionFraction);          } +        if (mIconsAlphaAnimator != null) { +            mIconsAlphaAnimator.setPosition(keyguardExpansionFraction); +        }          // If forceExpanded (we are opening QS from lockscreen), the animators have been set to          // position = 1f.          if (forceExpanded) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java index 3aafea98ff2a..617b067be891 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java @@ -225,7 +225,6 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader      private void setChipVisibility(boolean chipVisible) {          if (chipVisible && getChipEnabled()) { -            mPrivacyChip.setVisibility(View.VISIBLE);              mPrivacyLogger.logChipVisible(true);              // Makes sure that the chip is logged as viewed at most once each time QS is opened              // mListening makes sure that the callback didn't return after the user closed QS @@ -235,8 +234,8 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader              }          } else {              mPrivacyLogger.logChipVisible(false); -            mPrivacyChip.setVisibility(View.GONE);          } +        mView.setChipVisibility(chipVisible);      }      private List<String> getIgnoredIconSlots() { diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java index f078ccd9d382..1ec785d4712e 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java @@ -213,7 +213,9 @@ public class OverviewProxyService extends CurrentUserTracker implements                  // TODO move this logic to message queue                  mStatusBarOptionalLazy.ifPresent(statusBarLazy -> {                      StatusBar statusBar = statusBarLazy.get(); -                    statusBar.getPanelController().startExpandLatencyTracking(); +                    if (event.getActionMasked() == ACTION_DOWN) { +                        statusBar.getPanelController().startExpandLatencyTracking(); +                    }                      mHandler.post(()-> {                          int action = event.getActionMasked();                          if (action == ACTION_DOWN) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java index 6b68fc6640ee..a072de874938 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java @@ -924,7 +924,8 @@ public class KeyguardIndicationController implements KeyguardStateController.Cal              // check of whether non-strong biometric is allowed              return ((!updateMonitor.isUnlockingWithBiometricAllowed(true /* isStrongBiometric */)                      && msgId != FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT) -                    || msgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED); +                    || msgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED +                    || msgId == FingerprintManager.FINGERPRINT_ERROR_USER_CANCELED);          }          private boolean shouldSuppressFaceError(int msgId, KeyguardUpdateMonitor updateMonitor) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java index 5437ce63475e..7f31fddbfb6c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java @@ -18,6 +18,7 @@ package com.android.systemui.statusbar;  import static com.android.systemui.statusbar.RemoteInputController.processForRemoteInput;  import static com.android.systemui.statusbar.notification.NotificationEntryManager.UNDEFINED_DISMISS_REASON; +import static com.android.systemui.statusbar.phone.StatusBar.DEBUG;  import android.annotation.NonNull;  import android.annotation.SuppressLint; @@ -34,7 +35,6 @@ import android.util.Log;  import com.android.systemui.dagger.qualifiers.Main;  import com.android.systemui.statusbar.dagger.StatusBarModule;  import com.android.systemui.statusbar.phone.NotificationListenerWithPlugins; -import com.android.systemui.statusbar.phone.StatusBar;  import java.util.ArrayList;  import java.util.List; @@ -46,7 +46,6 @@ import java.util.List;  @SuppressLint("OverrideAbstract")  public class NotificationListener extends NotificationListenerWithPlugins {      private static final String TAG = "NotificationListener"; -    private static final boolean DEBUG = StatusBar.DEBUG;      private final Context mContext;      private final NotificationManager mNotificationManager; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java index 0e56ab73397b..dbd7b75a1eb3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java @@ -15,8 +15,6 @@   */  package com.android.systemui.statusbar; -import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY; -  import android.annotation.NonNull;  import android.annotation.Nullable;  import android.app.ActivityManager; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/commandline/CommandRegistry.kt b/packages/SystemUI/src/com/android/systemui/statusbar/commandline/CommandRegistry.kt index 1da42a705311..78e85f1e6f73 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/commandline/CommandRegistry.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/commandline/CommandRegistry.kt @@ -168,7 +168,6 @@ private class PrefsCommand(val context: Context) : Command {          when (topLevel) {              "list-prefs" -> listPrefs(pw) -            "set-pref" -> setPref(pw, args.drop(1))              else -> help(pw)          }      } @@ -180,25 +179,4 @@ private class PrefsCommand(val context: Context) : Command {              pw.println(field.get(Prefs.Key::class.java))          }      } - -    /** -     * Sets a preference from [Prefs] -     */ -    private fun setPref(pw: PrintWriter, args: List<String>) { -        if (args.isEmpty()) { -            pw.println("invalid arguments: $args") -            return -        } -        val pref = args[0] - -        when (pref) { -            Prefs.Key.HAS_SEEN_PRIORITY_ONBOARDING_IN_S -> { -                val value = Integer.parseInt(args[1]) -                Prefs.putBoolean(context, Prefs.Key.HAS_SEEN_PRIORITY_ONBOARDING_IN_S, value != 0) -            } -            else -> { -                pw.println("Cannot set pref ($pref)") -            } -        } -    }  } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt index 5ab71bc62fe6..b3f7ca6f2630 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt @@ -29,6 +29,8 @@ import com.android.systemui.animation.Interpolators  import com.android.systemui.R  import com.android.systemui.dagger.SysUISingleton  import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.statusbar.phone.StatusBarLocationPublisher +import com.android.systemui.statusbar.phone.StatusBarMarginUpdatedListener  import java.lang.IllegalStateException  import java.util.concurrent.Executor @@ -51,8 +53,9 @@ import javax.inject.Inject  @SysUISingleton  class PrivacyDotViewController @Inject constructor( -    @Main val mainExecutor: Executor, -    val animationScheduler: SystemStatusAnimationScheduler +    @Main private val mainExecutor: Executor, +    private val locationPublisher: StatusBarLocationPublisher, +    private val animationScheduler: SystemStatusAnimationScheduler  ) {      private var rotation = 0      private var leftSize = 0 @@ -80,12 +83,21 @@ class PrivacyDotViewController @Inject constructor(      private val views: Sequence<View>          get() = if (!this::tl.isInitialized) sequenceOf() else sequenceOf(tl, tr, br, bl) +    init { +        locationPublisher.addCallback(object : StatusBarMarginUpdatedListener { +            override fun onStatusBarMarginUpdated(marginLeft: Int, marginRight: Int) { +                setStatusBarMargins(marginLeft, marginRight) +            } +        }) +    } +      fun setUiExecutor(e: Executor) {          uiExecutor = e      }      @UiThread      fun updateRotation(rot: Int) { +        dlog("updateRotation: ")          if (rot == rotation) {              return          } @@ -248,7 +260,7 @@ class PrivacyDotViewController @Inject constructor(       * @param left the space between the status bar contents and the left side of the screen       * @param right space between the status bar contents and the right side of the screen       */ -    fun setStatusBarMargins(left: Int, right: Int) { +    private fun setStatusBarMargins(left: Int, right: Int) {          leftSize = left          rightSize = right @@ -262,6 +274,7 @@ class PrivacyDotViewController @Inject constructor(      }      private fun doUpdates(rot: Boolean, height: Boolean, width: Boolean) { +        dlog("doUpdates: ")          var newDesignatedCorner: View? = null          if (rot) { @@ -324,12 +337,19 @@ class PrivacyDotViewController @Inject constructor(      }  } +private fun dlog(s: String) { +    if (DEBUG) { +        Log.d(TAG, s) +    } +} +  const val TOP_LEFT = 0  const val TOP_RIGHT = 1  const val BOTTOM_RIGHT = 2  const val BOTTOM_LEFT = 3  private const val DURATION = 160L  private const val TAG = "PrivacyDotViewController" +private const val DEBUG = false  private fun Int.toGravity(): Int {      return when (this) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt index 620963060b49..b861c1db9b8b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt @@ -27,6 +27,7 @@ import android.widget.FrameLayout  import com.android.systemui.R  import com.android.systemui.statusbar.SuperStatusBarViewFactory +import com.android.systemui.statusbar.phone.StatusBarLocationPublisher  import com.android.systemui.statusbar.phone.StatusBarWindowController  import com.android.systemui.statusbar.phone.StatusBarWindowView @@ -39,7 +40,8 @@ import javax.inject.Inject  class SystemEventChipAnimationController @Inject constructor(      private val context: Context,      private val statusBarViewFactory: SuperStatusBarViewFactory, -    private val statusBarWindowController: StatusBarWindowController +    private val statusBarWindowController: StatusBarWindowController, +    private val locationPublisher: StatusBarLocationPublisher  ) : SystemStatusChipAnimationCallback {      var showPersistentDot = false          set(value) { @@ -64,13 +66,15 @@ class SystemEventChipAnimationController @Inject constructor(          if (state == ANIMATING_IN) {              currentAnimatedView = viewCreator(context) -            animationWindowView.addView(currentAnimatedView, layoutParamsDefault) +            animationWindowView.addView(currentAnimatedView, layoutParamsDefault())              // We are animating IN; chip comes in from View.END              currentAnimatedView?.apply { -                translationX = width.toFloat() +                val translation = width.toFloat() +                translationX = if (isLayoutRtl) -translation else translation                  alpha = 0f                  visibility = View.VISIBLE +                setPadding(locationPublisher.marginLeft, 0, locationPublisher.marginRight, 0)              }          } else {              // We are animating away @@ -109,7 +113,7 @@ class SystemEventChipAnimationController @Inject constructor(              val w = width              val translation = (1 - amt) * w -            translationX = translation +            translationX = if (isLayoutRtl) -translation else translation          }      } @@ -131,7 +135,13 @@ class SystemEventChipAnimationController @Inject constructor(          statusBarWindowView.addView(animationWindowView, lp)      } -    private val layoutParamsDefault = FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT).also { -        it.gravity = Gravity.END or Gravity.CENTER_VERTICAL +    private fun start() = if (animationWindowView.isLayoutRtl) right() else left() +    private fun right() = locationPublisher.marginRight +    private fun left() = locationPublisher.marginLeft + +    private fun layoutParamsDefault(): FrameLayout.LayoutParams = +        FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT).also { +            it.gravity = Gravity.END or Gravity.CENTER_VERTICAL +            it.marginStart = start()      }  } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt index 1e071312065b..40049373610c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt @@ -127,7 +127,6 @@ class SystemStatusAnimationScheduler @Inject constructor(      }      private fun isTooEarly(): Boolean { -        Log.d(TAG, "time=> ${systemClock.uptimeMillis() - Process.getStartUptimeMillis()}")          return systemClock.uptimeMillis() - Process.getStartUptimeMillis() < MIN_UPTIME      } @@ -339,4 +338,4 @@ private const val ENTRANCE_ANIM_LENGTH = 500L  private const val CHIP_ANIM_LENGTH = 500L  private const val MIN_UPTIME: Long = 5 * 1000 -private const val DEBUG = false
\ No newline at end of file +private const val DEBUG = false diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt index 81942209a055..c4e2279afdb3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt @@ -1,6 +1,6 @@  package com.android.systemui.statusbar.notification -import android.view.View +import android.view.ViewGroup  import com.android.internal.jank.InteractionJankMonitor  import com.android.systemui.animation.ActivityLaunchAnimator  import com.android.systemui.statusbar.NotificationShadeDepthController @@ -45,7 +45,11 @@ class NotificationLaunchAnimatorController(  ) : ActivityLaunchAnimator.Controller {      private val notificationKey = notification.entry.sbn.key -    override fun getRootView(): View = notification.rootView +    override var launchContainer: ViewGroup +        get() = notification.rootView as ViewGroup +        set(ignored) { +            // Do nothing. Notifications are always animated inside their rootView. +        }      override fun createAnimatorState(): ActivityLaunchAnimator.State {          // If the notification panel is collapsed, the clip may be larger than the height. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java index d95c265c1460..d6356de5ea51 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java @@ -16,9 +16,7 @@  package com.android.systemui.statusbar.notification.collection.legacy; -import android.annotation.NonNull;  import android.annotation.Nullable; -import android.app.Notification;  import android.service.notification.StatusBarNotification;  import android.util.ArraySet;  import android.util.Log; @@ -33,7 +31,6 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry;  import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;  import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;  import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; -import com.android.systemui.statusbar.phone.StatusBar;  import com.android.systemui.statusbar.policy.HeadsUpManager;  import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;  import com.android.wm.shell.bubbles.Bubbles; @@ -42,12 +39,10 @@ import java.io.FileDescriptor;  import java.io.PrintWriter;  import java.util.ArrayList;  import java.util.HashMap; -import java.util.HashSet;  import java.util.List;  import java.util.Map;  import java.util.Objects;  import java.util.Optional; -import java.util.TreeSet;  import javax.inject.Inject; @@ -63,21 +58,13 @@ import dagger.Lazy;  public class NotificationGroupManagerLegacy implements OnHeadsUpChangedListener, StateListener,          GroupMembershipManager, GroupExpansionManager, Dumpable { -    private static final String TAG = "NotifGroupManager"; -    private static final boolean DEBUG = StatusBar.DEBUG; -    private static final boolean SPEW = StatusBar.SPEW; -    /** -     * The maximum amount of time (in ms) between the posting of notifications that can be -     * considered part of the same update batch. -     */ -    private static final long POST_BATCH_MAX_AGE = 5000; +    private static final String TAG = "NotificationGroupManager";      private final HashMap<String, NotificationGroup> mGroupMap = new HashMap<>();      private final ArraySet<OnGroupExpansionChangeListener> mExpansionChangeListeners =              new ArraySet<>();      private final ArraySet<OnGroupChangeListener> mGroupChangeListeners = new ArraySet<>();      private final Lazy<PeopleNotificationIdentifier> mPeopleNotificationIdentifier;      private final Optional<Bubbles> mBubblesOptional; -    private final EventBuffer mEventBuffer = new EventBuffer();      private int mBarState = -1;      private HashMap<String, StatusBarNotification> mIsolatedEntries = new HashMap<>();      private HeadsUpManager mHeadsUpManager; @@ -147,14 +134,8 @@ public class NotificationGroupManagerLegacy implements OnHeadsUpChangedListener,       * When we want to remove an entry from being tracked for grouping       */      public void onEntryRemoved(NotificationEntry removed) { -        if (SPEW) { -            Log.d(TAG, "onEntryRemoved: entry=" + removed); -        }          onEntryRemovedInternal(removed, removed.getSbn()); -        StatusBarNotification oldSbn = mIsolatedEntries.remove(removed.getKey()); -        if (oldSbn != null) { -            updateSuppression(mGroupMap.get(oldSbn.getGroupKey())); -        } +        mIsolatedEntries.remove(removed.getKey());      }      /** @@ -181,9 +162,6 @@ public class NotificationGroupManagerLegacy implements OnHeadsUpChangedListener,              // the close future. See b/23676310 for reference.              return;          } -        if (SPEW) { -            Log.d(TAG, "onEntryRemovedInternal: entry=" + removed + " group=" + group.groupKey); -        }          if (isGroupChild(removed.getKey(), isGroup, isGroupSummary)) {              group.children.remove(removed.getKey());          } else { @@ -204,9 +182,6 @@ public class NotificationGroupManagerLegacy implements OnHeadsUpChangedListener,       * Notify the group manager that a new entry was added       */      public void onEntryAdded(final NotificationEntry added) { -        if (SPEW) { -            Log.d(TAG, "onEntryAdded: entry=" + added); -        }          updateIsolation(added);          onEntryAddedInternal(added);      } @@ -220,16 +195,13 @@ public class NotificationGroupManagerLegacy implements OnHeadsUpChangedListener,          String groupKey = getGroupKey(sbn);          NotificationGroup group = mGroupMap.get(groupKey);          if (group == null) { -            group = new NotificationGroup(groupKey); +            group = new NotificationGroup();              mGroupMap.put(groupKey, group);              for (OnGroupChangeListener listener : mGroupChangeListeners) {                  listener.onGroupCreated(group, groupKey);              }          } -        if (SPEW) { -            Log.d(TAG, "onEntryAddedInternal: entry=" + added + " group=" + group.groupKey); -        }          if (isGroupChild) {              NotificationEntry existing = group.children.get(added.getKey());              if (existing != null && existing != added) { @@ -241,11 +213,9 @@ public class NotificationGroupManagerLegacy implements OnHeadsUpChangedListener,                          + " added removed" + added.isRowRemoved(), new Throwable());              }              group.children.put(added.getKey(), added); -            addToPostBatchHistory(group, added);              updateSuppression(group);          } else {              group.summary = added; -            addToPostBatchHistory(group, added);              group.expanded = added.areChildrenExpanded();              updateSuppression(group);              if (!group.children.isEmpty()) { @@ -261,27 +231,6 @@ public class NotificationGroupManagerLegacy implements OnHeadsUpChangedListener,          }      } -    private void addToPostBatchHistory(NotificationGroup group, @Nullable NotificationEntry entry) { -        if (entry == null) { -            return; -        } -        boolean didAdd = group.postBatchHistory.add(new PostRecord(entry)); -        if (didAdd) { -            trimPostBatchHistory(group.postBatchHistory); -        } -    } - -    /** remove all history that's too old to be in the batch. */ -    private void trimPostBatchHistory(@NonNull TreeSet<PostRecord> postBatchHistory) { -        if (postBatchHistory.size() <= 1) { -            return; -        } -        long batchStartTime = postBatchHistory.last().postTime - POST_BATCH_MAX_AGE; -        while (!postBatchHistory.isEmpty() && postBatchHistory.first().postTime < batchStartTime) { -            postBatchHistory.pollFirst(); -        } -    } -      private void onEntryBecomingChild(NotificationEntry entry) {          updateIsolation(entry);      } @@ -290,9 +239,6 @@ public class NotificationGroupManagerLegacy implements OnHeadsUpChangedListener,          if (group == null) {              return;          } -        NotificationEntry prevAlertOverride = group.alertOverride; -        group.alertOverride = getPriorityConversationAlertOverride(group); -          int childCount = 0;          boolean hasBubbles = false;          for (NotificationEntry entry : group.children.values()) { @@ -309,146 +255,16 @@ public class NotificationGroupManagerLegacy implements OnHeadsUpChangedListener,          group.suppressed = group.summary != null && !group.expanded                  && (childCount == 1                  || (childCount == 0 -                && group.summary.getSbn().getNotification().isGroupSummary() -                && (hasIsolatedChildren(group) || hasBubbles))); - -        boolean alertOverrideChanged = prevAlertOverride != group.alertOverride; -        boolean suppressionChanged = prevSuppressed != group.suppressed; -        if (alertOverrideChanged || suppressionChanged) { -            if (DEBUG && alertOverrideChanged) { -                Log.d(TAG, group + " alertOverride was=" + prevAlertOverride + " now=" -                        + group.alertOverride); -            } -            if (DEBUG && suppressionChanged) { -                Log.d(TAG, group + " suppressed changed to " + group.suppressed); -            } -            if (!mIsUpdatingUnchangedGroup) { -                if (alertOverrideChanged) { -                    mEventBuffer.notifyAlertOverrideChanged(group, prevAlertOverride); -                } -                if (suppressionChanged) { -                    for (OnGroupChangeListener listener : mGroupChangeListeners) { -                        listener.onGroupSuppressionChanged(group, group.suppressed); -                    } -                } -                mEventBuffer.notifyGroupsChanged(); -            } else { -                if (DEBUG) { -                    Log.d(TAG, group + " did not notify listeners of above change(s)"); -                } -            } -        } -    } - -    /** -     * Finds the isolated logical child of this group which is should be alerted instead. -     * -     * Notifications from priority conversations are isolated from their groups to make them more -     * prominent, however apps may post these with a GroupAlertBehavior that has the group receiving -     * the alert.  This would lead to the group alerting even though the conversation that was -     * updated was not actually a part of that group.  This method finds the best priority -     * conversation in this situation, if there is one, so they can be set as the alertOverride of -     * the group. -     * -     * @param group the group to check -     * @return the entry which should receive the alert instead of the group, if any. -     */ -    @Nullable -    private NotificationEntry getPriorityConversationAlertOverride(NotificationGroup group) { -        // GOAL: if there is a priority child which wouldn't alert based on its groupAlertBehavior, -        // but which should be alerting (because priority conversations are isolated), find it. -        if (group == null || group.summary == null) { -            if (SPEW) { -                Log.d(TAG, "getPriorityConversationAlertOverride: null group or summary"); -            } -            return null; -        } -        if (isIsolated(group.summary.getKey())) { -            if (SPEW) { -                Log.d(TAG, "getPriorityConversationAlertOverride: isolated group"); -            } -            return null; -        } - -        // Precondiions: -        // * Only necessary when all notifications in the group use GROUP_ALERT_SUMMARY -        // * Only necessary when at least one notification in the group is on a priority channel -        if (group.summary.getSbn().getNotification().getGroupAlertBehavior() -                != Notification.GROUP_ALERT_SUMMARY) { -            if (SPEW) { -                Log.d(TAG, "getPriorityConversationAlertOverride: summary != GROUP_ALERT_SUMMARY"); -            } -            return null; -        } - -        // Get the important children first, copy the keys for the final importance check, -        // then add the non-isolated children to the map for unified lookup. -        HashMap<String, NotificationEntry> children = getImportantConversations(group); -        if (children == null || children.isEmpty()) { -            if (SPEW) { -                Log.d(TAG, "getPriorityConversationAlertOverride: no important conversations"); -            } -            return null; -        } -        HashSet<String> importantChildKeys = new HashSet<>(children.keySet()); -        children.putAll(group.children); - -        // Ensure all children have GROUP_ALERT_SUMMARY -        for (NotificationEntry child : children.values()) { -            if (child.getSbn().getNotification().getGroupAlertBehavior() -                    != Notification.GROUP_ALERT_SUMMARY) { -                if (SPEW) { -                    Log.d(TAG, "getPriorityConversationAlertOverride: " -                            + "child != GROUP_ALERT_SUMMARY"); -                } -                return null; -            } -        } - -        // Create a merged post history from all the children -        TreeSet<PostRecord> combinedHistory = new TreeSet<>(group.postBatchHistory); -        for (String importantChildKey : importantChildKeys) { -            NotificationGroup importantChildGroup = mGroupMap.get(importantChildKey); -            combinedHistory.addAll(importantChildGroup.postBatchHistory); -        } -        trimPostBatchHistory(combinedHistory); - -        // This is a streamlined implementation of the following idea: -        // * From the subset of notifications in the latest 'batch' of updates.  A batch is: -        //   * Notifs posted less than POST_BATCH_MAX_AGE before the most recently posted. -        //   * Only including notifs newer than the second-to-last post of any notification. -        // * Find the newest child in the batch -- the with the largest 'when' value. -        // * If the newest child is a priority conversation, set that as the override. -        HashSet<String> batchKeys = new HashSet<>(); -        long newestChildWhen = -1; -        NotificationEntry newestChild = null; -        // Iterate backwards through the post history, tracking the child with the smallest sort key -        for (PostRecord record : combinedHistory.descendingSet()) { -            if (batchKeys.contains(record.key)) { -                // Once you see a notification again, the batch has ended -                break; -            } -            batchKeys.add(record.key); -            NotificationEntry child = children.get(record.key); -            if (child != null) { -                long childWhen = child.getSbn().getNotification().when; -                if (newestChild == null || childWhen > newestChildWhen) { -                    newestChildWhen = childWhen; -                    newestChild = child; +                        && group.summary.getSbn().getNotification().isGroupSummary() +                        && (hasIsolatedChildren(group) || hasBubbles))); +        if (prevSuppressed != group.suppressed) { +            for (OnGroupChangeListener listener : mGroupChangeListeners) { +                if (!mIsUpdatingUnchangedGroup) { +                    listener.onGroupSuppressionChanged(group, group.suppressed); +                    listener.onGroupsChanged();                  }              }          } -        if (newestChild != null && importantChildKeys.contains(newestChild.getKey())) { -            if (SPEW) { -                Log.d(TAG, "getPriorityConversationAlertOverride: result=" + newestChild); -            } -            return newestChild; -        } -        if (SPEW) { -            Log.d(TAG, "getPriorityConversationAlertOverride: result=null, newestChild=" -                    + newestChild); -        } -        return null;      }      private boolean hasIsolatedChildren(NotificationGroup group) { @@ -465,33 +281,12 @@ public class NotificationGroupManagerLegacy implements OnHeadsUpChangedListener,          return count;      } -    @Nullable -    private HashMap<String, NotificationEntry> getImportantConversations(NotificationGroup group) { -        String groupKey = group.summary.getSbn().getGroupKey(); -        HashMap<String, NotificationEntry> result = null; -        for (StatusBarNotification sbn : mIsolatedEntries.values()) { -            if (sbn.getGroupKey().equals(groupKey)) { -                NotificationEntry entry = mGroupMap.get(sbn.getKey()).summary; -                if (isImportantConversation(entry)) { -                    if (result == null) { -                        result = new HashMap<>(); -                    } -                    result.put(sbn.getKey(), entry); -                } -            } -        } -        return result; -    } -      /**       * Update an entry's group information       * @param entry notification entry to update       * @param oldNotification previous notification info before this update       */      public void onEntryUpdated(NotificationEntry entry, StatusBarNotification oldNotification) { -        if (SPEW) { -            Log.d(TAG, "onEntryUpdated: entry=" + entry); -        }          onEntryUpdated(entry, oldNotification.getGroupKey(), oldNotification.isGroup(),                  oldNotification.getNotification().isGroupSummary());      } @@ -530,17 +325,7 @@ public class NotificationGroupManagerLegacy implements OnHeadsUpChangedListener,       * Whether the given notification is the summary of a group that is being suppressed       */      public boolean isSummaryOfSuppressedGroup(StatusBarNotification sbn) { -        return sbn.getNotification().isGroupSummary() && isGroupSuppressed(getGroupKey(sbn)); -    } - -    /** -     * If the given notification is a summary, get the group for it. -     */ -    public NotificationGroup getGroupForSummary(StatusBarNotification sbn) { -        if (sbn.getNotification().isGroupSummary()) { -            return mGroupMap.get(getGroupKey(sbn)); -        } -        return null; +        return isGroupSuppressed(getGroupKey(sbn)) && sbn.getNotification().isGroupSummary();      }      private boolean isOnlyChild(StatusBarNotification sbn) { @@ -760,7 +545,9 @@ public class NotificationGroupManagerLegacy implements OnHeadsUpChangedListener,          if (!sbn.isGroup() || sbn.getNotification().isGroupSummary()) {              return false;          } -        if (isImportantConversation(entry)) { +        int peopleNotificationType = +                mPeopleNotificationIdentifier.get().getPeopleNotificationType(entry); +        if (peopleNotificationType == PeopleNotificationIdentifier.TYPE_IMPORTANT_PERSON) {              return true;          }          if (mHeadsUpManager != null && !mHeadsUpManager.isAlerting(entry.getKey())) { @@ -773,25 +560,18 @@ public class NotificationGroupManagerLegacy implements OnHeadsUpChangedListener,                      || isGroupNotFullyVisible(notificationGroup));      } -    private boolean isImportantConversation(NotificationEntry entry) { -        int peopleNotificationType = -                mPeopleNotificationIdentifier.get().getPeopleNotificationType(entry); -        return peopleNotificationType == PeopleNotificationIdentifier.TYPE_IMPORTANT_PERSON; -    } -      /**       * Isolate a notification from its group so that it visually shows as its own group.       *       * @param entry the notification to isolate       */      private void isolateNotification(NotificationEntry entry) { -        if (SPEW) { -            Log.d(TAG, "isolateNotification: entry=" + entry); -        } +        StatusBarNotification sbn = entry.getSbn(); +          // We will be isolated now, so lets update the groups          onEntryRemovedInternal(entry, entry.getSbn()); -        mIsolatedEntries.put(entry.getKey(), entry.getSbn()); +        mIsolatedEntries.put(sbn.getKey(), sbn);          onEntryAddedInternal(entry);          // We also need to update the suppression of the old group, because this call comes @@ -808,14 +588,6 @@ public class NotificationGroupManagerLegacy implements OnHeadsUpChangedListener,       * Update the isolation of an entry, splitting it from the group.       */      public void updateIsolation(NotificationEntry entry) { -        // We need to buffer a few events because we do isolation changes in 3 steps: -        // removeInternal, update mIsolatedEntries, addInternal.  This means that often the -        // alertOverride will update on the removal, however processing the event in that case can -        // cause problems because the mIsolatedEntries map is not in its final state, so the event -        // listener may be unable to correctly determine the true state of the group.  By delaying -        // the alertOverride change until after the add phase, we can ensure that listeners only -        // have to handle a consistent state. -        mEventBuffer.startBuffering();          boolean isIsolated = isIsolated(entry.getSbn().getKey());          if (shouldIsolate(entry)) {              if (!isIsolated) { @@ -824,7 +596,6 @@ public class NotificationGroupManagerLegacy implements OnHeadsUpChangedListener,          } else if (isIsolated) {              stopIsolatingNotification(entry);          } -        mEventBuffer.flushAndStopBuffering();      }      /** @@ -833,15 +604,15 @@ public class NotificationGroupManagerLegacy implements OnHeadsUpChangedListener,       * @param entry the notification to un-isolate       */      private void stopIsolatingNotification(NotificationEntry entry) { -        if (SPEW) { -            Log.d(TAG, "stopIsolatingNotification: entry=" + entry); -        } -        // not isolated anymore, we need to update the groups -        onEntryRemovedInternal(entry, entry.getSbn()); -        mIsolatedEntries.remove(entry.getKey()); -        onEntryAddedInternal(entry); -        for (OnGroupChangeListener listener : mGroupChangeListeners) { -            listener.onGroupsChanged(); +        StatusBarNotification sbn = entry.getSbn(); +        if (isIsolated(sbn.getKey())) { +            // not isolated anymore, we need to update the groups +            onEntryRemovedInternal(entry, entry.getSbn()); +            mIsolatedEntries.remove(sbn.getKey()); +            onEntryAddedInternal(entry); +            for (OnGroupChangeListener listener : mGroupChangeListeners) { +                listener.onGroupsChanged(); +            }          }      } @@ -877,154 +648,33 @@ public class NotificationGroupManagerLegacy implements OnHeadsUpChangedListener,      }      /** -     * A record of a notification being posted, containing the time of the post and the key of the -     * notification entry.  These are stored in a TreeSet by the NotificationGroup and used to -     * calculate a batch of notifications. -     */ -    public static class PostRecord implements Comparable<PostRecord> { -        public final long postTime; -        public final String key; - -        /** constructs a record containing the post time and key from the notification entry */ -        public PostRecord(@NonNull NotificationEntry entry) { -            this.postTime = entry.getSbn().getPostTime(); -            this.key = entry.getKey(); -        } - -        @Override -        public int compareTo(PostRecord o) { -            int postTimeComparison = Long.compare(this.postTime, o.postTime); -            return postTimeComparison == 0 -                    ? String.CASE_INSENSITIVE_ORDER.compare(this.key, o.key) -                    : postTimeComparison; -        } - -        @Override -        public boolean equals(Object o) { -            if (this == o) return true; -            if (o == null || getClass() != o.getClass()) return false; -            PostRecord that = (PostRecord) o; -            return postTime == that.postTime && key.equals(that.key); -        } - -        @Override -        public int hashCode() { -            return Objects.hash(postTime, key); -        } -    } - -    /**       * Represents a notification group in the notification shade.       */      public static class NotificationGroup { -        public final String groupKey;          public final HashMap<String, NotificationEntry> children = new HashMap<>(); -        public final TreeSet<PostRecord> postBatchHistory = new TreeSet<>();          public NotificationEntry summary;          public boolean expanded;          /**           * Is this notification group suppressed, i.e its summary is hidden           */          public boolean suppressed; -        /** -         * The child (which is isolated from this group) to which the alert should be transferred, -         * due to priority conversations. -         */ -        public NotificationEntry alertOverride; - -        NotificationGroup(String groupKey) { -            this.groupKey = groupKey; -        }          @Override          public String toString() { -            StringBuilder sb = new StringBuilder(); -            sb.append("    groupKey: ").append(groupKey); -            sb.append("\n    summary:"); -            appendEntry(sb, summary); -            sb.append("\n    children size: ").append(children.size()); +            String result = "    summary:\n      " +                    + (summary != null ? summary.getSbn() : "null") +                    + (summary != null && summary.getDebugThrowable() != null +                            ? Log.getStackTraceString(summary.getDebugThrowable()) +                            : ""); +            result += "\n    children size: " + children.size();              for (NotificationEntry child : children.values()) { -                appendEntry(sb, child); -            } -            sb.append("\n    alertOverride:"); -            appendEntry(sb, alertOverride); -            sb.append("\n    summary suppressed: ").append(suppressed); -            return sb.toString(); -        } - -        private void appendEntry(StringBuilder sb, NotificationEntry entry) { -            sb.append("\n      ").append(entry != null ? entry.getSbn() : "null"); -            if (entry != null && entry.getDebugThrowable() != null) { -                sb.append(Log.getStackTraceString(entry.getDebugThrowable())); -            } -        } -    } - -    /** -     * This class is a toggleable buffer for a subset of events of {@link OnGroupChangeListener}. -     * When buffering, instead of notifying the listeners it will set internal state that will allow -     * it to notify listeners of those events later -     */ -    private class EventBuffer { -        private final HashMap<String, NotificationEntry> mOldAlertOverrideByGroup = new HashMap<>(); -        private boolean mIsBuffering = false; -        private boolean mDidGroupsChange = false; - -        void notifyAlertOverrideChanged(NotificationGroup group, -                NotificationEntry oldAlertOverride) { -            if (mIsBuffering) { -                // The value in this map is the override before the event.  If there is an entry -                // already in the map, then we are effectively coalescing two events, which means -                // we need to preserve the original initial value. -                mOldAlertOverrideByGroup.putIfAbsent(group.groupKey, oldAlertOverride); -            } else { -                for (OnGroupChangeListener listener : mGroupChangeListeners) { -                    listener.onGroupAlertOverrideChanged(group, oldAlertOverride, -                            group.alertOverride); -                } -            } -        } - -        void notifyGroupsChanged() { -            if (mIsBuffering) { -                mDidGroupsChange = true; -            } else { -                for (OnGroupChangeListener listener : mGroupChangeListeners) { -                    listener.onGroupsChanged(); -                } -            } -        } - -        void startBuffering() { -            mIsBuffering = true; -        } - -        void flushAndStopBuffering() { -            // stop buffering so that we can call our own helpers -            mIsBuffering = false; -            // alert all group alert override changes for groups that were not removed -            for (Map.Entry<String, NotificationEntry> entry : mOldAlertOverrideByGroup.entrySet()) { -                NotificationGroup group = mGroupMap.get(entry.getKey()); -                if (group == null) { -                    // The group can be null if this alertOverride changed before the group was -                    // permanently removed, meaning that there's no guarantee that listeners will -                    // that field clear. -                    continue; -                } -                NotificationEntry oldAlertOverride = entry.getValue(); -                if (group.alertOverride == oldAlertOverride) { -                    // If the final alertOverride equals the initial, it means we coalesced two -                    // events which undid the change, so we can drop it entirely. -                    continue; -                } -                notifyAlertOverrideChanged(group, oldAlertOverride); -            } -            mOldAlertOverrideByGroup.clear(); -            // alert that groups changed -            if (mDidGroupsChange) { -                notifyGroupsChanged(); -                mDidGroupsChange = false; +                result += "\n      " + child.getSbn() +                        + (child.getDebugThrowable() != null +                            ? Log.getStackTraceString(child.getDebugThrowable()) +                            : "");              } +            result += "\n    summary suppressed: " + suppressed; +            return result;          }      } @@ -1064,18 +714,6 @@ public class NotificationGroupManagerLegacy implements OnHeadsUpChangedListener,                  boolean suppressed) {}          /** -         * The alert override of a group has changed. -         * -         * @param group the group that has changed -         * @param oldAlertOverride the previous notification to which the group's alerts were sent -         * @param newAlertOverride the notification to which the group's alerts should now be sent -         */ -        default void onGroupAlertOverrideChanged( -                NotificationGroup group, -                @Nullable NotificationEntry oldAlertOverride, -                @Nullable NotificationEntry newAlertOverride) {} - -        /**           * A group of children just received a summary notification and should therefore become           * children of it.           * diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java index 617dadb42594..e2a37f647bf5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java @@ -69,7 +69,6 @@ import com.android.systemui.statusbar.notification.logging.NotificationPanelLogg  import com.android.systemui.statusbar.notification.row.ChannelEditorDialogController;  import com.android.systemui.statusbar.notification.row.NotificationGutsManager;  import com.android.systemui.statusbar.notification.row.OnUserInteractionCallback; -import com.android.systemui.statusbar.notification.row.PriorityOnboardingDialogController;  import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager;  import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm;  import com.android.systemui.statusbar.phone.ShadeController; @@ -141,7 +140,6 @@ public interface NotificationsModule {              ShortcutManager shortcutManager,              ChannelEditorDialogController channelEditorDialogController,              UserContextProvider contextTracker, -            Provider<PriorityOnboardingDialogController.Builder> builderProvider,              AssistantFeedbackController assistantFeedbackController,              Optional<BubblesManager> bubblesManagerOptional,              UiEventLogger uiEventLogger, @@ -161,7 +159,6 @@ public interface NotificationsModule {                  shortcutManager,                  channelEditorDialogController,                  contextTracker, -                builderProvider,                  assistantFeedbackController,                  bubblesManagerOptional,                  uiEventLogger, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java index 40be4bfa47dc..1f4f3caea517 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java @@ -22,6 +22,8 @@ import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED;  import static android.app.NotificationManager.IMPORTANCE_DEFAULT;  import static android.app.NotificationManager.IMPORTANCE_LOW;  import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED; +import static android.app.NotificationManager.Policy.CONVERSATION_SENDERS_ANYONE; +import static android.app.NotificationManager.Policy.CONVERSATION_SENDERS_IMPORTANT;  import static com.android.systemui.animation.Interpolators.FAST_OUT_SLOW_IN; @@ -34,7 +36,6 @@ import android.app.INotificationManager;  import android.app.Notification;  import android.app.NotificationChannel;  import android.app.NotificationChannelGroup; -import android.app.NotificationManager;  import android.content.Context;  import android.content.Intent;  import android.content.pm.ApplicationInfo; @@ -55,7 +56,6 @@ import android.transition.TransitionManager;  import android.transition.TransitionSet;  import android.util.AttributeSet;  import android.util.Log; -import android.view.LayoutInflater;  import android.view.View;  import android.view.accessibility.AccessibilityEvent;  import android.widget.ImageView; @@ -64,7 +64,6 @@ import android.widget.TextView;  import com.android.internal.annotations.VisibleForTesting;  import com.android.settingslib.notification.ConversationIconFactory; -import com.android.systemui.Prefs;  import com.android.systemui.R;  import com.android.systemui.dagger.qualifiers.Background;  import com.android.systemui.dagger.qualifiers.Main; @@ -78,8 +77,6 @@ import com.android.systemui.wmshell.BubblesManager;  import java.lang.annotation.Retention;  import java.util.Optional; -import javax.inject.Provider; -  /**   * The guts of a conversation notification revealed when performing a long press.   */ @@ -107,7 +104,6 @@ public class NotificationConversationInfo extends LinearLayout implements      private StatusBarNotification mSbn;      @Nullable private Notification.BubbleMetadata mBubbleMetadata;      private Context mUserContext; -    private Provider<PriorityOnboardingDialogController.Builder> mBuilderProvider;      private boolean mIsDeviceProvisioned;      private int mAppBubble; @@ -172,13 +168,9 @@ public class NotificationConversationInfo extends LinearLayout implements      private OnClickListener mOnDone = v -> {          mPressedApply = true; -        // If the user selected Priority, maybe show the priority onboarding.          // If the user selected Priority and the previous selection was not priority, show a -        // People Tile add request. If showing the priority onboarding, however, delay the request -        // to when the onboarding dialog closes. -        if (mSelectedAction == ACTION_FAVORITE && shouldShowPriorityOnboarding()) { -            showPriorityOnboarding(); -        } else if (mSelectedAction == ACTION_FAVORITE && getPriority() != mSelectedAction) { +        // People Tile add request. +        if (mSelectedAction == ACTION_FAVORITE && getPriority() != mSelectedAction) {              mShadeController.animateCollapsePanels();              mPeopleSpaceWidgetManager.requestPinAppWidget(mShortcutInfo, new Bundle());          } @@ -229,7 +221,6 @@ public class NotificationConversationInfo extends LinearLayout implements              OnSnoozeClickListener onSnoozeClickListener,              ConversationIconFactory conversationIconFactory,              Context userContext, -            Provider<PriorityOnboardingDialogController.Builder> builderProvider,              boolean isDeviceProvisioned,              @Main Handler mainHandler,              @Background Handler bgHandler, @@ -258,7 +249,6 @@ public class NotificationConversationInfo extends LinearLayout implements          mBubbleMetadata = bubbleMetadata;          mBubblesManagerOptional = bubblesManagerOptional;          mShadeController = shadeController; -        mBuilderProvider = builderProvider;          mMainHandler = mainHandler;          mBgHandler = bgHandler;          mShortcutManager = shortcutManager; @@ -342,6 +332,18 @@ public class NotificationConversationInfo extends LinearLayout implements          // bindName();          bindPackage();          bindIcon(mNotificationChannel.isImportantConversation()); + +        mPriorityDescriptionView = findViewById(R.id.priority_summary); +        if (willShowAsBubble() && willBypassDnd()) { +            mPriorityDescriptionView.setText(R.string.notification_channel_summary_priority_all); +        } else if (willShowAsBubble()) { +            mPriorityDescriptionView.setText(R.string.notification_channel_summary_priority_bubble); +        } else if (willBypassDnd()) { +            mPriorityDescriptionView.setText(R.string.notification_channel_summary_priority_dnd); +        } else { +            mPriorityDescriptionView.setText( +                    R.string.notification_channel_summary_priority_baseline); +        }      }      private void bindIcon(boolean important) { @@ -428,7 +430,6 @@ public class NotificationConversationInfo extends LinearLayout implements      protected void onFinishInflate() {          super.onFinishInflate(); -        mPriorityDescriptionView = findViewById(R.id.priority_summary);          mDefaultDescriptionView = findViewById(R.id.default_summary);          mSilentDescriptionView = findViewById(R.id.silence_summary);      } @@ -552,51 +553,22 @@ public class NotificationConversationInfo extends LinearLayout implements                  StackStateAnimator.ANIMATION_DURATION_STANDARD);      } -    private boolean shouldShowPriorityOnboarding() { -        return !Prefs.getBoolean(mUserContext, Prefs.Key.HAS_SEEN_PRIORITY_ONBOARDING_IN_S, false); -    } - -    private void showPriorityOnboarding() { -        View onboardingView = LayoutInflater.from(mContext) -                .inflate(R.layout.priority_onboarding_half_shell, null); - -        boolean ignoreDnd = false; +    private boolean willBypassDnd() { +        boolean bypassesDnd = false;          try { -            ignoreDnd = mINotificationManager -                    .getConsolidatedNotificationPolicy().priorityConversationSenders == -                    NotificationManager.Policy.CONVERSATION_SENDERS_IMPORTANT; +            int allowedSenders = mINotificationManager +                    .getConsolidatedNotificationPolicy().priorityConversationSenders; +            bypassesDnd =  allowedSenders == CONVERSATION_SENDERS_IMPORTANT +                    || allowedSenders == CONVERSATION_SENDERS_ANYONE;          } catch (RemoteException e) {              Log.e(TAG, "Could not check conversation senders", e);          } +        return bypassesDnd; +    } -        boolean showAsBubble = mBubbleMetadata != null -                && mBubbleMetadata.getAutoExpandBubble() +    private boolean willShowAsBubble() { +        return mBubbleMetadata != null                  && BubblesManager.areBubblesEnabled(mContext, mSbn.getUser()); - -        Drawable person =  mIconFactory.getBaseIconDrawable(mShortcutInfo); -        if (person == null) { -            person = mContext.getDrawable(R.drawable.ic_person).mutate(); -            TypedArray ta = mContext.obtainStyledAttributes(new int[]{android.R.attr.colorAccent}); -            int colorAccent = ta.getColor(0, 0); -            ta.recycle(); -            person.setTint(colorAccent); -        } - -        PriorityOnboardingDialogController controller = mBuilderProvider.get() -                .setContext(mUserContext) -                .setView(onboardingView) -                .setIgnoresDnd(ignoreDnd) -                .setShowsAsBubble(showAsBubble) -                .setIcon(person) -                .setBadge(mIconFactory.getAppBadge( -                        mPackageName, UserHandle.getUserId(mSbn.getUid()))) -                .setOnSettingsClick(mOnConversationSettingsClickListener) -                .setPeopleSpaceWidgetManager(mPeopleSpaceWidgetManager) -                .setShadeController(mShadeController) -                .build(); - -        controller.init(mShortcutInfo); -        controller.show();      }      @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java index 1a7f5b0bf5af..59b88a53b45e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java @@ -129,7 +129,6 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx      private final LauncherApps mLauncherApps;      private final ShortcutManager mShortcutManager;      private final UserContextProvider mContextTracker; -    private final Provider<PriorityOnboardingDialogController.Builder> mBuilderProvider;      private final UiEventLogger mUiEventLogger;      private final ShadeController mShadeController;      private final AppWidgetManager mAppWidgetManager; @@ -150,7 +149,6 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx              ShortcutManager shortcutManager,              ChannelEditorDialogController channelEditorDialogController,              UserContextProvider contextTracker, -            Provider<PriorityOnboardingDialogController.Builder> builderProvider,              AssistantFeedbackController assistantFeedbackController,              Optional<BubblesManager> bubblesManagerOptional,              UiEventLogger uiEventLogger, @@ -168,7 +166,6 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx          mLauncherApps = launcherApps;          mShortcutManager = shortcutManager;          mContextTracker = contextTracker; -        mBuilderProvider = builderProvider;          mChannelEditorDialogController = channelEditorDialogController;          mAssistantFeedbackController = assistantFeedbackController;          mBubblesManagerOptional = bubblesManagerOptional; @@ -503,7 +500,6 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx                  onSnoozeClickListener,                  iconFactoryLoader,                  mContextTracker.getUserContext(), -                mBuilderProvider,                  mDeviceProvisionedController.isDeviceProvisioned(),                  mMainHandler,                  mBgHandler, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PriorityOnboardingDialogController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PriorityOnboardingDialogController.kt deleted file mode 100644 index 270721ffa4b8..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PriorityOnboardingDialogController.kt +++ /dev/null @@ -1,291 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - *      http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.statusbar.notification.row - -import android.animation.Animator -import android.animation.AnimatorListenerAdapter -import android.animation.AnimatorSet -import android.animation.ValueAnimator -import android.app.Dialog -import android.content.Context -import android.content.pm.ShortcutInfo -import android.graphics.Color -import android.graphics.PixelFormat -import android.graphics.drawable.ColorDrawable -import android.graphics.drawable.Drawable -import android.graphics.drawable.GradientDrawable -import android.os.Bundle -import android.text.SpannableStringBuilder -import android.text.style.BulletSpan -import android.view.Gravity -import android.view.View -import android.view.ViewGroup.LayoutParams.MATCH_PARENT -import android.view.ViewGroup.LayoutParams.WRAP_CONTENT -import android.view.Window -import android.view.WindowInsets.Type.statusBars -import android.view.WindowManager -import android.view.animation.Interpolator -import android.view.animation.PathInterpolator -import android.widget.ImageView -import android.widget.TextView -import com.android.systemui.Prefs -import com.android.systemui.R -import com.android.systemui.animation.Interpolators.LINEAR_OUT_SLOW_IN -import com.android.systemui.people.widget.PeopleSpaceWidgetManager -import com.android.systemui.statusbar.notification.row.NotificationConversationInfo.OnConversationSettingsClickListener -import com.android.systemui.statusbar.phone.ShadeController -import javax.inject.Inject - -/** - * Controller to handle presenting the priority conversations onboarding dialog - */ -class PriorityOnboardingDialogController @Inject constructor( -    val view: View, -    val context: Context, -    private val ignoresDnd: Boolean, -    private val showsAsBubble: Boolean, -    val icon: Drawable, -    private val onConversationSettingsClickListener: OnConversationSettingsClickListener, -    val badge: Drawable, -    private val peopleSpaceWidgetManager: PeopleSpaceWidgetManager, -    private val shadeController: ShadeController -) { - -    private lateinit var dialog: Dialog -    private lateinit var shortcutInfo: ShortcutInfo -    private val OVERSHOOT: Interpolator = PathInterpolator(0.4f, 0f, 0.2f, 1.4f) -    private val IMPORTANCE_ANIM_DELAY = 150L -    private val IMPORTANCE_ANIM_GROW_DURATION = 250L -    private val IMPORTANCE_ANIM_SHRINK_DURATION = 200L -    private val IMPORTANCE_ANIM_SHRINK_DELAY = 25L - -    fun init(info: ShortcutInfo) { -        shortcutInfo = info -        initDialog() -    } - -    fun show() { -        dialog.show() -    } - -    private fun done() { -        // Log that the user has seen the onboarding -        Prefs.putBoolean(context, Prefs.Key.HAS_SEEN_PRIORITY_ONBOARDING_IN_S, true) -        dialog.dismiss() -        shadeController.animateCollapsePanels() -        peopleSpaceWidgetManager.requestPinAppWidget(shortcutInfo, Bundle()) -    } - -    private fun settings() { -        // Log that the user has seen the onboarding -        Prefs.putBoolean(context, Prefs.Key.HAS_SEEN_PRIORITY_ONBOARDING_IN_S, true) -        dialog.dismiss() -        onConversationSettingsClickListener?.onClick() -    } - -    class Builder @Inject constructor() { -        private lateinit var view: View -        private lateinit var context: Context -        private var ignoresDnd = false -        private var showAsBubble = false -        private lateinit var icon: Drawable -        private lateinit var onConversationSettingsClickListener: -                OnConversationSettingsClickListener -        private lateinit var badge: Drawable -        private lateinit var peopleSpaceWidgetManager: PeopleSpaceWidgetManager -        private lateinit var shadeController: ShadeController - -        fun setView(v: View): Builder { -            view = v -            return this -        } - -        fun setContext(c: Context): Builder { -            context = c -            return this -        } - -        fun setIgnoresDnd(ignore: Boolean): Builder { -            ignoresDnd = ignore -            return this -        } - -        fun setShowsAsBubble(bubble: Boolean): Builder { -            showAsBubble = bubble -            return this -        } - -        fun setIcon(draw: Drawable): Builder { -            icon = draw -            return this -        } -        fun setBadge(badge: Drawable): Builder { -            this.badge = badge -            return this -        } - -        fun setOnSettingsClick(onClick: OnConversationSettingsClickListener): Builder { -            onConversationSettingsClickListener = onClick -            return this -        } - -        fun setShadeController(shadeController: ShadeController): Builder { -            this.shadeController = shadeController -            return this -        } - -        fun setPeopleSpaceWidgetManager(peopleSpaceWidgetManager: PeopleSpaceWidgetManager): -                Builder { -            this.peopleSpaceWidgetManager = peopleSpaceWidgetManager -            return this -        } - -        fun build(): PriorityOnboardingDialogController { -            val controller = PriorityOnboardingDialogController( -                    view, context, ignoresDnd, showAsBubble, icon, -                    onConversationSettingsClickListener, badge, peopleSpaceWidgetManager, -                    shadeController) -            return controller -        } -    } - -    private fun initDialog() { -        dialog = Dialog(context) - -        if (dialog.window == null) { -            throw IllegalStateException("Need a window for the onboarding dialog to show") -        } - -        dialog.window?.requestFeature(Window.FEATURE_NO_TITLE) -        // Prevent a11y readers from reading the first element in the dialog twice -        dialog.setTitle("\u00A0") -        dialog.apply { -            setContentView(view) -            setCanceledOnTouchOutside(true) - -            findViewById<TextView>(R.id.done_button)?.setOnClickListener { -                done() -            } - -            findViewById<TextView>(R.id.settings_button)?.setOnClickListener { -                settings() -            } - -            findViewById<ImageView>(R.id.conversation_icon)?.setImageDrawable(icon) -            findViewById<ImageView>(R.id.icon)?.setImageDrawable(badge) -            val mImportanceRingView = findViewById<ImageView>(R.id.conversation_icon_badge_ring) -            val conversationIconBadgeBg = findViewById<ImageView>(R.id.conversation_icon_badge_bg) - -            val ring: GradientDrawable = mImportanceRingView.drawable as GradientDrawable -            ring.mutate() -            val bg = conversationIconBadgeBg.drawable as GradientDrawable -            bg.mutate() -            val ringColor = context.getResources() -                    .getColor(com.android.internal.R.color.conversation_important_highlight) -            val standardThickness = context.resources.getDimensionPixelSize( -                    com.android.internal.R.dimen.importance_ring_stroke_width) -            val largeThickness = context.resources.getDimensionPixelSize( -                    com.android.internal.R.dimen.importance_ring_anim_max_stroke_width) -            val standardSize = context.resources.getDimensionPixelSize( -                    com.android.internal.R.dimen.importance_ring_size) -            val baseSize = standardSize - standardThickness * 2 -            val largeSize = baseSize + largeThickness * 2 -            val bgSize = context.resources.getDimensionPixelSize( -                    com.android.internal.R.dimen.conversation_icon_size_badged) - -            val animatorUpdateListener: ValueAnimator.AnimatorUpdateListener = -                    ValueAnimator.AnimatorUpdateListener { animation -> -                val strokeWidth = animation.animatedValue as Int -                ring.setStroke(strokeWidth, ringColor) -                val newSize = baseSize + strokeWidth * 2 -                ring.setSize(newSize, newSize) -                mImportanceRingView.invalidate() -            } - -            val growAnimation: ValueAnimator = ValueAnimator.ofInt(0, largeThickness) -            growAnimation.interpolator = LINEAR_OUT_SLOW_IN -            growAnimation.duration = IMPORTANCE_ANIM_GROW_DURATION -            growAnimation.addUpdateListener(animatorUpdateListener) - -            val shrinkAnimation: ValueAnimator = -                    ValueAnimator.ofInt(largeThickness, standardThickness) -            shrinkAnimation.duration = IMPORTANCE_ANIM_SHRINK_DURATION -            shrinkAnimation.startDelay = IMPORTANCE_ANIM_SHRINK_DELAY -            shrinkAnimation.interpolator = OVERSHOOT -            shrinkAnimation.addUpdateListener(animatorUpdateListener) -            shrinkAnimation.addListener(object : AnimatorListenerAdapter() { -                override fun onAnimationStart(animation: Animator?) { -                    // Shrink the badge bg so that it doesn't peek behind the animation -                    bg.setSize(baseSize, baseSize) -                    conversationIconBadgeBg.invalidate() -                } - -                override fun onAnimationEnd(animation: Animator?) { -                    // Reset bg back to normal size -                    bg.setSize(bgSize, bgSize) -                    conversationIconBadgeBg.invalidate() -                } -            }) - -            val anims = AnimatorSet() -            anims.startDelay = IMPORTANCE_ANIM_DELAY -            anims.playSequentially(growAnimation, shrinkAnimation) - -            val gapWidth = dialog.context.getResources().getDimensionPixelSize( -                    R.dimen.conversation_onboarding_bullet_gap_width) -            val description = SpannableStringBuilder() -            description.append(context.getText(R.string.priority_onboarding_show_at_top_text), -                    BulletSpan(gapWidth), /* flags */0) -            description.append(System.lineSeparator()) -            description.append(context.getText(R.string.priority_onboarding_show_avatar_text), -                    BulletSpan(gapWidth), /* flags */0) -            if (showsAsBubble) { -                description.append(System.lineSeparator()) -                description.append(context.getText( -                        R.string.priority_onboarding_appear_as_bubble_text), -                        BulletSpan(gapWidth), /* flags */0) -            } -            if (ignoresDnd) { -                description.append(System.lineSeparator()) -                description.append(context.getText(R.string.priority_onboarding_ignores_dnd_text), -                        BulletSpan(gapWidth), /* flags */0) -            } -            findViewById<TextView>(R.id.behaviors).setText(description) - -            window?.apply { -                setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) -                addFlags(wmFlags) -                setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL) -                setWindowAnimations(com.android.internal.R.style.Animation_InputMethod) - -                attributes = attributes.apply { -                    format = PixelFormat.TRANSLUCENT -                    title = PriorityOnboardingDialogController::class.java.simpleName -                    gravity = Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL -                    fitInsetsTypes = attributes.fitInsetsTypes and statusBars().inv() -                    width = MATCH_PARENT -                    height = WRAP_CONTENT -                } -            } -            anims.start() -        } -    } - -    private val wmFlags = (WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS -            or WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH -            or WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index b81619317b95..506d8a185adc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -1000,7 +1000,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable          mAmbientState.setCurrentScrollVelocity(mScroller.isFinished()                  ? 0                  : mScroller.getCurrVelocity()); -        mAmbientState.setScrollY(mOwnScrollY);          mStackScrollAlgorithm.resetViewStates(mAmbientState, getSpeedBumpIndex());          if (!isCurrentlyAnimating() && !mNeedsAnimation) {              applyCurrentState(); @@ -1143,16 +1142,18 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable       */      private void updateStackPosition() {          // Consider interpolating from an mExpansionStartY for use on lockscreen and AOD -        final float stackY = MathUtils.lerp(0, mTopPadding, mAmbientState.getExpansionFraction()); +        final float fraction = mAmbientState.getExpansionFraction(); +        final float stackY = MathUtils.lerp(0, mTopPadding, fraction);          mAmbientState.setStackY(stackY);          if (mOnStackYChanged != null) {              mOnStackYChanged.run();          } -        final float shadeBottom = getHeight() - getEmptyBottomMargin(); -        mAmbientState.setStackEndHeight(shadeBottom - mTopPadding); +        final float stackEndHeight = getHeight() - getEmptyBottomMargin() - mTopPadding; +        mAmbientState.setStackEndHeight(stackEndHeight);          mAmbientState.setStackHeight( -                MathUtils.lerp(0, shadeBottom - mTopPadding, mAmbientState.getExpansionFraction())); +                MathUtils.lerp(stackEndHeight * StackScrollAlgorithm.START_FRACTION, +                        stackEndHeight, fraction));      }      void setOnStackYChanged(Runnable onStackYChanged) { @@ -2439,18 +2440,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable      }      @ShadeViewRefactor(RefactorComponent.COORDINATOR) -    public int getPeekHeight() { -        final ExpandableView firstChild = getFirstChildNotGone(); -        final int firstChildMinHeight = firstChild != null ? firstChild.getCollapsedHeight() -                : mCollapsedSize; -        int shelfHeight = 0; -        if (getLastVisibleSection() != null && mShelf.getVisibility() != GONE) { -            shelfHeight = mShelf.getIntrinsicHeight(); -        } -        return mIntrinsicPadding + firstChildMinHeight + shelfHeight; -    } - -    @ShadeViewRefactor(RefactorComponent.COORDINATOR)      private int clampPadding(int desiredPadding) {          return Math.max(desiredPadding, mIntrinsicPadding);      } @@ -4542,7 +4531,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable              // We still want to call the normal scrolled changed for accessibility reasons              onScrollChanged(mScrollX, ownScrollY, mScrollX, mOwnScrollY);              mOwnScrollY = ownScrollY; -            updateChildren(); +            mAmbientState.setScrollY(mOwnScrollY);              updateOnScrollChange();              updateStackPosition();          } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java index b039df3f32af..f7eb574feac3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java @@ -1061,10 +1061,6 @@ public class NotificationStackScrollLayoutController {          mView.setUnlockHintRunning(running);      } -    public float getPeekHeight() { -        return mView.getPeekHeight(); -    } -      public boolean isFooterViewNotGone() {          return mView.isFooterViewNotGone();      } 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 7d586ba3cbce..413048d6ce54 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 @@ -42,6 +42,8 @@ import java.util.List;   */  public class StackScrollAlgorithm { +    public static final float START_FRACTION = 0.3f; +      private static final String LOG_TAG = "StackScrollAlgorithm";      private final ViewGroup mHostView; @@ -400,10 +402,14 @@ public class StackScrollAlgorithm {          }          if (view instanceof FooterView) { -            viewState.yTranslation = Math.min(viewState.yTranslation, -                    ambientState.getStackHeight()); -            // Hide footer if shelf is showing -            viewState.hidden = algorithmState.firstViewInShelf != null; +            final boolean isShelfShowing = algorithmState.firstViewInShelf != null; + +            final float footerEnd = viewState.yTranslation + view.getIntrinsicHeight(); +            final boolean noSpaceForFooter = footerEnd > ambientState.getStackHeight(); + +            viewState.hidden = isShelfShowing +                    || (!ambientState.isExpansionChanging() && noSpaceForFooter); +          } else if (view != ambientState.getTrackedHeadsUpRow()) {              if (ambientState.isExpansionChanging()) {                  // Show all views. Views below the shelf will later be clipped (essentially hidden) @@ -438,7 +444,8 @@ public class StackScrollAlgorithm {                      maxViewHeight = algorithmState.viewHeightBeforeShelf;                  }              } -            viewState.height = (int) MathUtils.lerp(0, maxViewHeight, expansionFraction); +            viewState.height = (int) MathUtils.lerp(maxViewHeight * START_FRACTION, maxViewHeight, +                    expansionFraction);          }          currentYPosition += viewState.height + expansionFraction * mPaddingBetweenElements; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java index 76657ad5ab07..16bed6f3f38d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java @@ -43,7 +43,6 @@ import com.android.systemui.animation.Interpolators;  import com.android.systemui.plugins.statusbar.StatusBarStateController;  import com.android.systemui.statusbar.CommandQueue;  import com.android.systemui.statusbar.StatusBarState; -import com.android.systemui.statusbar.events.PrivacyDotViewController;  import com.android.systemui.statusbar.events.SystemStatusAnimationCallback;  import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;  import com.android.systemui.statusbar.phone.StatusBarIconController.DarkIconManager; @@ -92,7 +91,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue      private CommandQueue mCommandQueue;      private OngoingCallController mOngoingCallController;      private final SystemStatusAnimationScheduler mAnimationScheduler; -    private final PrivacyDotViewController mDotViewController; +    private final StatusBarLocationPublisher mLocationPublisher;      private NotificationIconAreaController mNotificationIconAreaController;      private List<String> mBlockedIcons = new ArrayList<>(); @@ -120,12 +119,12 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue      public CollapsedStatusBarFragment(              OngoingCallController ongoingCallController,              SystemStatusAnimationScheduler animationScheduler, -            PrivacyDotViewController dotViewController, +            StatusBarLocationPublisher locationPublisher,              NotificationIconAreaController notificationIconAreaController      ) {          mOngoingCallController = ongoingCallController;          mAnimationScheduler = animationScheduler; -        mDotViewController = dotViewController; +        mLocationPublisher = locationPublisher;          mNotificationIconAreaController = notificationIconAreaController;      } @@ -540,7 +539,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue          int leftMargin = left - mStatusBar.getLeft();          int rightMargin = mStatusBar.getRight() - right; -        mDotViewController.setStatusBarMargins(leftMargin, rightMargin); +        mLocationPublisher.updateStatusBarMargin(leftMargin, rightMargin);      }      // Listen for view end changes of PhoneStatusBarView and publish that to the privacy dot diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java index 0b747f94e935..42f301d2f222 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java @@ -118,7 +118,6 @@ public class HeadsUpTouchHelper implements Gefingerpoken {                      mPanel.setPanelScrimMinFraction(maxPanelHeight > 0f                              ? (float) startHeight / maxPanelHeight : 0f);                      mPanel.startExpandMotion(x, y, true /* startTracking */, startHeight); -                    mPanel.startExpandingFromPeek();                      // This call needs to be after the expansion start otherwise we will get a                      // flicker of one frame as it's not expanded yet.                      mHeadsUpManager.unpinAll(true); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java index 9787a9446019..3181f520dca2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java @@ -22,12 +22,12 @@ import android.app.Notification;  import android.os.SystemClock;  import android.service.notification.StatusBarNotification;  import android.util.ArrayMap; -import android.util.Log;  import com.android.internal.statusbar.NotificationVisibility;  import com.android.systemui.Dependency;  import com.android.systemui.plugins.statusbar.StatusBarStateController;  import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; +import com.android.systemui.statusbar.AlertingNotificationManager;  import com.android.systemui.statusbar.notification.NotificationEntryListener;  import com.android.systemui.statusbar.notification.NotificationEntryManager;  import com.android.systemui.statusbar.notification.collection.NotificationEntry; @@ -41,21 +41,17 @@ import com.android.systemui.statusbar.policy.HeadsUpManager;  import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;  import java.util.ArrayList; -import java.util.List;  import java.util.Objects;  /**   * A helper class dealing with the alert interactions between {@link NotificationGroupManagerLegacy}   * and {@link HeadsUpManager}. In particular, this class deals with keeping - * the correct notification in a group alerting based off the group suppression and alertOverride. + * the correct notification in a group alerting based off the group suppression.   */  public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedListener,          StateListener {      private static final long ALERT_TRANSFER_TIMEOUT = 300; -    private static final String TAG = "NotifGroupAlertTransfer"; -    private static final boolean DEBUG = StatusBar.DEBUG; -    private static final boolean SPEW = StatusBar.SPEW;      /**       * The list of entries containing group alert metadata for each group. Keyed by group key. @@ -146,98 +142,41 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis          @Override          public void onGroupSuppressionChanged(NotificationGroup group, boolean suppressed) { -            if (DEBUG) { -                Log.d(TAG, "!! onGroupSuppressionChanged: group.summary=" + group.summary -                        + " suppressed=" + suppressed); -            } -            NotificationEntry oldAlertOverride = group.alertOverride; -            onGroupChanged(group, oldAlertOverride); -        } - -        @Override -        public void onGroupAlertOverrideChanged(NotificationGroup group, -                @Nullable NotificationEntry oldAlertOverride, -                @Nullable NotificationEntry newAlertOverride) { -            if (DEBUG) { -                Log.d(TAG, "!! onGroupAlertOverrideChanged: group.summary=" + group.summary -                        + " oldAlertOverride=" + oldAlertOverride -                        + " newAlertOverride=" + newAlertOverride); -            } -            onGroupChanged(group, oldAlertOverride); -        } -    }; - -    /** -     * Called when either the suppressed or alertOverride fields of the group changed -     * -     * @param group the group which changed -     * @param oldAlertOverride the previous value of group.alertOverride -     */ -    private void onGroupChanged(NotificationGroup group, -            NotificationEntry oldAlertOverride) { -        // Group summary can be null if we are no longer suppressed because the summary was -        // removed. In that case, we don't need to alert the summary. -        if (group.summary == null) { -            if (DEBUG) { -                Log.d(TAG, "onGroupChanged: summary is null"); -            } -            return; -        } -        if (group.suppressed || group.alertOverride != null) { -            checkForForwardAlertTransfer(group.summary, oldAlertOverride); -        } else { -            if (DEBUG) { -                Log.d(TAG, "onGroupChanged: maybe transfer back"); -            } -            GroupAlertEntry groupAlertEntry = mGroupAlertEntries.get(mGroupManager.getGroupKey( -                    group.summary.getSbn())); -            // Group is no longer suppressed or overridden. -            // We should check if we need to transfer the alert back to the summary. -            if (groupAlertEntry.mAlertSummaryOnNextAddition) { -                if (!mHeadsUpManager.isAlerting(group.summary.getKey())) { -                    alertNotificationWhenPossible(group.summary); +            if (suppressed) { +                if (mHeadsUpManager.isAlerting(group.summary.getKey())) { +                    handleSuppressedSummaryAlerted(group.summary, mHeadsUpManager);                  } -                groupAlertEntry.mAlertSummaryOnNextAddition = false;              } else { -                checkShouldTransferBack(groupAlertEntry); +                // Group summary can be null if we are no longer suppressed because the summary was +                // removed. In that case, we don't need to alert the summary. +                if (group.summary == null) { +                    return; +                } +                GroupAlertEntry groupAlertEntry = mGroupAlertEntries.get(mGroupManager.getGroupKey( +                        group.summary.getSbn())); +                // Group is no longer suppressed. We should check if we need to transfer the alert +                // back to the summary now that it's no longer suppressed. +                if (groupAlertEntry.mAlertSummaryOnNextAddition) { +                    if (!mHeadsUpManager.isAlerting(group.summary.getKey())) { +                        alertNotificationWhenPossible(group.summary, mHeadsUpManager); +                    } +                    groupAlertEntry.mAlertSummaryOnNextAddition = false; +                } else { +                    checkShouldTransferBack(groupAlertEntry); +                }              }          } -    } +    };      @Override      public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) { -        if (DEBUG) { -            Log.d(TAG, "!! onHeadsUpStateChanged: entry=" + entry + " isHeadsUp=" + isHeadsUp); -        } -        if (isHeadsUp && entry.getSbn().getNotification().isGroupSummary()) { -            // a group summary is alerting; trigger the forward transfer checks -            checkForForwardAlertTransfer(entry, /* oldAlertOverride */ null); -        } +        onAlertStateChanged(entry, isHeadsUp, mHeadsUpManager);      } -    /** -     * Handles changes in a group's suppression or alertOverride, but where at least one of those -     * conditions is still true (either the group is suppressed, the group has an alertOverride, -     * or both).  The method determined which kind of child needs to receive the alert, finds the -     * entry currently alerting, and makes the transfer. -     * -     * Internally, this is handled with two main cases: the override needs the alert, or there is -     * no override but the summary is suppressed (so an isolated child needs the alert). -     * -     * @param summary the notification entry of the summary of the logical group. -     * @param oldAlertOverride the former value of group.alertOverride, before whatever event -     *                         required us to check for for a transfer condition. -     */ -    private void checkForForwardAlertTransfer(NotificationEntry summary, -            NotificationEntry oldAlertOverride) { -        if (DEBUG) { -            Log.d(TAG, "checkForForwardAlertTransfer: enter"); -        } -        NotificationGroup group = mGroupManager.getGroupForSummary(summary.getSbn()); -        if (group != null && group.alertOverride != null) { -            handleOverriddenSummaryAlerted(summary); -        } else if (mGroupManager.isSummaryOfSuppressedGroup(summary.getSbn())) { -            handleSuppressedSummaryAlerted(summary, oldAlertOverride); +    private void onAlertStateChanged(NotificationEntry entry, boolean isAlerting, +            AlertingNotificationManager alertManager) { +        if (isAlerting && mGroupManager.isSummaryOfSuppressedGroup(entry.getSbn())) { +            handleSuppressedSummaryAlerted(entry, alertManager);          }      } @@ -247,16 +186,9 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis          // see as early as we can if we need to abort a transfer.          @Override          public void onPendingEntryAdded(NotificationEntry entry) { -            if (DEBUG) { -                Log.d(TAG, "!! onPendingEntryAdded: entry=" + entry); -            }              String groupKey = mGroupManager.getGroupKey(entry.getSbn());              GroupAlertEntry groupAlertEntry = mGroupAlertEntries.get(groupKey); -            if (groupAlertEntry != null && groupAlertEntry.mGroup.alertOverride == null) { -                // new pending group entries require us to transfer back from the child to the -                // group, but alertOverrides are only present in very limited circumstances, so -                // while it's possible the group should ALSO alert, the previous detection which set -                // this alertOverride won't be invalidated by this notification added to this group. +            if (groupAlertEntry != null) {                  checkShouldTransferBack(groupAlertEntry);              }          } @@ -330,128 +262,43 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis      }      /** -     * Handles the scenario where a summary that has been suppressed is itself, or has a former -     * alertOverride (in the form of an isolated logical child) which was alerted.  A suppressed +     * Handles the scenario where a summary that has been suppressed is alerted.  A suppressed       * summary should for all intents and purposes be invisible to the user and as a result should       * not alert.  When this is the case, it is our responsibility to pass the alert to the       * appropriate child which will be the representative notification alerting for the group.       * -     * @param summary the summary that is suppressed and (potentially) alerting -     * @param oldAlertOverride the alertOverride before whatever event triggered this method.  If -     *                         the alert override was removed, this will be the entry that should -     *                         be transferred back from. +     * @param summary the summary that is suppressed and alerting +     * @param alertManager the alert manager that manages the alerting summary       */      private void handleSuppressedSummaryAlerted(@NonNull NotificationEntry summary, -            NotificationEntry oldAlertOverride) { -        if (DEBUG) { -            Log.d(TAG, "handleSuppressedSummaryAlerted: summary=" + summary); -        } +            @NonNull AlertingNotificationManager alertManager) { +        StatusBarNotification sbn = summary.getSbn();          GroupAlertEntry groupAlertEntry = -                mGroupAlertEntries.get(mGroupManager.getGroupKey(summary.getSbn())); - +                mGroupAlertEntries.get(mGroupManager.getGroupKey(sbn));          if (!mGroupManager.isSummaryOfSuppressedGroup(summary.getSbn()) +                || !alertManager.isAlerting(sbn.getKey())                  || groupAlertEntry == null) { -            if (DEBUG) { -                Log.d(TAG, "handleSuppressedSummaryAlerted: invalid state"); -            } -            return; -        } -        boolean summaryIsAlerting = mHeadsUpManager.isAlerting(summary.getKey()); -        boolean priorityIsAlerting = oldAlertOverride != null -                && mHeadsUpManager.isAlerting(oldAlertOverride.getKey()); -        if (!summaryIsAlerting && !priorityIsAlerting) { -            if (DEBUG) { -                Log.d(TAG, "handleSuppressedSummaryAlerted: no summary or override alerting"); -            }              return;          }          if (pendingInflationsWillAddChildren(groupAlertEntry.mGroup)) {              // New children will actually be added to this group, let's not transfer the alert. -            if (DEBUG) { -                Log.d(TAG, "handleSuppressedSummaryAlerted: pending inflations"); -            }              return;          }          NotificationEntry child =                  mGroupManager.getLogicalChildren(summary.getSbn()).iterator().next(); -        if (summaryIsAlerting) { -            if (DEBUG) { -                Log.d(TAG, "handleSuppressedSummaryAlerted: transfer summary -> child"); -            } -            tryTransferAlertState(summary, /*from*/ summary, /*to*/ child, groupAlertEntry); -            return; -        } -        // Summary didn't have the alert, so we're in "transfer back" territory.  First, make sure -        // it's not too late to transfer back, then transfer the alert from the oldAlertOverride to -        // the isolated child which should receive the alert. -        if (!canStillTransferBack(groupAlertEntry)) { -            if (DEBUG) { -                Log.d(TAG, "handleSuppressedSummaryAlerted: transfer from override: too late"); -            } -            return; -        } - -        if (DEBUG) { -            Log.d(TAG, "handleSuppressedSummaryAlerted: transfer override -> child"); -        } -        tryTransferAlertState(summary, /*from*/ oldAlertOverride, /*to*/ child, groupAlertEntry); -    } - -    /** -     * Checks for and handles the scenario where the given entry is the summary of a group which -     * has an alertOverride, and either the summary itself or one of its logical isolated children -     * is currently alerting (which happens if the summary is suppressed). -     */ -    private void handleOverriddenSummaryAlerted(NotificationEntry summary) { -        if (DEBUG) { -            Log.d(TAG, "handleOverriddenSummaryAlerted: summary=" + summary); -        } -        GroupAlertEntry groupAlertEntry = -                mGroupAlertEntries.get(mGroupManager.getGroupKey(summary.getSbn())); -        NotificationGroup group = mGroupManager.getGroupForSummary(summary.getSbn()); -        if (group == null || group.alertOverride == null || groupAlertEntry == null) { -            if (DEBUG) { -                Log.d(TAG, "handleOverriddenSummaryAlerted: invalid state"); -            } -            return; -        } -        boolean summaryIsAlerting = mHeadsUpManager.isAlerting(summary.getKey()); -        if (summaryIsAlerting) { -            if (DEBUG) { -                Log.d(TAG, "handleOverriddenSummaryAlerted: transfer summary -> override"); -            } -            tryTransferAlertState(summary, /*from*/ summary, group.alertOverride, groupAlertEntry); -            return; -        } -        // Summary didn't have the alert, so we're in "transfer back" territory.  First, make sure -        // it's not too late to transfer back, then remove the alert from any of the logical -        // children, and if one of them was alerting, we can alert the override. -        if (!canStillTransferBack(groupAlertEntry)) { -            if (DEBUG) { -                Log.d(TAG, "handleOverriddenSummaryAlerted: transfer from child: too late"); -            } -            return; -        } -        List<NotificationEntry> children = mGroupManager.getLogicalChildren(summary.getSbn()); -        if (children == null) { -            if (DEBUG) { -                Log.d(TAG, "handleOverriddenSummaryAlerted: no children"); -            } -            return; -        } -        children.remove(group.alertOverride); // do not release the alert on our desired destination -        boolean releasedChild = releaseChildAlerts(children); -        if (releasedChild) { -            if (DEBUG) { -                Log.d(TAG, "handleOverriddenSummaryAlerted: transfer child -> override"); +        if (child != null) { +            if (child.getRow().keepInParent() +                    || child.isRowRemoved() +                    || child.isRowDismissed()) { +                // The notification is actually already removed. No need to alert it. +                return;              } -            tryTransferAlertState(summary, /*from*/ null, group.alertOverride, groupAlertEntry); -        } else { -            if (DEBUG) { -                Log.d(TAG, "handleOverriddenSummaryAlerted: no child alert released"); +            if (!alertManager.isAlerting(child.getKey()) && onlySummaryAlerts(summary)) { +                groupAlertEntry.mLastAlertTransferTime = SystemClock.elapsedRealtime();              } +            transferAlertState(summary, child, alertManager);          }      } @@ -460,37 +307,14 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis       * immediately to have the incorrect one up as short as possible. The second should alert       * when possible.       * -     * @param summary entry of the summary       * @param fromEntry entry to transfer alert from       * @param toEntry entry to transfer to +     * @param alertManager alert manager for the alert type       */ -    private void tryTransferAlertState( -            NotificationEntry summary, -            NotificationEntry fromEntry, -            NotificationEntry toEntry, -            GroupAlertEntry groupAlertEntry) { -        if (toEntry != null) { -            if (toEntry.getRow().keepInParent() -                    || toEntry.isRowRemoved() -                    || toEntry.isRowDismissed()) { -                // The notification is actually already removed. No need to alert it. -                return; -            } -            if (!mHeadsUpManager.isAlerting(toEntry.getKey()) && onlySummaryAlerts(summary)) { -                groupAlertEntry.mLastAlertTransferTime = SystemClock.elapsedRealtime(); -            } -            if (DEBUG) { -                Log.d(TAG, "transferAlertState: fromEntry=" + fromEntry + " toEntry=" + toEntry); -            } -            transferAlertState(fromEntry, toEntry); -        } -    } -    private void transferAlertState(@Nullable NotificationEntry fromEntry, -            @NonNull NotificationEntry toEntry) { -        if (fromEntry != null) { -            mHeadsUpManager.removeNotification(fromEntry.getKey(), true /* releaseImmediately */); -        } -        alertNotificationWhenPossible(toEntry); +    private void transferAlertState(@NonNull NotificationEntry fromEntry, @NonNull NotificationEntry toEntry, +            @NonNull AlertingNotificationManager alertManager) { +        alertManager.removeNotification(fromEntry.getKey(), true /* releaseImmediately */); +        alertNotificationWhenPossible(toEntry, alertManager);      }      /** @@ -502,13 +326,11 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis       * more children are coming. Thus, if a child is added within a certain timeframe after we       * transfer, we back out and alert the summary again.       * -     * An alert can only transfer back within a small window of time after a transfer away from the -     * summary to a child happened. -     *       * @param groupAlertEntry group alert entry to check       */      private void checkShouldTransferBack(@NonNull GroupAlertEntry groupAlertEntry) { -        if (canStillTransferBack(groupAlertEntry)) { +        if (SystemClock.elapsedRealtime() - groupAlertEntry.mLastAlertTransferTime +                < ALERT_TRANSFER_TIMEOUT) {              NotificationEntry summary = groupAlertEntry.mGroup.summary;              if (!onlySummaryAlerts(summary)) { @@ -516,17 +338,30 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis              }              ArrayList<NotificationEntry> children = mGroupManager.getLogicalChildren(                      summary.getSbn()); -            int numActiveChildren = children.size(); +            int numChildren = children.size();              int numPendingChildren = getPendingChildrenNotAlerting(groupAlertEntry.mGroup); -            int numChildren = numActiveChildren + numPendingChildren; +            numChildren += numPendingChildren;              if (numChildren <= 1) {                  return;              } -            boolean releasedChild = releaseChildAlerts(children); +            boolean releasedChild = false; +            for (int i = 0; i < children.size(); i++) { +                NotificationEntry entry = children.get(i); +                if (onlySummaryAlerts(entry) && mHeadsUpManager.isAlerting(entry.getKey())) { +                    releasedChild = true; +                    mHeadsUpManager.removeNotification( +                            entry.getKey(), true /* releaseImmediately */); +                } +                if (mPendingAlerts.containsKey(entry.getKey())) { +                    // This is the child that would've been removed if it was inflated. +                    releasedChild = true; +                    mPendingAlerts.get(entry.getKey()).mAbortOnInflation = true; +                } +            }              if (releasedChild && !mHeadsUpManager.isAlerting(summary.getKey())) { -                boolean notifyImmediately = numActiveChildren > 1; +                boolean notifyImmediately = (numChildren - numPendingChildren) > 1;                  if (notifyImmediately) { -                    alertNotificationWhenPossible(summary); +                    alertNotificationWhenPossible(summary, mHeadsUpManager);                  } else {                      // Should wait until the pending child inflates before alerting.                      groupAlertEntry.mAlertSummaryOnNextAddition = true; @@ -536,61 +371,25 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis          }      } -    private boolean canStillTransferBack(@NonNull GroupAlertEntry groupAlertEntry) { -        return SystemClock.elapsedRealtime() - groupAlertEntry.mLastAlertTransferTime -                < ALERT_TRANSFER_TIMEOUT; -    } - -    private boolean releaseChildAlerts(List<NotificationEntry> children) { -        boolean releasedChild = false; -        if (SPEW) { -            Log.d(TAG, "releaseChildAlerts: numChildren=" + children.size()); -        } -        for (int i = 0; i < children.size(); i++) { -            NotificationEntry entry = children.get(i); -            if (SPEW) { -                Log.d(TAG, "releaseChildAlerts: checking i=" + i + " entry=" + entry -                        + " onlySummaryAlerts=" + onlySummaryAlerts(entry) -                        + " isAlerting=" + mHeadsUpManager.isAlerting(entry.getKey()) -                        + " isPendingAlert=" + mPendingAlerts.containsKey(entry.getKey())); -            } -            if (onlySummaryAlerts(entry) && mHeadsUpManager.isAlerting(entry.getKey())) { -                releasedChild = true; -                mHeadsUpManager.removeNotification( -                        entry.getKey(), true /* releaseImmediately */); -            } -            if (mPendingAlerts.containsKey(entry.getKey())) { -                // This is the child that would've been removed if it was inflated. -                releasedChild = true; -                mPendingAlerts.get(entry.getKey()).mAbortOnInflation = true; -            } -        } -        if (SPEW) { -            Log.d(TAG, "releaseChildAlerts: didRelease=" + releasedChild); -        } -        return releasedChild; -    } -      /**       * Tries to alert the notification. If its content view is not inflated, we inflate and continue       * when the entry finishes inflating the view.       *       * @param entry entry to show +     * @param alertManager alert manager for the alert type       */ -    private void alertNotificationWhenPossible(@NonNull NotificationEntry entry) { -        @InflationFlag int contentFlag = mHeadsUpManager.getContentFlag(); +    private void alertNotificationWhenPossible(@NonNull NotificationEntry entry, +            @NonNull AlertingNotificationManager alertManager) { +        @InflationFlag int contentFlag = alertManager.getContentFlag();          final RowContentBindParams params = mRowContentBindStage.getStageParams(entry);          if ((params.getContentViews() & contentFlag) == 0) { -            if (DEBUG) { -                Log.d(TAG, "alertNotificationWhenPossible: async requestRebind entry=" + entry); -            }              mPendingAlerts.put(entry.getKey(), new PendingAlertInfo(entry));              params.requireContentViews(contentFlag);              mRowContentBindStage.requestRebind(entry, en -> {                  PendingAlertInfo alertInfo = mPendingAlerts.remove(entry.getKey());                  if (alertInfo != null) {                      if (alertInfo.isStillValid()) { -                        alertNotificationWhenPossible(entry); +                        alertNotificationWhenPossible(entry, mHeadsUpManager);                      } else {                          // The transfer is no longer valid. Free the content.                          mRowContentBindStage.getStageParams(entry).markContentViewsFreeable( @@ -601,16 +400,10 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis              });              return;          } -        if (mHeadsUpManager.isAlerting(entry.getKey())) { -            if (DEBUG) { -                Log.d(TAG, "alertNotificationWhenPossible: continue alerting entry=" + entry); -            } -            mHeadsUpManager.updateNotification(entry.getKey(), true /* alert */); +        if (alertManager.isAlerting(entry.getKey())) { +            alertManager.updateNotification(entry.getKey(), true /* alert */);          } else { -            if (DEBUG) { -                Log.d(TAG, "alertNotificationWhenPossible: start alerting entry=" + entry); -            } -            mHeadsUpManager.showNotification(entry); +            alertManager.showNotification(entry);          }      } 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 c79e503379bd..20b37e26dcee 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -22,7 +22,6 @@ import static androidx.constraintlayout.widget.ConstraintSet.END;  import static androidx.constraintlayout.widget.ConstraintSet.PARENT_ID;  import static androidx.constraintlayout.widget.ConstraintSet.START; -import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE;  import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE;  import static com.android.systemui.classifier.Classifier.QS_COLLAPSE;  import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS; @@ -1730,7 +1729,6 @@ public class NotificationPanelViewController extends PanelViewController {              return;          }          mExpectingSynthesizedDown = true; -        InteractionJankMonitor.getInstance().begin(mView, CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);          onTrackingStarted();          updatePanelExpanded();      } @@ -2075,20 +2073,18 @@ public class NotificationPanelViewController extends PanelViewController {          setQsExpansionEnabled(mAmbientState.getScrollY() == 0);          int radius = mScrimCornerRadius; -        if (visible || !mShouldUseSplitNotificationShade) { -            if (!mShouldUseSplitNotificationShade) { -                top = (int) Math.min(qsPanelBottomY, notificationTop); -                bottom = getView().getBottom(); -                left = getView().getLeft(); -                right = getView().getRight(); -                radius = (int) MathUtils.lerp(mScreenCornerRadius, mScrimCornerRadius, -                        Math.min(top / (float) mScrimCornerRadius, 1f)); -            } else { -                top = Math.min(qsPanelBottomY, mSplitShadeNotificationsTopPadding); -                bottom = mNotificationStackScrollLayoutController.getHeight(); -                left = mNotificationStackScrollLayoutController.getLeft(); -                right = mNotificationStackScrollLayoutController.getRight(); -            } +        if (!mShouldUseSplitNotificationShade) { +            top = (int) Math.min(qsPanelBottomY, notificationTop); +            bottom = getView().getBottom(); +            left = getView().getLeft(); +            right = getView().getRight(); +            radius = (int) MathUtils.lerp(mScreenCornerRadius, mScrimCornerRadius, +                    Math.min(top / (float) mScrimCornerRadius, 1f)); +        } else if (qsPanelBottomY > 0) { // so bounds are empty on lockscreen +            top = Math.min(qsPanelBottomY, mSplitShadeNotificationsTopPadding); +            bottom = mNotificationStackScrollLayoutController.getHeight(); +            left = mNotificationStackScrollLayoutController.getLeft(); +            right = mNotificationStackScrollLayoutController.getRight();          }          // Fancy clipping for quick settings @@ -2698,6 +2694,7 @@ public class NotificationPanelViewController extends PanelViewController {          mConversationNotificationManager.onNotificationPanelExpandStateChanged(isFullyCollapsed());          mIsExpanding = false;          mMediaHierarchyManager.setCollapsingShadeFromQS(false); +        mMediaHierarchyManager.setQsExpanded(mQsExpanded);          if (isFullyCollapsed()) {              DejankUtils.postAfterTraversal(new Runnable() {                  @Override @@ -2834,15 +2831,6 @@ public class NotificationPanelViewController extends PanelViewController {      }      @Override -    protected float getPeekHeight() { -        if (mNotificationStackScrollLayoutController.getNotGoneChildCount() > 0) { -            return mNotificationStackScrollLayoutController.getPeekHeight(); -        } else { -            return mQsMinExpansionHeight; -        } -    } - -    @Override      protected boolean shouldUseDismissingAnimation() {          return mBarState != StatusBarState.SHADE && (mKeyguardStateController.canDismissLockScreen()                  || !isTracking()); @@ -3709,6 +3697,12 @@ public class NotificationPanelViewController extends PanelViewController {          @Override          public void flingTopOverscroll(float velocity, boolean open) { +            // in split shade mode we want to expand/collapse QS only when touch happens within QS +            if (mShouldUseSplitNotificationShade +                    && (mInitialTouchX < mQsFrame.getX() +                        || mInitialTouchX > mQsFrame.getX() + mQsFrame.getWidth())) { +                return; +            }              mLastOverscroll = 0f;              mQsExpansionFromOverscroll = false;              setQsExpansion(mQsExpansionHeight); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java index 28cfe214dd3a..64e2c1c5d268 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java @@ -212,7 +212,6 @@ public abstract class PanelBar extends FrameLayout {          } else {              pv.resetViews(false /* animate */);              pv.setExpandedFraction(0); // just in case -            pv.cancelPeek();          }          if (DEBUG) LOG("collapsePanel: animate=%s waiting=%s", animate, waiting);          if (!waiting && mState != STATE_CLOSED) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java index 4714c4b5d476..f9a644fe2def 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java @@ -42,6 +42,7 @@ import android.view.ViewConfiguration;  import android.view.ViewGroup;  import android.view.ViewTreeObserver;  import android.view.animation.Interpolator; +import android.view.animation.PathInterpolator;  import com.android.internal.jank.InteractionJankMonitor;  import com.android.internal.logging.nano.MetricsProto.MetricsEvent; @@ -67,8 +68,6 @@ import java.util.ArrayList;  public abstract class PanelViewController {      public static final boolean DEBUG = PanelBar.DEBUG;      public static final String TAG = PanelView.class.getSimpleName(); -    private static final int INITIAL_OPENING_PEEK_DURATION = 200; -    private static final int PEEK_ANIMATION_DURATION = 360;      private static final int NO_FIXED_DURATION = -1;      private static final long SHADE_OPEN_SPRING_OUT_DURATION = 350L;      private static final long SHADE_OPEN_SPRING_BACK_DURATION = 200L; @@ -95,7 +94,6 @@ public abstract class PanelViewController {      protected HeadsUpManagerPhone mHeadsUpManager;      protected final StatusBarTouchableRegionManager mStatusBarTouchableRegionManager; -    private float mPeekHeight;      private float mHintDistance;      private float mInitialOffsetOnTouch;      private boolean mCollapsedAndHeadsUpOnDown; @@ -105,8 +103,6 @@ public abstract class PanelViewController {      private boolean mHasLayoutedSinceDown;      private float mUpdateFlingVelocity;      private boolean mUpdateFlingOnLayout; -    private boolean mPeekTouching; -    private boolean mJustPeeked;      private boolean mClosing;      protected boolean mTracking;      private boolean mTouchSlopExceeded; @@ -124,7 +120,6 @@ public abstract class PanelViewController {      private boolean mHandlingPointerUp;      private ValueAnimator mHeightAnimator; -    private ObjectAnimator mPeekAnimator;      private final VelocityTracker mVelocityTracker = VelocityTracker.obtain();      private FlingAnimationUtils mFlingAnimationUtils;      private FlingAnimationUtils mFlingAnimationUtilsClosing; @@ -139,6 +134,7 @@ public abstract class PanelViewController {       */      private boolean mInstantExpanding;      private boolean mAnimateAfterExpanding; +    private boolean mIsFlinging;      PanelBar mBar; @@ -193,40 +189,6 @@ public abstract class PanelViewController {          }      } -    private void runPeekAnimation(long duration, float peekHeight, boolean collapseWhenFinished) { -        mPeekHeight = peekHeight; -        if (DEBUG) logf("peek to height=%.1f", mPeekHeight); -        if (mHeightAnimator != null) { -            return; -        } -        if (mPeekAnimator != null) { -            mPeekAnimator.cancel(); -        } -        mPeekAnimator = ObjectAnimator.ofFloat(this, "expandedHeight", mPeekHeight).setDuration( -                duration); -        mPeekAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN); -        mPeekAnimator.addListener(new AnimatorListenerAdapter() { -            private boolean mCancelled; - -            @Override -            public void onAnimationCancel(Animator animation) { -                mCancelled = true; -            } - -            @Override -            public void onAnimationEnd(Animator animation) { -                mPeekAnimator = null; -                if (!mCancelled && collapseWhenFinished) { -                    mView.postOnAnimation(mPostCollapseRunnable); -                } - -            } -        }); -        notifyExpandingStarted(); -        mPeekAnimator.start(); -        mJustPeeked = true; -    } -      protected AmbientState getAmbientState() {          return mAmbientState;      } @@ -334,8 +296,6 @@ public abstract class PanelViewController {      }      private void startOpening(MotionEvent event) { -        runPeekAnimation(INITIAL_OPENING_PEEK_DURATION, getOpeningHeight(), -                false /* collapseWhenFinished */);          notifyBarPanelExpansionChanged();          maybeVibrateOnOpening(); @@ -373,10 +333,6 @@ public abstract class PanelViewController {          return Math.abs(yDiff) >= Math.abs(xDiff);      } -    protected void startExpandingFromPeek() { -        mStatusBar.handlePeekToExpandTransistion(); -    } -      protected void startExpandMotion(float newX, float newY, boolean startTracking,              float expandedHeight) {          if (!mHandlingPointerUp) { @@ -440,18 +396,6 @@ public abstract class PanelViewController {              if (mUpdateFlingOnLayout) {                  mUpdateFlingVelocity = vel;              } -        } else if (mPanelClosedOnDown && !mHeadsUpManager.hasPinnedHeadsUp() && !mTracking -                && !mStatusBar.isBouncerShowing() -                && !mKeyguardStateController.isKeyguardFadingAway()) { -            long timePassed = SystemClock.uptimeMillis() - mDownTime; -            if (timePassed < ViewConfiguration.getLongPressTimeout()) { -                // Let's show the user that they can actually expand the panel -                runPeekAnimation( -                        PEEK_ANIMATION_DURATION, getPeekHeight(), true /* collapseWhenFinished */); -            } else { -                // We need to collapse the panel since we peeked to the small height. -                mView.postOnAnimation(mPostCollapseRunnable); -            }          } else if (!mStatusBar.isBouncerShowing()                  && !mStatusBarKeyguardViewManager.isShowingAlternateAuthOrAnimating()) {              boolean expands = onEmptySpaceClick(mInitialTouchX); @@ -459,7 +403,6 @@ public abstract class PanelViewController {          }          mVelocityTracker.clear(); -        mPeekTouching = false;      }      protected float getCurrentExpandVelocity() { @@ -580,7 +523,6 @@ public abstract class PanelViewController {      protected void fling(float vel, boolean expand, float collapseSpeedUpFactor,              boolean expandBecauseOfFalsing) { -        cancelPeek();          float target = expand ? getMaxPanelHeight() : 0;          if (!expand) {              mClosing = true; @@ -596,6 +538,7 @@ public abstract class PanelViewController {              notifyExpandingFinished();              return;          } +        mIsFlinging = true;          mOverExpandedBeforeFling = getOverExpansionAmount() > 0f;          ValueAnimator animator = createHeightAnimator(target);          mFlingTarget = target; @@ -635,6 +578,12 @@ public abstract class PanelViewController {              private boolean mCancelled;              @Override +            public void onAnimationStart(Animator animation) { +                InteractionJankMonitor.getInstance() +                        .begin(mView, CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE); +            } + +            @Override              public void onAnimationCancel(Animator animation) {                  mCancelled = true;              } @@ -679,6 +628,7 @@ public abstract class PanelViewController {      }      private void onFlingEnd(boolean cancelled) { +        mIsFlinging = false;          setAnimator(null);          mKeyguardStateController.notifyPanelFlingEnd();          if (!cancelled) { @@ -714,10 +664,6 @@ public abstract class PanelViewController {              return;          } -        if (mPeekAnimator != null || mPeekTouching) { -            return; -        } -          if (mTracking && !isTrackingBlocked()) {              return;          } @@ -751,6 +697,16 @@ public abstract class PanelViewController {          if (isNaN(h)) {              Log.wtf(TAG, "ExpandedHeight set to NaN");          } +        if (mAmbientState.isExpansionChanging() +                && !mIsFlinging  // Fling already uses interpolated height from end of swipe +                && !mAmbientState.isOnKeyguard() +                && !mAmbientState.isDozing() +                && !mAmbientState.isPulsing()) { +            final float fraction = h / mView.getHeight(); +            final float interpolatedFraction = new PathInterpolator(0.2f, 0.8f, 0.8f, 1f) +                    .getInterpolation(fraction); +            h = interpolatedFraction * mView.getHeight(); +        }          maybeOverScrollForShadeFlingOpen(h);          if (mExpandLatencyTracking && h != 0f) {              DejankUtils.postAfterTraversal( @@ -870,20 +826,6 @@ public abstract class PanelViewController {          }      }; -    public void cancelPeek() { -        boolean cancelled = false; -        if (mPeekAnimator != null) { -            cancelled = true; -            mPeekAnimator.cancel(); -        } - -        if (cancelled) { -            // When peeking, we already tell mBar that we expanded ourselves. Make sure that we also -            // notify mBar that we might have closed ourselves. -            notifyBarPanelExpansionChanged(); -        } -    } -      public void expand(final boolean animate) {          if (!isFullyCollapsed() && !isCollapsing()) {              return; @@ -893,7 +835,6 @@ public abstract class PanelViewController {          mAnimateAfterExpanding = animate;          mUpdateFlingOnLayout = false;          abortAnimations(); -        cancelPeek();          if (mTracking) {              onTrackingStopped(true /* expands */); // The panel is expanded after this call.          } @@ -944,7 +885,6 @@ public abstract class PanelViewController {      }      private void abortAnimations() { -        cancelPeek();          cancelHeightAnimator();          mView.removeCallbacks(mPostCollapseRunnable);          mView.removeCallbacks(mFlingCollapseRunnable); @@ -962,7 +902,6 @@ public abstract class PanelViewController {          if (mHeightAnimator != null || mTracking) {              return;          } -        cancelPeek();          notifyExpandingStarted();          startUnlockHintAnimationPhase1(() -> {              notifyExpandingFinished(); @@ -1065,7 +1004,7 @@ public abstract class PanelViewController {          if (mBar != null) {              mBar.panelExpansionChanged(                      mExpandedFraction, -                    mExpandedFraction > 0f || mPeekAnimator != null || mInstantExpanding +                    mExpandedFraction > 0f || mInstantExpanding                              || isPanelVisibleBecauseOfHeadsUp() || mTracking                              || mHeightAnimator != null);          } @@ -1105,19 +1044,16 @@ public abstract class PanelViewController {      public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {          pw.println(String.format("[PanelView(%s): expandedHeight=%f maxPanelHeight=%d closing=%s" -                        + " tracking=%s justPeeked=%s peekAnim=%s%s timeAnim=%s%s " +                        + " tracking=%s timeAnim=%s%s "                          + "touchDisabled=%s" + "]",                  this.getClass().getSimpleName(), getExpandedHeight(), getMaxPanelHeight(), -                mClosing ? "T" : "f", mTracking ? "T" : "f", mJustPeeked ? "T" : "f", mPeekAnimator, -                ((mPeekAnimator != null && mPeekAnimator.isStarted()) ? " (started)" : ""), -                mHeightAnimator, +                mClosing ? "T" : "f", mTracking ? "T" : "f", mHeightAnimator,                  ((mHeightAnimator != null && mHeightAnimator.isStarted()) ? " (started)" : ""),                  mTouchDisabled ? "T" : "f"));      }      public abstract void resetViews(boolean animate); -    protected abstract float getPeekHeight();      /**       * @return whether "Clear all" button will be visible when the panel is fully expanded @@ -1192,10 +1128,8 @@ public abstract class PanelViewController {                      mAnimatingOnDown = mHeightAnimator != null;                      mMinExpandHeight = 0.0f;                      mDownTime = SystemClock.uptimeMillis(); -                    if (mAnimatingOnDown && mClosing && !mHintAnimationRunning -                            || mPeekAnimator != null) { +                    if (mAnimatingOnDown && mClosing && !mHintAnimationRunning) {                          cancelHeightAnimator(); -                        cancelPeek();                          mTouchSlopExceeded = true;                          return true;                      } @@ -1203,7 +1137,6 @@ public abstract class PanelViewController {                      mInitialTouchX = x;                      mTouchStartedInEmptyArea = !isInContentBounds(x, y);                      mTouchSlopExceeded = mTouchSlopExceededBeforeDown; -                    mJustPeeked = false;                      mMotionAborted = false;                      mPanelClosedOnDown = isFullyCollapsed();                      mCollapsedAndHeadsUpOnDown = false; @@ -1282,8 +1215,6 @@ public abstract class PanelViewController {               * We capture touch events here and update the expand height here in case according to               * the users fingers. This also handles multi-touch.               * -             * If the user just clicks shortly, we show a quick peek of the shade. -             *               * Flinging is also enabled in order to open or close the shade.               */ @@ -1303,25 +1234,22 @@ public abstract class PanelViewController {              switch (event.getActionMasked()) {                  case MotionEvent.ACTION_DOWN:                      startExpandMotion(x, y, false /* startTracking */, mExpandedHeight); -                    mJustPeeked = false;                      mMinExpandHeight = 0.0f;                      mPanelClosedOnDown = isFullyCollapsed();                      mHasLayoutedSinceDown = false;                      mUpdateFlingOnLayout = false;                      mMotionAborted = false; -                    mPeekTouching = mPanelClosedOnDown;                      mDownTime = SystemClock.uptimeMillis();                      mTouchAboveFalsingThreshold = false;                      mCollapsedAndHeadsUpOnDown =                              isFullyCollapsed() && mHeadsUpManager.hasPinnedHeadsUp();                      addMovement(event);                      if (!mGestureWaitForTouchSlop || (mHeightAnimator != null -                            && !mHintAnimationRunning) || mPeekAnimator != null) { +                            && !mHintAnimationRunning)) {                          mTouchSlopExceeded =                                  (mHeightAnimator != null && !mHintAnimationRunning) -                                        || mPeekAnimator != null || mTouchSlopExceededBeforeDown; +                                        || mTouchSlopExceededBeforeDown;                          cancelHeightAnimator(); -                        cancelPeek();                          onTrackingStarted();                      }                      if (isFullyCollapsed() && !mHeadsUpManager.hasPinnedHeadsUp() @@ -1361,7 +1289,7 @@ public abstract class PanelViewController {                              || mIgnoreXTouchSlop)) {                          mTouchSlopExceeded = true;                          if (mGestureWaitForTouchSlop && !mTracking && !mCollapsedAndHeadsUpOnDown) { -                            if (!mJustPeeked && mInitialOffsetOnTouch != 0f) { +                            if (mInitialOffsetOnTouch != 0f) {                                  startExpandMotion(x, y, false /* startTracking */, mExpandedHeight);                                  h = 0;                              } @@ -1370,26 +1298,12 @@ public abstract class PanelViewController {                          }                      }                      float newHeight = Math.max(0, h + mInitialOffsetOnTouch); -                    if (newHeight > mPeekHeight) { -                        if (mPeekAnimator != null) { -                            mPeekAnimator.cancel(); -                        } -                        mJustPeeked = false; -                    } else if (mPeekAnimator == null && mJustPeeked) { -                        // The initial peek has finished, but we haven't dragged as far yet, lets -                        // speed it up by starting at the peek height. -                        mInitialOffsetOnTouch = mExpandedHeight; -                        mInitialTouchY = y; -                        mMinExpandHeight = mExpandedHeight; -                        mJustPeeked = false; -                    }                      newHeight = Math.max(newHeight, mMinExpandHeight);                      if (-h >= getFalsingThreshold()) {                          mTouchAboveFalsingThreshold = true;                          mUpwardsWhenThresholdReached = isDirectionUpwards(x, y);                      } -                    if (!mJustPeeked && (!mGestureWaitForTouchSlop || mTracking) -                            && !isTrackingBlocked()) { +                    if ((!mGestureWaitForTouchSlop || mTracking) && !isTrackingBlocked()) {                          setExpandedHeightInternal(newHeight);                      }                      break; @@ -1398,11 +1312,14 @@ public abstract class PanelViewController {                  case MotionEvent.ACTION_CANCEL:                      addMovement(event);                      endMotionEvent(event, x, y, false /* forceCancel */); -                    InteractionJankMonitor monitor = InteractionJankMonitor.getInstance(); -                    if (event.getActionMasked() == MotionEvent.ACTION_UP) { -                        monitor.end(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE); -                    } else { -                        monitor.cancel(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE); +                    // mHeightAnimator is null, there is no remaining frame, ends instrumenting. +                    if (mHeightAnimator == null) { +                        InteractionJankMonitor monitor = InteractionJankMonitor.getInstance(); +                        if (event.getActionMasked() == MotionEvent.ACTION_UP) { +                            monitor.end(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE); +                        } else { +                            monitor.cancel(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE); +                        }                      }                      break;              } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java index c09293115492..a952db2a6073 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -163,7 +163,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump      private final float mDefaultScrimAlpha;      // Assuming the shade is expanded during initialization -    private float mExpansionFraction = 1f; +    private float mPanelExpansion = 1f;      private float mQsExpansion;      private boolean mQsBottomVisible; @@ -487,8 +487,8 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump          if (isNaN(fraction)) {              throw new IllegalArgumentException("Fraction should not be NaN");          } -        if (mExpansionFraction != fraction) { -            mExpansionFraction = fraction; +        if (mPanelExpansion != fraction) { +            mPanelExpansion = fraction;              boolean relevantState = (mState == ScrimState.UNLOCKED                      || mState == ScrimState.KEYGUARD @@ -641,7 +641,12 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump                  mBehindTint = Color.BLACK;              } else {                  mBehindAlpha = backAlpha; -                mNotificationsAlpha = Math.max(1.0f - getInterpolatedFraction(), mQsExpansion); +                if (mState == ScrimState.SHADE_LOCKED) { +                    // going from KEYGUARD to SHADE_LOCKED state +                    mNotificationsAlpha = getInterpolatedFraction(); +                } else { +                    mNotificationsAlpha = Math.max(1.0f - getInterpolatedFraction(), mQsExpansion); +                }                  mBehindTint = backTint;              }          } @@ -805,7 +810,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump      }      private float getInterpolatedFraction() { -        float frac = mExpansionFraction; +        float frac = mPanelExpansion;          // let's start this 20% of the way down the screen          frac = frac * 1.2f - 0.2f;          if (frac <= 0) { @@ -1165,7 +1170,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump          pw.print("  mDefaultScrimAlpha=");          pw.println(mDefaultScrimAlpha);          pw.print("  mExpansionFraction="); -        pw.println(mExpansionFraction); +        pw.println(mPanelExpansion);      }      public void setWallpaperSupportsAmbientMode(boolean wallpaperSupportsAmbientMode) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 6ef4663ea5f3..bd17d00063d7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -148,6 +148,7 @@ import com.android.systemui.R;  import com.android.systemui.SystemUI;  import com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuController;  import com.android.systemui.animation.ActivityLaunchAnimator; +import com.android.systemui.animation.DelegateLaunchAnimatorController;  import com.android.systemui.assist.AssistManager;  import com.android.systemui.broadcast.BroadcastDispatcher;  import com.android.systemui.camera.CameraIntents; @@ -208,7 +209,6 @@ import com.android.systemui.statusbar.SuperStatusBarViewFactory;  import com.android.systemui.statusbar.SysuiStatusBarStateController;  import com.android.systemui.statusbar.VibratorHelper;  import com.android.systemui.statusbar.charging.WiredChargingRippleController; -import com.android.systemui.statusbar.events.PrivacyDotViewController;  import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;  import com.android.systemui.statusbar.notification.DynamicPrivacyController;  import com.android.systemui.statusbar.notification.NotificationActivityStarter; @@ -428,7 +428,7 @@ public class StatusBar extends SystemUI implements DemoMode,      private NotificationsController mNotificationsController;      private final OngoingCallController mOngoingCallController;      private final SystemStatusAnimationScheduler mAnimationScheduler; -    private final PrivacyDotViewController mDotViewController; +    private final StatusBarLocationPublisher mStatusBarLocationPublisher;      // expanded notifications      // the sliding/resizing panel within the notification window @@ -798,7 +798,7 @@ public class StatusBar extends SystemUI implements DemoMode,              WiredChargingRippleController chargingRippleAnimationController,              OngoingCallController ongoingCallController,              SystemStatusAnimationScheduler animationScheduler, -            PrivacyDotViewController dotViewController, +            StatusBarLocationPublisher locationPublisher,              FeatureFlags featureFlags,              KeyguardUnlockAnimationController keyguardUnlockAnimationController) {          super(context); @@ -881,7 +881,7 @@ public class StatusBar extends SystemUI implements DemoMode,          mChargingRippleAnimationController = chargingRippleAnimationController;          mOngoingCallController = ongoingCallController;          mAnimationScheduler = animationScheduler; -        mDotViewController = dotViewController; +        mStatusBarLocationPublisher = locationPublisher;          mFeatureFlags = featureFlags;          mExpansionChangedListeners = new ArrayList<>(); @@ -1174,7 +1174,7 @@ public class StatusBar extends SystemUI implements DemoMode,                          new CollapsedStatusBarFragment(                                  mOngoingCallController,                                  mAnimationScheduler, -                                mDotViewController, +                                mStatusBarLocationPublisher,                                  mNotificationIconAreaController),                          CollapsedStatusBarFragment.TAG)                  .commit(); @@ -2785,13 +2785,8 @@ public class StatusBar extends SystemUI implements DemoMode,          final boolean afterKeyguardGone = mActivityIntentHelper.wouldLaunchResolverActivity(                  intent, mLockscreenUserManager.getCurrentUserId()); -        ActivityLaunchAnimator.Controller animController = null; -        if (animationController != null) { -            animController = dismissShade ? new StatusBarLaunchAnimatorController( -                    animationController, this, true /* isLaunchForActivity */) -                    : animationController; -        } -        final ActivityLaunchAnimator.Controller animCallbackForLambda = animController; +        ActivityLaunchAnimator.Controller animController = wrapAnimationController( +                animationController, dismissShade);          // If we animate, we will dismiss the shade only once the animation is done. This is taken          // care of by the StatusBarLaunchAnimationController. @@ -2804,7 +2799,7 @@ public class StatusBar extends SystemUI implements DemoMode,              intent.addFlags(flags);              int[] result = new int[]{ActivityManager.START_CANCELED}; -            mActivityLaunchAnimator.startIntentWithAnimation(animCallbackForLambda, +            mActivityLaunchAnimator.startIntentWithAnimation(animController,                      areLaunchAnimationsEnabled(), (adapter) -> {                          ActivityOptions options = new ActivityOptions(                                  getActivityOptions(mDisplayId, adapter)); @@ -2858,6 +2853,46 @@ public class StatusBar extends SystemUI implements DemoMode,                  afterKeyguardGone, true /* deferred */);      } +    @Nullable +    private ActivityLaunchAnimator.Controller wrapAnimationController( +            @Nullable ActivityLaunchAnimator.Controller animationController, boolean dismissShade) { +        if (animationController == null) { +            return null; +        } + +        View rootView = animationController.getLaunchContainer().getRootView(); +        if (rootView == mSuperStatusBarViewFactory.getStatusBarWindowView()) { +            // We are animating a view in the status bar. We have to make sure that the status bar +            // window matches the full screen during the animation and that we are expanding the +            // view below the other status bar text. +            animationController.setLaunchContainer( +                    mStatusBarWindowController.getLaunchAnimationContainer()); + +            return new DelegateLaunchAnimatorController(animationController) { +                @Override +                public void onLaunchAnimationStart(boolean isExpandingFullyAbove) { +                    getDelegate().onLaunchAnimationStart(isExpandingFullyAbove); +                    mStatusBarWindowController.setLaunchAnimationRunning(true); +                } + +                @Override +                public void onLaunchAnimationEnd(boolean isExpandingFullyAbove) { +                    getDelegate().onLaunchAnimationEnd(isExpandingFullyAbove); +                    mStatusBarWindowController.setLaunchAnimationRunning(false); +                } +            }; +        } + +        if (dismissShade && rootView == mNotificationShadeWindowView) { +            // We are animating a view in the shade. We have to make sure that we collapse it when +            // the animation ends or is cancelled. +            return new StatusBarLaunchAnimatorController(animationController, this, +                    true /* isLaunchForActivity */); +        } + +        return animationController; +    } +      public void readyForKeyguardDone() {          mStatusBarKeyguardViewManager.readyForKeyguardDone();      } @@ -3059,19 +3094,7 @@ public class StatusBar extends SystemUI implements DemoMode,          }      } -    void handlePeekToExpandTransistion() { -        try { -            // consider the transition from peek to expanded to be a panel open, -            // but not one that clears notification effects. -            int notificationLoad = mNotificationsController.getActiveNotificationsCount(); -            mBarService.onPanelRevealed(false, notificationLoad); -        } catch (RemoteException ex) { -            // Won't fail unless the world has ended. -        } -    } -      // Visibility reporting -      void handleVisibleToUserChangedImpl(boolean visibleToUser) {          if (visibleToUser) {              /* The LEDs are turned off when the notification panel is shown, even just a little bit. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index f403cc94d831..1ef8470180f3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -591,6 +591,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb          if (mStatusBar.isInLaunchTransition()                  || mKeyguardStateController.isFlingingToDismissKeyguard()) { +            final boolean wasFlingingToDismissKeyguard = +                    mKeyguardStateController.isFlingingToDismissKeyguard();              mStatusBar.fadeKeyguardAfterLaunchTransition(new Runnable() {                  @Override                  public void run() { @@ -604,6 +606,11 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb                  public void run() {                      mStatusBar.hideKeyguard();                      mNotificationShadeWindowController.setKeyguardFadingAway(false); + +                    if (wasFlingingToDismissKeyguard) { +                        mStatusBar.finishKeyguardFadingAway(); +                    } +                      mViewMediatorCallback.keyguardGone();                      executeAfterKeyguardGoneAction();                  } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLocationPublisher.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLocationPublisher.kt new file mode 100644 index 000000000000..4e5ecfe3f623 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLocationPublisher.kt @@ -0,0 +1,83 @@ +/* + * 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.systemui.statusbar.phone + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.statusbar.policy.CallbackController +import java.lang.ref.WeakReference +import javax.inject.Inject + +/** + * Publishes updates to the status bar's margins. + * + * While the status bar view consumes the entire width of the device, the status bar + * contents are laid out with margins for rounded corners, padding from the absolute + * edges, and potentially display cutouts in the corner. + */ +@SysUISingleton +class StatusBarLocationPublisher @Inject constructor() +: CallbackController<StatusBarMarginUpdatedListener> { +    private val listeners = mutableSetOf<WeakReference<StatusBarMarginUpdatedListener>>() + +    var marginLeft: Int = 0 +        private set +    var marginRight: Int = 0 +        private set + +    override fun addCallback(listener: StatusBarMarginUpdatedListener) { +        listeners.add(WeakReference(listener)) +    } + +    override fun removeCallback(listener: StatusBarMarginUpdatedListener) { +        var toRemove: WeakReference<StatusBarMarginUpdatedListener>? = null +        for (l in listeners) { +            if (l.get() == listener) { +                toRemove = l +            } +        } + +        if (toRemove != null) { +            listeners.remove(toRemove) +        } +    } + +    fun updateStatusBarMargin(left: Int, right: Int) { +        marginLeft = left +        marginRight = right + +        notifyListeners() +    } + +    private fun notifyListeners() { +        var listenerList: List<WeakReference<StatusBarMarginUpdatedListener>> +        synchronized(this) { +            listenerList = listeners.toList() +        } + +        listenerList.forEach { wrapper -> +            if (wrapper.get() == null) { +                listeners.remove(wrapper) +            } + +            wrapper.get()?.onStatusBarMarginUpdated(marginLeft, marginRight) +        } +    } +} + +interface StatusBarMarginUpdatedListener { +    fun onStatusBarMarginUpdated(marginLeft: Int, marginRight: Int) +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java index 2f7278b38d15..30b8c5c0d8d3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java @@ -29,6 +29,7 @@ import android.view.Gravity;  import android.view.ViewGroup;  import android.view.WindowManager; +import com.android.systemui.R;  import com.android.systemui.dagger.SysUISingleton;  import com.android.systemui.dagger.qualifiers.Main;  import com.android.systemui.statusbar.SuperStatusBarViewFactory; @@ -51,6 +52,7 @@ public class StatusBarWindowController {      private final State mCurrentState = new State();      private ViewGroup mStatusBarView; +    private ViewGroup mLaunchAnimationContainer;      private WindowManager.LayoutParams mLp;      private final WindowManager.LayoutParams mLpChanged; @@ -62,6 +64,8 @@ public class StatusBarWindowController {          mWindowManager = windowManager;          mSuperStatusBarViewFactory = superStatusBarViewFactory;          mStatusBarView = mSuperStatusBarViewFactory.getStatusBarWindowView(); +        mLaunchAnimationContainer = mStatusBarView.findViewById( +                R.id.status_bar_launch_animation_container);          mLpChanged = new WindowManager.LayoutParams();          mResources = resources; @@ -124,13 +128,38 @@ public class StatusBarWindowController {          apply(mCurrentState);      } -    private void applyHeight() { -        mLpChanged.height = mBarHeight; +    /** +     * Return the container in which we should run launch animations started from the status bar and +     * expanding into the opening window. +     * +     * @see #setLaunchAnimationRunning +     */ +    public ViewGroup getLaunchAnimationContainer() { +        return mLaunchAnimationContainer; +    } + +    /** +     * Set whether a launch animation is currently running. If true, this will ensure that the +     * window matches its parent height so that the animation is not clipped by the normal status +     * bar height. +     */ +    public void setLaunchAnimationRunning(boolean isLaunchAnimationRunning) { +        if (isLaunchAnimationRunning == mCurrentState.mIsLaunchAnimationRunning) { +            return; +        } + +        mCurrentState.mIsLaunchAnimationRunning = isLaunchAnimationRunning; +        apply(mCurrentState); +    } + +    private void applyHeight(State state) { +        mLpChanged.height = +                state.mIsLaunchAnimationRunning ? ViewGroup.LayoutParams.MATCH_PARENT : mBarHeight;      }      private void apply(State state) {          applyForceStatusBarVisibleFlag(state); -        applyHeight(); +        applyHeight(state);          if (mLp != null && mLp.copyFrom(mLpChanged) != 0) {              mWindowManager.updateViewLayout(mStatusBarView, mLp);          } @@ -138,10 +167,11 @@ public class StatusBarWindowController {      private static class State {          boolean mForceStatusBarVisible; +        boolean mIsLaunchAnimationRunning;      }      private void applyForceStatusBarVisibleFlag(State state) { -        if (state.mForceStatusBarVisible) { +        if (state.mForceStatusBarVisible || state.mIsLaunchAnimationRunning) {              mLpChanged.privateFlags |= PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;          } else {              mLpChanged.privateFlags &= ~PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java index 66e1c2e1b571..ae11a74748cd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java @@ -62,7 +62,6 @@ import com.android.systemui.statusbar.SuperStatusBarViewFactory;  import com.android.systemui.statusbar.SysuiStatusBarStateController;  import com.android.systemui.statusbar.VibratorHelper;  import com.android.systemui.statusbar.charging.WiredChargingRippleController; -import com.android.systemui.statusbar.events.PrivacyDotViewController;  import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;  import com.android.systemui.statusbar.notification.DynamicPrivacyController;  import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; @@ -91,6 +90,7 @@ import com.android.systemui.statusbar.phone.ShadeController;  import com.android.systemui.statusbar.phone.StatusBar;  import com.android.systemui.statusbar.phone.StatusBarIconController;  import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; +import com.android.systemui.statusbar.phone.StatusBarLocationPublisher;  import com.android.systemui.statusbar.phone.StatusBarNotificationActivityStarter;  import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager;  import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController; @@ -212,7 +212,7 @@ public interface StatusBarPhoneModule {              WiredChargingRippleController chargingRippleAnimationController,              OngoingCallController ongoingCallController,              SystemStatusAnimationScheduler animationScheduler, -            PrivacyDotViewController dotViewController, +            StatusBarLocationPublisher locationPublisher,              FeatureFlags featureFlags,              KeyguardUnlockAnimationController keyguardUnlockAnimationController) {          return new StatusBar( @@ -298,7 +298,7 @@ public interface StatusBarPhoneModule {                  chargingRippleAnimationController,                  ongoingCallController,                  animationScheduler, -                dotViewController, +                locationPublisher,                  featureFlags,                  keyguardUnlockAnimationController);      } diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java index b95545576e56..10c4a55ad240 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java @@ -675,7 +675,6 @@ public class BubblesManager implements Dumpable {          }          try {              int flags = Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION; -            flags |= Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE;              mBarService.onNotificationBubbleChanged(entry.getKey(), true, flags);          } catch (RemoteException e) {              Log.e(TAG, e.getMessage()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt index fbba09a255e7..897d78b2ba0e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt @@ -11,7 +11,8 @@ import android.view.IRemoteAnimationFinishedCallback  import android.view.RemoteAnimationAdapter  import android.view.RemoteAnimationTarget  import android.view.SurfaceControl -import android.view.View +import android.view.ViewGroup +import android.widget.LinearLayout  import androidx.test.filters.SmallTest  import com.android.systemui.SysuiTestCase  import junit.framework.Assert.assertFalse @@ -36,8 +37,8 @@ import kotlin.concurrent.thread  @RunWithLooper  class ActivityLaunchAnimatorTest : SysuiTestCase() {      private val activityLaunchAnimator = ActivityLaunchAnimator(mContext) -    private val rootView = View(mContext) -    @Spy private val controller = TestLaunchAnimatorController(rootView) +    private val launchContainer = LinearLayout(mContext) +    @Spy private val controller = TestLaunchAnimatorController(launchContainer)      @Mock lateinit var iCallback: IRemoteAnimationFinishedCallback      @get:Rule val rule = MockitoJUnit.rule() @@ -146,10 +147,8 @@ class ActivityLaunchAnimatorTest : SysuiTestCase() {   * outside of the main thread.   */  private class TestLaunchAnimatorController( -    private val rootView: View +    override var launchContainer: ViewGroup  ) : ActivityLaunchAnimator.Controller { -    override fun getRootView(): View = rootView -      override fun createAnimatorState() = ActivityLaunchAnimator.State(              top = 100,              bottom = 200, diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/ProximityClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/ProximityClassifierTest.java index 60786f6afe99..1c3922a57368 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/ProximityClassifierTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/ProximityClassifierTest.java @@ -29,8 +29,8 @@ import android.view.MotionEvent;  import androidx.test.filters.SmallTest; +import com.android.systemui.plugins.FalsingManager;  import com.android.systemui.util.DeviceConfigProxyFake; -import com.android.systemui.util.sensors.ProximitySensor;  import org.junit.After;  import org.junit.Before; @@ -149,8 +149,17 @@ public class ProximityClassifierTest extends ClassifierTest {          motionEvent.recycle();      } -    private ProximitySensor.ThresholdSensorEvent createSensorEvent( -            boolean covered, long timestampMs) { -        return new ProximitySensor.ThresholdSensorEvent(covered, timestampMs * NS_PER_MS); +    private FalsingManager.ProximityEvent createSensorEvent(boolean covered, long timestampMs) { +        return new FalsingManager.ProximityEvent() { +            @Override +            public boolean getCovered() { +                return covered; +            } + +            @Override +            public long getTimestampNs() { +                return timestampMs * NS_PER_MS; +            } +        };      }  } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt index 94252d2b8331..800daa1e96aa 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt @@ -17,7 +17,6 @@  package com.android.systemui.media  import android.content.Intent -import android.content.res.ColorStateList  import android.graphics.Color  import android.graphics.drawable.GradientDrawable  import android.graphics.drawable.RippleDrawable @@ -222,17 +221,6 @@ public class MediaControlPanelTest : SysuiTestCase() {      }      @Test -    fun bindBackgroundColor() { -        player.attachPlayer(holder) -        val state = MediaData(USER_ID, true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(), -                emptyList(), PACKAGE, session.getSessionToken(), null, device, true, null) -        player.bindPlayer(state, PACKAGE) -        val list = ArgumentCaptor.forClass(ColorStateList::class.java) -        verify(view).setBackgroundTintList(list.capture()) -        assertThat(list.value).isEqualTo(ColorStateList.valueOf(BG_COLOR)) -    } - -    @Test      fun bindDevice() {          player.attachPlayer(holder)          val state = MediaData(USER_ID, true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(), diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt index d86dfa5fa5f7..406f40c75735 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt @@ -28,6 +28,7 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManager  import com.android.systemui.statusbar.StatusBarState  import com.android.systemui.statusbar.SysuiStatusBarStateController  import com.android.systemui.statusbar.phone.KeyguardBypassController +import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager  import com.android.systemui.statusbar.policy.KeyguardStateController  import com.android.systemui.util.animation.UniqueObjectHostView  import org.junit.Assert.assertNotNull @@ -73,6 +74,8 @@ class MediaHierarchyManagerTest : SysuiTestCase() {      private lateinit var mediaCarouselController: MediaCarouselController      @Mock      private lateinit var wakefulnessLifecycle: WakefulnessLifecycle +    @Mock +    private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager      @Captor      private lateinit var wakefullnessObserver: ArgumentCaptor<(WakefulnessLifecycle.Observer)>      @JvmField @@ -90,7 +93,8 @@ class MediaHierarchyManagerTest : SysuiTestCase() {                  bypassController,                  mediaCarouselController,                  notificationLockscreenUserManager, -                wakefulnessLifecycle) +                wakefulnessLifecycle, +                statusBarKeyguardViewManager)          verify(wakefulnessLifecycle).addObserver(wakefullnessObserver.capture())          setupHost(lockHost, MediaHierarchyManager.LOCATION_LOCKSCREEN)          setupHost(qsHost, MediaHierarchyManager.LOCATION_QS) @@ -98,7 +102,6 @@ class MediaHierarchyManagerTest : SysuiTestCase() {          `when`(statusBarStateController.state).thenReturn(StatusBarState.SHADE)          // We'll use the viewmanager to verify a few calls below, let's reset this.          clearInvocations(mediaCarouselController) -      }      private fun setupHost(host: MediaHost, location: Int) { @@ -125,7 +128,8 @@ class MediaHierarchyManagerTest : SysuiTestCase() {          observer.onStartedGoingToSleep()          clearInvocations(mediaCarouselController)          mediaHiearchyManager.qsExpansion = 0.0f -        verify(mediaCarouselController, times(0)).onDesiredLocationChanged(ArgumentMatchers.anyInt(), +        verify(mediaCarouselController, times(0)) +                .onDesiredLocationChanged(ArgumentMatchers.anyInt(),                  any(MediaHostState::class.java), anyBoolean(), anyLong(), anyLong())      } diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarRotationContextTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarRotationContextTest.java index b85af4846390..47f41836f1a6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarRotationContextTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarRotationContextTest.java @@ -62,8 +62,8 @@ public class NavigationBarRotationContextTest extends SysuiTestCase {          final View view = new View(mContext);          mRotationButton = mock(RotationButton.class); -        mRotationButtonController = spy(new RotationButtonController(mContext, 0, 0)); -        mRotationButtonController.setRotationButton(mRotationButton, (visibility) -> {}); +        mRotationButtonController = spy(new RotationButtonController(mContext, 0, 0, +                mRotationButton, (visibility) -> {}));          final KeyButtonDrawable kbd = mock(KeyButtonDrawable.class);          doReturn(view).when(mRotationButton).getCurrentView();          doReturn(true).when(mRotationButton).acceptRotationProposal(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java index cc322620eb57..0dd1f6816787 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java @@ -24,7 +24,6 @@ import static com.google.common.truth.Truth.assertThat;  import static org.mockito.ArgumentMatchers.any;  import static org.mockito.ArgumentMatchers.anyString;  import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.isNull;  import static org.mockito.Mockito.mock;  import static org.mockito.Mockito.never;  import static org.mockito.Mockito.times; @@ -59,6 +58,7 @@ import androidx.test.filters.SmallTest;  import com.android.internal.appwidget.IAppWidgetService;  import com.android.systemui.R;  import com.android.systemui.SysuiTestCase; +import com.android.systemui.people.widget.PeopleSpaceWidgetManager;  import com.android.systemui.people.widget.PeopleTileKey;  import com.android.systemui.statusbar.NotificationListener;  import com.android.systemui.statusbar.notification.NotificationEntryManager; @@ -73,6 +73,7 @@ import org.mockito.MockitoAnnotations;  import java.util.List;  import java.util.Map; +import java.util.Optional;  @RunWith(AndroidTestingRunner.class)  @SmallTest @@ -188,6 +189,8 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase {      private PackageManager mPackageManager;      @Mock      private NotificationEntryManager mNotificationEntryManager; +    @Mock +    private PeopleSpaceWidgetManager mPeopleSpaceWidgetManager;      private Bundle mOptions; @@ -212,8 +215,8 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase {          when(resources.getConfiguration()).thenReturn(configuration);          when(resources.getDisplayMetrics()).thenReturn(displayMetrics);          when(mMockContext.getContentResolver()).thenReturn(mMockContentResolver); -        when(mMockContentResolver.query(any(Uri.class), any(), anyString(), any(), -                isNull())).thenReturn(mMockCursor); +        when(mMockContentResolver.query(any(Uri.class), any(), any(), any(), +                any())).thenReturn(mMockCursor);          when(mMockContext.getString(R.string.birthday_status)).thenReturn(                  mContext.getString(R.string.birthday_status));          when(mMockContext.getString(R.string.basic_status)).thenReturn( @@ -236,7 +239,8 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase {                          .build();          PeopleTileKey key = new PeopleTileKey(tile);          PeopleSpaceTile actual = PeopleSpaceUtils -                .augmentTileFromNotification(mContext, tile, key, mNotificationEntry1, 0); +                .augmentTileFromNotification(mContext, tile, key, mNotificationEntry1, 0, +                        Optional.empty());          assertThat(actual.getNotificationContent().toString()).isEqualTo(NOTIFICATION_TEXT_2);          assertThat(actual.getNotificationSender()).isEqualTo(null); @@ -275,7 +279,8 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase {                          .build();          PeopleTileKey key = new PeopleTileKey(tile);          PeopleSpaceTile actual = PeopleSpaceUtils -                .augmentTileFromNotification(mContext, tile, key, notificationEntry, 0); +                .augmentTileFromNotification(mContext, tile, key, notificationEntry, 0, +                        Optional.empty());          assertThat(actual.getNotificationContent().toString()).isEqualTo(NOTIFICATION_TEXT_2);          assertThat(actual.getNotificationSender().toString()).isEqualTo("name"); @@ -291,7 +296,8 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase {                          .build();          PeopleTileKey key = new PeopleTileKey(tile);          PeopleSpaceTile actual = PeopleSpaceUtils -                .augmentTileFromNotification(mContext, tile, key, mNotificationEntry3, 0); +                .augmentTileFromNotification(mContext, tile, key, mNotificationEntry3, 0, +                        Optional.empty());          assertThat(actual.getNotificationContent()).isEqualTo(null);      } @@ -308,10 +314,11 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase {          Map<Integer, PeopleSpaceTile> widgetIdToTile = Map.of(WIDGET_ID_WITH_SHORTCUT,                  new PeopleSpaceTile.Builder(mShortcutInfoWithoutPerson,                          mContext.getSystemService(LauncherApps.class)).build()); -        PeopleSpaceUtils.getBirthdays(mMockContext, mAppWidgetManager, +        PeopleSpaceUtils.getDataFromContacts(mMockContext, mPeopleSpaceWidgetManager,                  widgetIdToTile, widgetIdsArray); -        verify(mAppWidgetManager, never()).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT), +        verify(mPeopleSpaceWidgetManager, never()).updateAppWidgetOptionsAndView( +                eq(WIDGET_ID_WITH_SHORTCUT),                  any());      } @@ -328,10 +335,11 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase {                  new PeopleSpaceTile.Builder(mShortcutInfoWithoutPerson,                          mContext.getSystemService(LauncherApps.class)).setBirthdayText(                          mContext.getString(R.string.birthday_status)).build()); -        PeopleSpaceUtils.getBirthdays(mMockContext, mAppWidgetManager, +        PeopleSpaceUtils.getDataFromContacts(mMockContext, mPeopleSpaceWidgetManager,                  widgetIdToTile, widgetIdsArray); -        verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT), +        verify(mPeopleSpaceWidgetManager, times(1)).updateAppWidgetOptionsAndView( +                eq(WIDGET_ID_WITH_SHORTCUT),                  any());      } @@ -363,10 +371,11 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase {                  new PeopleSpaceTile.Builder(mShortcutInfo,                          mContext.getSystemService(LauncherApps.class)).setBirthdayText(                          mContext.getString(R.string.birthday_status)).build()); -        PeopleSpaceUtils.getBirthdays(mMockContext, mAppWidgetManager, +        PeopleSpaceUtils.getDataFromContacts(mMockContext, mPeopleSpaceWidgetManager,                  widgetIdToTile, widgetIdsArray); -        verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT), +        verify(mPeopleSpaceWidgetManager, times(1)).updateAppWidgetOptionsAndView( +                eq(WIDGET_ID_WITH_SHORTCUT),                  any());      } @@ -375,6 +384,9 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase {          int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT};          when(mMockCursor.moveToNext()).thenReturn(true, false, true, false);          when(mMockCursor.getString(eq(TEST_COLUMN_INDEX))).thenReturn(TEST_LOOKUP_KEY); +        when(mMockCursor.getInt(eq(TEST_COLUMN_INDEX + 1))).thenReturn(1); +        when(mMockCursor.getColumnIndex(eq(ContactsContract.Contacts.STARRED))).thenReturn( +                TEST_COLUMN_INDEX + 1);          when(mMockCursor.getColumnIndex(eq(ContactsContract.CommonDataKinds.Event.LOOKUP_KEY)          )).thenReturn(TEST_COLUMN_INDEX); @@ -383,10 +395,11 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase {                  new PeopleSpaceTile.Builder(mShortcutInfo,                          mContext.getSystemService(LauncherApps.class)).setBirthdayText(                          mContext.getString(R.string.birthday_status)).build()); -        PeopleSpaceUtils.getBirthdays(mMockContext, mAppWidgetManager, +        PeopleSpaceUtils.getDataFromContacts(mMockContext, mPeopleSpaceWidgetManager,                  widgetIdToTile, widgetIdsArray); -        verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT), +        verify(mPeopleSpaceWidgetManager, times(1)).updateAppWidgetOptionsAndView( +                eq(WIDGET_ID_WITH_SHORTCUT),                  any());      }  } diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java index 764cdee7e36d..228e5e8d481d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java @@ -21,13 +21,20 @@ import static android.app.people.ConversationStatus.ACTIVITY_BIRTHDAY;  import static android.app.people.ConversationStatus.ACTIVITY_GAME;  import static android.app.people.ConversationStatus.ACTIVITY_NEW_STORY;  import static android.app.people.ConversationStatus.AVAILABILITY_AVAILABLE; +import static android.app.people.PeopleSpaceTile.BLOCK_CONVERSATIONS; +import static android.app.people.PeopleSpaceTile.SHOW_CONTACTS; +import static android.app.people.PeopleSpaceTile.SHOW_IMPORTANT_CONVERSATIONS; +import static android.app.people.PeopleSpaceTile.SHOW_STARRED_CONTACTS;  import static android.appwidget.AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH; +import static com.android.systemui.people.PeopleSpaceUtils.STARRED_CONTACT; +import static com.android.systemui.people.PeopleSpaceUtils.VALID_CONTACT;  import static com.android.systemui.people.widget.AppWidgetOptionsHelper.OPTIONS_PEOPLE_TILE;  import static com.google.common.truth.Truth.assertThat;  import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals;  import static org.mockito.ArgumentMatchers.anyString;  import static org.mockito.Mockito.mock;  import static org.mockito.Mockito.when; @@ -53,6 +60,7 @@ import androidx.test.filters.SmallTest;  import com.android.systemui.R;  import com.android.systemui.SysuiTestCase; +import com.android.systemui.people.widget.PeopleTileKey;  import org.junit.Before;  import org.junit.Test; @@ -148,14 +156,14 @@ public class PeopleTileViewHelperTest extends SysuiTestCase {          TextView textView = mock(TextView.class);          when(textView.getLineHeight()).thenReturn(16);          when(mPackageManager.getApplicationIcon(anyString())).thenReturn(null); -        mPeopleTileViewHelper = new PeopleTileViewHelper(mContext, -                PERSON_TILE, 0, mOptions); +        mPeopleTileViewHelper = getPeopleTileViewHelper( +                PERSON_TILE, mOptions);      }      @Test      public void testCreateRemoteViewsWithLastInteractionTimeUnderOneDayHidden() { -        RemoteViews views = new PeopleTileViewHelper(mContext, -                PERSON_TILE_WITHOUT_NOTIFICATION, 0, mOptions).getViews(); +        RemoteViews views = getPeopleTileViewHelper( +                PERSON_TILE_WITHOUT_NOTIFICATION, mOptions).getViews();          View result = views.apply(mContext, null);          // Not showing last interaction. @@ -165,8 +173,8 @@ public class PeopleTileViewHelperTest extends SysuiTestCase {                  getSizeInDp(R.dimen.required_width_for_large));          mOptions.putInt(OPTION_APPWIDGET_MIN_WIDTH,                  getSizeInDp(R.dimen.required_height_for_large)); -        RemoteViews largeView = new PeopleTileViewHelper(mContext, -                PERSON_TILE_WITHOUT_NOTIFICATION, 0, mOptions).getViews(); +        RemoteViews largeView = getPeopleTileViewHelper( +                PERSON_TILE_WITHOUT_NOTIFICATION, mOptions).getViews();          View largeResult = largeView.apply(mContext, null);          // Not showing last interaction. @@ -178,8 +186,8 @@ public class PeopleTileViewHelperTest extends SysuiTestCase {          PeopleSpaceTile tileWithLastInteraction =                  PERSON_TILE_WITHOUT_NOTIFICATION.toBuilder().setLastInteractionTimestamp(                          123445L).build(); -        RemoteViews views = new PeopleTileViewHelper(mContext, -                tileWithLastInteraction, 0, mOptions).getViews(); +        RemoteViews views = getPeopleTileViewHelper( +                tileWithLastInteraction, mOptions).getViews();          View result = views.apply(mContext, null);          TextView name = (TextView) result.findViewById(R.id.name); @@ -197,8 +205,8 @@ public class PeopleTileViewHelperTest extends SysuiTestCase {          mOptions.putInt(OPTION_APPWIDGET_MIN_WIDTH,                  getSizeInDp(R.dimen.required_width_for_medium) - 1); -        RemoteViews smallView = new PeopleTileViewHelper(mContext, -                tileWithLastInteraction, 0, mOptions).getViews(); +        RemoteViews smallView = getPeopleTileViewHelper( +                tileWithLastInteraction, mOptions).getViews();          View smallResult = smallView.apply(mContext, null);          // Show name over predefined icon. @@ -214,8 +222,8 @@ public class PeopleTileViewHelperTest extends SysuiTestCase {                  getSizeInDp(R.dimen.required_width_for_large));          mOptions.putInt(OPTION_APPWIDGET_MIN_WIDTH,                  getSizeInDp(R.dimen.required_height_for_large)); -        RemoteViews largeView = new PeopleTileViewHelper(mContext, -                tileWithLastInteraction, 0, mOptions).getViews(); +        RemoteViews largeView = getPeopleTileViewHelper( +                tileWithLastInteraction, mOptions).getViews();          View largeResult = largeView.apply(mContext, null);          name = (TextView) largeResult.findViewById(R.id.name); @@ -240,8 +248,8 @@ public class PeopleTileViewHelperTest extends SysuiTestCase {                                  new ConversationStatus.Builder(                                          PERSON_TILE_WITHOUT_NOTIFICATION.getId(),                                          ACTIVITY_GAME).build())).build(); -        RemoteViews views = new PeopleTileViewHelper(mContext, -                tileWithAvailabilityAndNewStory, 0, mOptions).getViews(); +        RemoteViews views = getPeopleTileViewHelper( +                tileWithAvailabilityAndNewStory, mOptions).getViews();          View result = views.apply(mContext, null);          TextView name = (TextView) result.findViewById(R.id.name); @@ -257,8 +265,8 @@ public class PeopleTileViewHelperTest extends SysuiTestCase {          mOptions.putInt(OPTION_APPWIDGET_MIN_WIDTH,                  getSizeInDp(R.dimen.required_width_for_medium) - 1); -        RemoteViews smallView = new PeopleTileViewHelper(mContext, -                tileWithAvailabilityAndNewStory, 0, mOptions).getViews(); +        RemoteViews smallView = getPeopleTileViewHelper( +                tileWithAvailabilityAndNewStory, mOptions).getViews();          View smallResult = smallView.apply(mContext, null);          // Show name rather than game type. @@ -274,8 +282,8 @@ public class PeopleTileViewHelperTest extends SysuiTestCase {                  getSizeInDp(R.dimen.required_width_for_large));          mOptions.putInt(OPTION_APPWIDGET_MIN_WIDTH,                  getSizeInDp(R.dimen.required_height_for_large)); -        RemoteViews largeView = new PeopleTileViewHelper(mContext, -                tileWithAvailabilityAndNewStory, 0, mOptions).getViews(); +        RemoteViews largeView = getPeopleTileViewHelper( +                tileWithAvailabilityAndNewStory, mOptions).getViews();          View largeResult = largeView.apply(mContext, null);          name = (TextView) largeResult.findViewById(R.id.name); @@ -298,8 +306,8 @@ public class PeopleTileViewHelperTest extends SysuiTestCase {                                  NEW_STORY_WITH_AVAILABILITY, new ConversationStatus.Builder(                                          PERSON_TILE_WITHOUT_NOTIFICATION.getId(),                                          ACTIVITY_BIRTHDAY).build())).build(); -        RemoteViews views = new PeopleTileViewHelper(mContext, -                tileWithStatusTemplate, 0, mOptions).getViews(); +        RemoteViews views = getPeopleTileViewHelper( +                tileWithStatusTemplate, mOptions).getViews();          View result = views.apply(mContext, null);          TextView name = (TextView) result.findViewById(R.id.name); @@ -318,8 +326,8 @@ public class PeopleTileViewHelperTest extends SysuiTestCase {          mOptions.putInt(OPTION_APPWIDGET_MIN_WIDTH,                  getSizeInDp(R.dimen.required_width_for_medium) - 1); -        RemoteViews smallView = new PeopleTileViewHelper(mContext, -                tileWithStatusTemplate, 0, mOptions).getViews(); +        RemoteViews smallView = getPeopleTileViewHelper( +                tileWithStatusTemplate, mOptions).getViews();          View smallResult = smallView.apply(mContext, null);          // Show icon instead of name. @@ -336,8 +344,8 @@ public class PeopleTileViewHelperTest extends SysuiTestCase {                  getSizeInDp(R.dimen.required_width_for_large));          mOptions.putInt(OPTION_APPWIDGET_MIN_WIDTH,                  getSizeInDp(R.dimen.required_height_for_large)); -        RemoteViews largeView = new PeopleTileViewHelper(mContext, -                tileWithStatusTemplate, 0, mOptions).getViews(); +        RemoteViews largeView = getPeopleTileViewHelper( +                tileWithStatusTemplate, mOptions).getViews();          View largeResult = largeView.apply(mContext, null);          name = (TextView) largeResult.findViewById(R.id.name); @@ -362,8 +370,8 @@ public class PeopleTileViewHelperTest extends SysuiTestCase {                  PERSON_TILE_WITHOUT_NOTIFICATION.toBuilder().setStatuses(                          Arrays.asList(GAME_STATUS,                                  NEW_STORY_WITH_AVAILABILITY)).build(); -        RemoteViews views = new PeopleTileViewHelper(mContext, -                tileWithStatusTemplate, 0, mOptions).getViews(); +        RemoteViews views = getPeopleTileViewHelper( +                tileWithStatusTemplate, mOptions).getViews();          View result = views.apply(mContext, null);          TextView name = (TextView) result.findViewById(R.id.name); @@ -381,8 +389,8 @@ public class PeopleTileViewHelperTest extends SysuiTestCase {          mOptions.putInt(OPTION_APPWIDGET_MIN_WIDTH,                  getSizeInDp(R.dimen.required_width_for_medium) - 1); -        RemoteViews smallView = new PeopleTileViewHelper(mContext, -                tileWithStatusTemplate, 0, mOptions).getViews(); +        RemoteViews smallView = getPeopleTileViewHelper( +                tileWithStatusTemplate, mOptions).getViews();          View smallResult = smallView.apply(mContext, null);          // Show icon instead of name. @@ -399,8 +407,8 @@ public class PeopleTileViewHelperTest extends SysuiTestCase {                  getSizeInDp(R.dimen.required_width_for_large));          mOptions.putInt(OPTION_APPWIDGET_MIN_WIDTH,                  getSizeInDp(R.dimen.required_height_for_large)); -        RemoteViews largeView = new PeopleTileViewHelper(mContext, -                tileWithStatusTemplate, 0, mOptions).getViews(); +        RemoteViews largeView = getPeopleTileViewHelper( +                tileWithStatusTemplate, mOptions).getViews();          View largeResult = largeView.apply(mContext, null);          name = (TextView) largeResult.findViewById(R.id.name); @@ -420,14 +428,128 @@ public class PeopleTileViewHelperTest extends SysuiTestCase {      }      @Test +    public void testCreateRemoteViewsWithPackageSuspended() { +        PeopleSpaceTile tile = PERSON_TILE.toBuilder() +                .setIsPackageSuspended(true) +                .build(); +        RemoteViews views = getPeopleTileViewHelper( +                tile, mOptions).getViews(); +        View result = views.apply(mContext, null); + +        assertEquals(result.getSourceLayoutResId(), R.layout.people_tile_empty_layout); +    } + +    @Test +    public void testCreateRemoteViewsWithUserQuieted() { +        PeopleSpaceTile tile = PERSON_TILE.toBuilder() +                .setIsUserQuieted(true) +                .build(); +        RemoteViews views = getPeopleTileViewHelper( +                tile, mOptions).getViews(); +        View result = views.apply(mContext, null); + +        assertEquals(result.getSourceLayoutResId(), R.layout.people_tile_empty_layout); +    } + +    @Test +    public void testCreateRemoteViewsWithDndBlocking() { +        PeopleSpaceTile tileWithDndBlocking = PERSON_TILE.toBuilder() +                .setNotificationPolicyState(BLOCK_CONVERSATIONS) +                .build(); +        RemoteViews views = getPeopleTileViewHelper( +                tileWithDndBlocking, mOptions).getViews(); +        View result = views.apply(mContext, null); + +        assertEquals(result.getSourceLayoutResId(), R.layout.people_tile_empty_layout); + +        tileWithDndBlocking = PERSON_TILE.toBuilder() +                .setNotificationPolicyState(BLOCK_CONVERSATIONS) +                .setCanBypassDnd(true) +                .build(); +        views = getPeopleTileViewHelper( +                tileWithDndBlocking, mOptions).getViews(); +        result = views.apply(mContext, null); + +        assertNotEquals(result.getSourceLayoutResId(), R.layout.people_tile_empty_layout); + +        tileWithDndBlocking = PERSON_TILE.toBuilder() +                .setNotificationPolicyState(SHOW_IMPORTANT_CONVERSATIONS) +                .build(); +        views = getPeopleTileViewHelper( +                tileWithDndBlocking, mOptions).getViews(); +        result = views.apply(mContext, null); + +        assertEquals(result.getSourceLayoutResId(), R.layout.people_tile_empty_layout); + +        tileWithDndBlocking = PERSON_TILE.toBuilder() +                .setNotificationPolicyState(SHOW_IMPORTANT_CONVERSATIONS) +                .setIsImportantConversation(true) +                .build(); +        views = getPeopleTileViewHelper( +                tileWithDndBlocking, mOptions).getViews(); +        result = views.apply(mContext, null); + +        assertNotEquals(result.getSourceLayoutResId(), R.layout.people_tile_empty_layout); + +        tileWithDndBlocking = PERSON_TILE.toBuilder() +                .setNotificationPolicyState(SHOW_STARRED_CONTACTS) +                .setContactAffinity(VALID_CONTACT) +                .build(); +        views = getPeopleTileViewHelper( +                tileWithDndBlocking, mOptions).getViews(); +        result = views.apply(mContext, null); + +        assertEquals(result.getSourceLayoutResId(), R.layout.people_tile_empty_layout); + +        tileWithDndBlocking = PERSON_TILE.toBuilder() +                .setNotificationPolicyState(SHOW_STARRED_CONTACTS) +                .setContactAffinity(STARRED_CONTACT) +                .build(); +        views = getPeopleTileViewHelper( +                tileWithDndBlocking, mOptions).getViews(); +        result = views.apply(mContext, null); + +        assertNotEquals(result.getSourceLayoutResId(), R.layout.people_tile_empty_layout); + +        tileWithDndBlocking = PERSON_TILE.toBuilder() +                .setNotificationPolicyState(SHOW_CONTACTS) +                .setContactAffinity(STARRED_CONTACT) +                .build(); +        views = getPeopleTileViewHelper( +                tileWithDndBlocking, mOptions).getViews(); +        result = views.apply(mContext, null); + +        assertNotEquals(result.getSourceLayoutResId(), R.layout.people_tile_empty_layout); + +        tileWithDndBlocking = PERSON_TILE.toBuilder() +                .setNotificationPolicyState(SHOW_CONTACTS) +                .setContactAffinity(VALID_CONTACT) +                .build(); +        views = getPeopleTileViewHelper( +                tileWithDndBlocking, mOptions).getViews(); +        result = views.apply(mContext, null); + +        assertNotEquals(result.getSourceLayoutResId(), R.layout.people_tile_empty_layout); + +        tileWithDndBlocking = PERSON_TILE.toBuilder() +                .setNotificationPolicyState(SHOW_CONTACTS) +                .build(); +        views = getPeopleTileViewHelper( +                tileWithDndBlocking, mOptions).getViews(); +        result = views.apply(mContext, null); + +        assertEquals(result.getSourceLayoutResId(), R.layout.people_tile_empty_layout); +    } + +    @Test      public void testCreateRemoteViewsWithMissedCallNotification() {          PeopleSpaceTile tileWithMissedCallNotification = PERSON_TILE.toBuilder()                  .setNotificationDataUri(null)                  .setNotificationCategory(CATEGORY_MISSED_CALL)                  .setNotificationContent(MISSED_CALL)                  .build(); -        RemoteViews views = new PeopleTileViewHelper(mContext, -                tileWithMissedCallNotification, 0, mOptions).getViews(); +        RemoteViews views = getPeopleTileViewHelper( +                tileWithMissedCallNotification, mOptions).getViews();          View result = views.apply(mContext, null);          TextView name = (TextView) result.findViewById(R.id.name); @@ -446,8 +568,8 @@ public class PeopleTileViewHelperTest extends SysuiTestCase {          mOptions.putInt(OPTION_APPWIDGET_MIN_WIDTH,                  getSizeInDp(R.dimen.required_width_for_medium) - 1); -        RemoteViews smallView = new PeopleTileViewHelper(mContext, -                tileWithMissedCallNotification, 0, mOptions).getViews(); +        RemoteViews smallView = getPeopleTileViewHelper( +                tileWithMissedCallNotification, mOptions).getViews();          View smallResult = smallView.apply(mContext, null);          // Show icon instead of name. @@ -463,8 +585,8 @@ public class PeopleTileViewHelperTest extends SysuiTestCase {                  getSizeInDp(R.dimen.required_width_for_large));          mOptions.putInt(OPTION_APPWIDGET_MIN_WIDTH,                  getSizeInDp(R.dimen.required_height_for_large)); -        RemoteViews largeView = new PeopleTileViewHelper(mContext, -                tileWithMissedCallNotification, 0, mOptions).getViews(); +        RemoteViews largeView = getPeopleTileViewHelper( +                tileWithMissedCallNotification, mOptions).getViews();          View largeResult = largeView.apply(mContext, null);          name = (TextView) largeResult.findViewById(R.id.name); @@ -489,8 +611,8 @@ public class PeopleTileViewHelperTest extends SysuiTestCase {                  .setNotificationDataUri(null)                  .setStatuses(Arrays.asList(GAME_STATUS,                          NEW_STORY_WITH_AVAILABILITY)).build(); -        RemoteViews views = new PeopleTileViewHelper(mContext, -                tileWithStatusAndNotification, 0, mOptions).getViews(); +        RemoteViews views = getPeopleTileViewHelper( +                tileWithStatusAndNotification, mOptions).getViews();          View result = views.apply(mContext, null);          TextView name = (TextView) result.findViewById(R.id.name); @@ -512,8 +634,8 @@ public class PeopleTileViewHelperTest extends SysuiTestCase {          mOptions.putInt(OPTION_APPWIDGET_MIN_WIDTH,                  getSizeInDp(R.dimen.required_width_for_medium) - 1); -        RemoteViews smallView = new PeopleTileViewHelper(mContext, -                tileWithStatusAndNotification, 0, mOptions).getViews(); +        RemoteViews smallView = getPeopleTileViewHelper( +                tileWithStatusAndNotification, mOptions).getViews();          View smallResult = smallView.apply(mContext, null);          // Show icon instead of name. @@ -531,8 +653,8 @@ public class PeopleTileViewHelperTest extends SysuiTestCase {                  getSizeInDp(R.dimen.required_width_for_large));          mOptions.putInt(OPTION_APPWIDGET_MIN_WIDTH,                  getSizeInDp(R.dimen.required_height_for_large)); -        RemoteViews largeView = new PeopleTileViewHelper(mContext, -                tileWithStatusAndNotification, 0, mOptions).getViews(); +        RemoteViews largeView = getPeopleTileViewHelper( +                tileWithStatusAndNotification, mOptions).getViews();          View largeResult = largeView.apply(mContext, null);          name = (TextView) largeResult.findViewById(R.id.name); @@ -561,8 +683,8 @@ public class PeopleTileViewHelperTest extends SysuiTestCase {                  .setNotificationDataUri(null)                  .setStatuses(Arrays.asList(GAME_STATUS,                          NEW_STORY_WITH_AVAILABILITY)).build(); -        RemoteViews views = new PeopleTileViewHelper(mContext, -                tileWithStatusAndNotification, 0, mOptions).getViews(); +        RemoteViews views = getPeopleTileViewHelper( +                tileWithStatusAndNotification, mOptions).getViews();          View result = views.apply(mContext, null);          TextView name = (TextView) result.findViewById(R.id.name); @@ -588,8 +710,8 @@ public class PeopleTileViewHelperTest extends SysuiTestCase {          mOptions.putInt(OPTION_APPWIDGET_MIN_WIDTH,                  getSizeInDp(R.dimen.required_width_for_medium) - 1); -        RemoteViews smallView = new PeopleTileViewHelper(mContext, -                tileWithStatusAndNotification, 0, mOptions).getViews(); +        RemoteViews smallView = getPeopleTileViewHelper( +                tileWithStatusAndNotification, mOptions).getViews();          View smallResult = smallView.apply(mContext, null);          // Show icon instead of name. @@ -607,8 +729,8 @@ public class PeopleTileViewHelperTest extends SysuiTestCase {                  getSizeInDp(R.dimen.required_width_for_large));          mOptions.putInt(OPTION_APPWIDGET_MIN_WIDTH,                  getSizeInDp(R.dimen.required_height_for_large)); -        RemoteViews largeView = new PeopleTileViewHelper(mContext, -                tileWithStatusAndNotification, 0, mOptions).getViews(); +        RemoteViews largeView = getPeopleTileViewHelper( +                tileWithStatusAndNotification, mOptions).getViews();          View largeResult = largeView.apply(mContext, null);          name = (TextView) largeResult.findViewById(R.id.name); @@ -642,8 +764,8 @@ public class PeopleTileViewHelperTest extends SysuiTestCase {                  .setStatuses(Arrays.asList(GAME_STATUS,                          NEW_STORY_WITH_AVAILABILITY))                  .setMessagesCount(2).build(); -        RemoteViews views = new PeopleTileViewHelper(mContext, -                tileWithStatusAndNotification, 0, mOptions).getViews(); +        RemoteViews views = getPeopleTileViewHelper( +                tileWithStatusAndNotification, mOptions).getViews();          View result = views.apply(mContext, null);          TextView name = (TextView) result.findViewById(R.id.name); @@ -665,8 +787,8 @@ public class PeopleTileViewHelperTest extends SysuiTestCase {          mOptions.putInt(OPTION_APPWIDGET_MIN_WIDTH,                  getSizeInDp(R.dimen.required_width_for_medium) - 1); -        RemoteViews smallView = new PeopleTileViewHelper(mContext, -                tileWithStatusAndNotification, 0, mOptions).getViews(); +        RemoteViews smallView = getPeopleTileViewHelper( +                tileWithStatusAndNotification, mOptions).getViews();          View smallResult = smallView.apply(mContext, null);          // Show icon instead of name. @@ -684,8 +806,8 @@ public class PeopleTileViewHelperTest extends SysuiTestCase {                  getSizeInDp(R.dimen.required_width_for_large));          mOptions.putInt(OPTION_APPWIDGET_MIN_WIDTH,                  getSizeInDp(R.dimen.required_height_for_large)); -        RemoteViews largeView = new PeopleTileViewHelper(mContext, -                tileWithStatusAndNotification, 0, mOptions).getViews(); +        RemoteViews largeView = getPeopleTileViewHelper( +                tileWithStatusAndNotification, mOptions).getViews();          View largeResult = largeView.apply(mContext, null);          name = (TextView) largeResult.findViewById(R.id.name); @@ -858,4 +980,9 @@ public class PeopleTileViewHelperTest extends SysuiTestCase {          return (int) (mContext.getResources().getDimension(dimenResourceId)                  / mContext.getResources().getDisplayMetrics().density);      } + +    private PeopleTileViewHelper getPeopleTileViewHelper(PeopleSpaceTile tile, Bundle options) { +        return new PeopleTileViewHelper(mContext, tile, 0, options, +                new PeopleTileKey(tile.getId(), 0, tile.getPackageName())); +    }  } diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java index 411fb02ba87a..f31f326c0c45 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java @@ -20,11 +20,32 @@ import static android.app.Notification.CATEGORY_MISSED_CALL;  import static android.app.Notification.EXTRA_PEOPLE_LIST;  import static android.app.NotificationManager.IMPORTANCE_DEFAULT;  import static android.app.NotificationManager.IMPORTANCE_HIGH; +import static android.app.NotificationManager.INTERRUPTION_FILTER_ALARMS; +import static android.app.NotificationManager.INTERRUPTION_FILTER_ALL; +import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY; +import static android.app.NotificationManager.Policy.CONVERSATION_SENDERS_IMPORTANT; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;  import static android.app.people.ConversationStatus.ACTIVITY_ANNIVERSARY;  import static android.app.people.ConversationStatus.ACTIVITY_BIRTHDAY;  import static android.app.people.ConversationStatus.ACTIVITY_GAME; +import static android.app.people.PeopleSpaceTile.BLOCK_CONVERSATIONS; +import static android.app.people.PeopleSpaceTile.SHOW_CONTACTS; +import static android.app.people.PeopleSpaceTile.SHOW_CONVERSATIONS; +import static android.app.people.PeopleSpaceTile.SHOW_IMPORTANT_CONVERSATIONS; +import static android.app.people.PeopleSpaceTile.SHOW_STARRED_CONTACTS; +import static android.content.Intent.ACTION_BOOT_COMPLETED; +import static android.content.Intent.ACTION_PACKAGES_SUSPENDED;  import static android.content.PermissionChecker.PERMISSION_GRANTED;  import static android.content.PermissionChecker.PERMISSION_HARD_DENIED; +import static android.service.notification.ZenPolicy.CONVERSATION_SENDERS_ANYONE;  import static com.android.systemui.people.PeopleSpaceUtils.EMPTY_STRING;  import static com.android.systemui.people.PeopleSpaceUtils.INVALID_USER_ID; @@ -73,6 +94,7 @@ import android.os.UserHandle;  import android.os.UserManager;  import android.service.notification.ConversationChannelWrapper;  import android.service.notification.StatusBarNotification; +import android.service.notification.ZenModeConfig;  import android.testing.AndroidTestingRunner;  import androidx.preference.PreferenceManager; @@ -89,6 +111,7 @@ import com.android.systemui.statusbar.notification.collection.NoManSimulator;  import com.android.systemui.statusbar.notification.collection.NoManSimulator.NotifEvent;  import com.android.systemui.statusbar.notification.collection.NotificationEntry;  import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; +import com.android.systemui.util.concurrency.FakeExecutor;  import com.android.systemui.util.time.FakeSystemClock;  import org.junit.Before; @@ -99,12 +122,14 @@ import org.mockito.Captor;  import org.mockito.Mock;  import org.mockito.MockitoAnnotations; +import java.lang.reflect.Field;  import java.util.ArrayList;  import java.util.Arrays;  import java.util.Collections;  import java.util.HashSet;  import java.util.List;  import java.util.Map; +import java.util.Optional;  import java.util.Set;  import java.util.stream.Collectors; @@ -158,6 +183,16 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {                      // Same contact uri.                      .setContactUri(URI)                      .build(); +    private static final int ALL_SUPPRESSED_VISUAL_EFFECTS = SUPPRESSED_EFFECT_SCREEN_OFF +            | SUPPRESSED_EFFECT_SCREEN_ON +            | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT +            | SUPPRESSED_EFFECT_AMBIENT +            | SUPPRESSED_EFFECT_STATUS_BAR +            | SUPPRESSED_EFFECT_BADGE +            | SUPPRESSED_EFFECT_LIGHTS +            | SUPPRESSED_EFFECT_PEEK +            | SUPPRESSED_EFFECT_NOTIFICATION_LIST; +      private ShortcutInfo mShortcutInfo;      private NotificationEntry mNotificationEntry; @@ -182,9 +217,13 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {      @Mock      private PackageManager mPackageManager;      @Mock -    private INotificationManager mNotificationManager; +    private INotificationManager mINotificationManager;      @Mock      private UserManager mUserManager; +    @Mock +    private NotificationManager mNotificationManager; +    @Mock +    private NotificationManager.Policy mNotificationPolicy;      @Captor      private ArgumentCaptor<NotificationHandler> mListenerCaptor; @@ -194,19 +233,16 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {      private final NoManSimulator mNoMan = new NoManSimulator();      private final FakeSystemClock mClock = new FakeSystemClock(); -    private PeopleSpaceWidgetProvider mProvider; +    private final FakeExecutor mFakeExecutor = new FakeExecutor(mClock);      @Before      public void setUp() throws Exception {          MockitoAnnotations.initMocks(this);          mLauncherApps = mock(LauncherApps.class);          mDependency.injectTestDependency(NotificationEntryManager.class, mNotificationEntryManager); -        mManager = new PeopleSpaceWidgetManager(mContext); -        mProvider = new PeopleSpaceWidgetProvider(); -        mProvider.setPeopleSpaceWidgetManager(mManager); -        mManager.setAppWidgetManager(mAppWidgetManager, mIPeopleManager, mPeopleManager, -                mLauncherApps, mNotificationEntryManager, mPackageManager, true, mProvider, -                mUserManager, mNotificationManager); +        mManager = new PeopleSpaceWidgetManager(mContext, mAppWidgetManager, mIPeopleManager, +                mPeopleManager, mLauncherApps, mNotificationEntryManager, mPackageManager, +                mUserManager, mINotificationManager, mNotificationManager, mFakeExecutor);          mManager.attach(mListenerService);          verify(mListenerService).addNotificationHandler(mListenerCaptor.capture()); @@ -218,7 +254,19 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {          addTileForWidget(PERSON_TILE_WITH_SAME_URI, WIDGET_ID_WITH_SAME_URI);          when(mAppWidgetManager.getAppWidgetOptions(eq(WIDGET_ID_WITHOUT_SHORTCUT)))                  .thenReturn(new Bundle()); +          when(mUserManager.isQuietModeEnabled(any())).thenReturn(false); +        when(mPackageManager.isPackageSuspended(any())).thenReturn(false); +        setFinalField("suppressedVisualEffects", ALL_SUPPRESSED_VISUAL_EFFECTS); +        when(mNotificationPolicy.allowConversationsFrom()).thenReturn(CONVERSATION_SENDERS_ANYONE); +        when(mNotificationPolicy.allowConversations()).thenReturn(false); +        when(mNotificationPolicy.allowMessagesFrom()).thenReturn(ZenModeConfig.SOURCE_ANYONE); +        when(mNotificationPolicy.allowMessages()).thenReturn(false); +        when(mNotificationManager.getNotificationPolicy()).thenReturn(mNotificationPolicy); +        when(mNotificationManager.getCurrentInterruptionFilter()).thenReturn( +                INTERRUPTION_FILTER_ALL); +        int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT}; +        when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray);          when(mMockContext.getPackageName()).thenReturn(TEST_PACKAGE_A);          when(mMockContext.getUserId()).thenReturn(0); @@ -242,7 +290,7 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {          ConversationChannelWrapper olderImportantConversation = getConversationChannelWrapper(                  SHORTCUT_ID + 2,                  true, 1); -        when(mNotificationManager.getConversations(anyBoolean())).thenReturn( +        when(mINotificationManager.getConversations(anyBoolean())).thenReturn(                  new ParceledListSlice(Arrays.asList(                          newerNonImportantConversation, newerImportantConversation,                          olderImportantConversation))); @@ -280,7 +328,7 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {          ConversationChannelWrapper olderImportantConversation = getConversationChannelWrapper(                  SHORTCUT_ID + 2,                  true, 1); -        when(mNotificationManager.getConversations(anyBoolean())).thenReturn( +        when(mINotificationManager.getConversations(anyBoolean())).thenReturn(                  new ParceledListSlice(Arrays.asList(                          newerNonImportantConversation, newerImportantConversation,                          olderImportantConversation))); @@ -306,7 +354,7 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {          ConversationChannelWrapper olderImportantConversation = getConversationChannelWrapper(                  SHORTCUT_ID + 2,                  true, 1); -        when(mNotificationManager.getConversations(anyBoolean())).thenReturn( +        when(mINotificationManager.getConversations(anyBoolean())).thenReturn(                  new ParceledListSlice(Arrays.asList(                          newerNonImportantConversation, newerImportantConversation,                          olderImportantConversation))); @@ -1027,8 +1075,7 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {      public void testDeleteAllWidgetsForConversationsUncachesShortcutAndRemovesListeners()              throws Exception {          addSecondWidgetForPersonTile(); -        mProvider.onUpdate(mContext, mAppWidgetManager, -                new int[]{WIDGET_ID_WITH_SHORTCUT, SECOND_WIDGET_ID_WITH_SHORTCUT}); +        mManager.updateWidgets(new int[]{WIDGET_ID_WITH_SHORTCUT, SECOND_WIDGET_ID_WITH_SHORTCUT});          // Delete only one widget for the conversation.          mManager.deleteWidgets(new int[]{WIDGET_ID_WITH_SHORTCUT}); @@ -1050,7 +1097,7 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {                  eq(LauncherApps.FLAG_CACHE_PEOPLE_TILE_SHORTCUTS));          // Delete all widgets for the conversation. -        mProvider.onDeleted(mContext, new int[]{SECOND_WIDGET_ID_WITH_SHORTCUT}); +        mManager.deleteWidgets(new int[]{SECOND_WIDGET_ID_WITH_SHORTCUT});          // Check deleted storage.          SharedPreferences secondWidgetSp = mContext.getSharedPreferences( @@ -1154,7 +1201,7 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {                  new PeopleTileKey(SHORTCUT_ID, 0, TEST_PACKAGE_A));          when(mIPeopleManager.getConversation(TEST_PACKAGE_A, 0, SHORTCUT_ID)).thenReturn(channel);          PeopleTileKey key = new PeopleTileKey(SHORTCUT_ID, 0, TEST_PACKAGE_A); -        PeopleSpaceTile tile = mManager.getTileFromPersistentStorage(key); +        PeopleSpaceTile tile = mManager.getTileFromPersistentStorage(key, WIDGET_ID_WITH_SHORTCUT);          assertThat(tile.getId()).isEqualTo(key.getShortcutId());      } @@ -1162,7 +1209,7 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {      public void testGetPeopleTileFromPersistentStorageNoConversation() throws RemoteException {          when(mIPeopleManager.getConversation(TEST_PACKAGE_A, 0, SHORTCUT_ID)).thenReturn(null);          PeopleTileKey key = new PeopleTileKey(SHORTCUT_ID, 0, TEST_PACKAGE_A); -        PeopleSpaceTile tile = mManager.getTileFromPersistentStorage(key); +        PeopleSpaceTile tile = mManager.getTileFromPersistentStorage(key, WIDGET_ID_WITH_SHORTCUT);          assertThat(tile).isNull();      } @@ -1195,18 +1242,25 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {      @Test      public void testAugmentTileFromNotifications() { +        clearStorage(); +        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext); +        assertThat(sp.getString(String.valueOf(WIDGET_ID_WITH_SHORTCUT), null)).isEqualTo(null);          PeopleSpaceTile tile =                  new PeopleSpaceTile                          .Builder(SHORTCUT_ID, "userName", ICON, new Intent())                          .setPackageName(TEST_PACKAGE_A)                          .setUserHandle(new UserHandle(0))                          .build(); +          PeopleTileKey key = new PeopleTileKey(tile);          PeopleSpaceTile actual = mManager.augmentTileFromNotifications(tile, key, EMPTY_STRING, -                        Map.of(new PeopleTileKey(mNotificationEntry), -                                new HashSet<>(Collections.singleton(mNotificationEntry)))); +                Map.of(new PeopleTileKey(mNotificationEntry), +                        new HashSet<>(Collections.singleton(mNotificationEntry))), +                Optional.of(WIDGET_ID_WITH_SHORTCUT));          assertThat(actual.getNotificationContent().toString()).isEqualTo(NOTIFICATION_CONTENT_1); +        assertThat(sp.getString(String.valueOf(WIDGET_ID_WITH_SHORTCUT), null)).isEqualTo( +                URI.toString());      }      @Test @@ -1221,7 +1275,8 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {          PeopleSpaceTile actual = mManager                  .augmentTileFromNotifications(tile, key, EMPTY_STRING,                          Map.of(new PeopleTileKey(mNotificationEntry), -                                new HashSet<>(Collections.singleton(mNotificationEntry)))); +                                new HashSet<>(Collections.singleton(mNotificationEntry))), +                        Optional.empty());          assertThat(actual.getNotificationContent()).isEqualTo(null);      } @@ -1238,7 +1293,8 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {                  .thenReturn(List.of(mNotificationEntry));          PeopleSpaceTile actual = -                mManager.augmentTileFromNotificationEntryManager(tile); +                mManager.augmentTileFromNotificationEntryManager(tile, +                        Optional.of(WIDGET_ID_WITH_SHORTCUT));          assertThat(actual.getNotificationContent().toString()).isEqualTo(NOTIFICATION_CONTENT_1); @@ -1246,6 +1302,202 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {                  .getVisibleNotifications();      } +    @Test +    public void testUpdateWidgetsOnStateChange() { +        mManager.updateWidgetsOnStateChange(ACTION_BOOT_COMPLETED); + +        verify(mAppWidgetManager, times(1)) +                .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT), +                        mBundleArgumentCaptor.capture()); +        Bundle bundle = mBundleArgumentCaptor.getValue(); +        PeopleSpaceTile tile = bundle.getParcelable(OPTIONS_PEOPLE_TILE); +        assertThat(tile.isPackageSuspended()).isFalse(); +        assertThat(tile.isUserQuieted()).isFalse(); +        assertThat(tile.canBypassDnd()).isFalse(); +        assertThat(tile.getNotificationPolicyState()).isEqualTo(SHOW_CONVERSATIONS); +        verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT), +                any()); +    } + +    @Test +    public void testUpdateWidgetsOnStateChangeWithUserQuieted() { +        when(mUserManager.isQuietModeEnabled(any())).thenReturn(true); + +        mManager.updateWidgetsOnStateChange(ACTION_BOOT_COMPLETED); + +        verify(mAppWidgetManager, times(1)) +                .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT), +                        mBundleArgumentCaptor.capture()); +        Bundle bundle = mBundleArgumentCaptor.getValue(); +        PeopleSpaceTile tile = bundle.getParcelable(OPTIONS_PEOPLE_TILE); +        assertThat(tile.isPackageSuspended()).isFalse(); +        assertThat(tile.isUserQuieted()).isTrue(); +        assertThat(tile.getNotificationPolicyState()).isEqualTo(SHOW_CONVERSATIONS); +    } + +    @Test +    public void testUpdateWidgetsOnStateChangeWithPackageSuspended() throws Exception { +        when(mPackageManager.isPackageSuspended(any())).thenReturn(true); + +        mManager.updateWidgetsOnStateChange(ACTION_PACKAGES_SUSPENDED); + +        verify(mAppWidgetManager, times(1)) +                .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT), +                        mBundleArgumentCaptor.capture()); +        Bundle bundle = mBundleArgumentCaptor.getValue(); +        PeopleSpaceTile tile = bundle.getParcelable(OPTIONS_PEOPLE_TILE); +        assertThat(tile.isPackageSuspended()).isTrue(); +        assertThat(tile.isUserQuieted()).isFalse(); +        assertThat(tile.getNotificationPolicyState()).isEqualTo(SHOW_CONVERSATIONS); +    } + +    @Test +    public void testUpdateWidgetsOnStateChangeNotInDnd() { +        int expected = 0; +        mManager.updateWidgetsOnStateChange(NotificationManager +                .ACTION_INTERRUPTION_FILTER_CHANGED); + +        verify(mAppWidgetManager, times(1)) +                .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT), +                        mBundleArgumentCaptor.capture()); +        PeopleSpaceTile tile = mBundleArgumentCaptor.getValue().getParcelable(OPTIONS_PEOPLE_TILE); +        assertThat(tile.getNotificationPolicyState()).isEqualTo(expected | SHOW_CONVERSATIONS); +    } + +    @Test +    public void testUpdateWidgetsOnStateChangeAllConversations() { +        int expected = 0; +        when(mNotificationManager.getCurrentInterruptionFilter()).thenReturn( +                INTERRUPTION_FILTER_PRIORITY); +        when(mNotificationPolicy.allowConversations()).thenReturn(true); +        setFinalField("priorityConversationSenders", CONVERSATION_SENDERS_ANYONE); + +        mManager.updateWidgetsOnStateChange(NotificationManager +                .ACTION_INTERRUPTION_FILTER_CHANGED); + +        verify(mAppWidgetManager, times(1)) +                .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT), +                        mBundleArgumentCaptor.capture()); +        PeopleSpaceTile tile = mBundleArgumentCaptor.getValue().getParcelable(OPTIONS_PEOPLE_TILE); +        assertThat(tile.getNotificationPolicyState()).isEqualTo(expected | SHOW_CONVERSATIONS); +    } + +    @Test +    public void testUpdateWidgetsOnStateChangeAllowOnlyImportantConversations() { +        int expected = 0; +        // Only allow important conversations. +        when(mNotificationManager.getCurrentInterruptionFilter()).thenReturn( +                INTERRUPTION_FILTER_PRIORITY); +        when(mNotificationPolicy.allowConversations()).thenReturn(true); +        setFinalField("priorityConversationSenders", CONVERSATION_SENDERS_IMPORTANT); + +        mManager.updateWidgetsOnStateChange(NotificationManager +                .ACTION_INTERRUPTION_FILTER_CHANGED); + +        verify(mAppWidgetManager, times(1)) +                .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT), +                        mBundleArgumentCaptor.capture()); +        PeopleSpaceTile tile = mBundleArgumentCaptor.getValue().getParcelable(OPTIONS_PEOPLE_TILE); +        assertThat(tile.getNotificationPolicyState()).isEqualTo( +                expected | SHOW_IMPORTANT_CONVERSATIONS); +    } + +    @Test +    public void testUpdateWidgetsOnStateChangeAllowNoConversations() { +        int expected = 0; +        when(mNotificationManager.getCurrentInterruptionFilter()).thenReturn( +                INTERRUPTION_FILTER_PRIORITY); +        when(mNotificationPolicy.allowConversations()).thenReturn(false); + +        mManager.updateWidgetsOnStateChange(NotificationManager +                .ACTION_INTERRUPTION_FILTER_CHANGED); + +        verify(mAppWidgetManager, times(1)) +                .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT), +                        mBundleArgumentCaptor.capture()); +        PeopleSpaceTile tile = mBundleArgumentCaptor.getValue().getParcelable(OPTIONS_PEOPLE_TILE); +        assertThat(tile.getNotificationPolicyState()).isEqualTo(expected | BLOCK_CONVERSATIONS); +    } + +    @Test +    public void testUpdateWidgetsOnStateChangeAllowNoConversationsAllowContactMessages() { +        int expected = 0; +        when(mNotificationManager.getCurrentInterruptionFilter()).thenReturn( +                INTERRUPTION_FILTER_PRIORITY); +        when(mNotificationPolicy.allowConversations()).thenReturn(false); +        when(mNotificationPolicy.allowMessagesFrom()).thenReturn(ZenModeConfig.SOURCE_CONTACT); +        when(mNotificationPolicy.allowMessages()).thenReturn(true); + +        mManager.updateWidgetsOnStateChange(ACTION_BOOT_COMPLETED); + +        verify(mAppWidgetManager, times(1)) +                .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT), +                        mBundleArgumentCaptor.capture()); +        PeopleSpaceTile tile = mBundleArgumentCaptor.getValue().getParcelable(OPTIONS_PEOPLE_TILE); +        assertThat(tile.getNotificationPolicyState()).isEqualTo(expected | SHOW_CONTACTS); +    } + +    @Test +    public void testUpdateWidgetsOnStateChangeAllowNoConversationsAllowStarredContactMessages() { +        int expected = 0; +        when(mNotificationManager.getCurrentInterruptionFilter()).thenReturn( +                INTERRUPTION_FILTER_PRIORITY); +        when(mNotificationPolicy.allowConversations()).thenReturn(false); +        when(mNotificationPolicy.allowMessagesFrom()).thenReturn(ZenModeConfig.SOURCE_STAR); +        when(mNotificationPolicy.allowMessages()).thenReturn(true); + +        mManager.updateWidgetsOnStateChange(ACTION_BOOT_COMPLETED); + +        verify(mAppWidgetManager, times(1)) +                .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT), +                        mBundleArgumentCaptor.capture()); +        PeopleSpaceTile tile = mBundleArgumentCaptor.getValue().getParcelable(OPTIONS_PEOPLE_TILE); +        assertThat(tile.getNotificationPolicyState()).isEqualTo(expected | SHOW_STARRED_CONTACTS); +    } + +    @Test +    public void testUpdateWidgetsOnStateChangeAllowAlarmsOnly() { +        int expected = 0; +        when(mNotificationManager.getCurrentInterruptionFilter()).thenReturn( +                INTERRUPTION_FILTER_ALARMS); + +        mManager.updateWidgetsOnStateChange(NotificationManager +                .ACTION_INTERRUPTION_FILTER_CHANGED); + +        verify(mAppWidgetManager, times(1)) +                .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT), +                        mBundleArgumentCaptor.capture()); +        PeopleSpaceTile tile = mBundleArgumentCaptor.getValue().getParcelable(OPTIONS_PEOPLE_TILE); +        assertThat(tile.getNotificationPolicyState()).isEqualTo(expected | BLOCK_CONVERSATIONS); +    } + +    @Test +    public void testUpdateWidgetsOnStateChangeAllowVisualEffectsAndAllowAlarmsOnly() { +        int expected = 0; +        // If we show visuals, but just only make sounds for alarms, still show content in tiles. +        when(mNotificationManager.getCurrentInterruptionFilter()).thenReturn( +                INTERRUPTION_FILTER_ALARMS); +        setFinalField("suppressedVisualEffects", SUPPRESSED_EFFECT_FULL_SCREEN_INTENT +                | SUPPRESSED_EFFECT_AMBIENT); + +        mManager.updateWidgetsOnStateChange(ACTION_BOOT_COMPLETED); + +        verify(mAppWidgetManager, times(1)) +                .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT), +                        mBundleArgumentCaptor.capture()); +        PeopleSpaceTile tile = mBundleArgumentCaptor.getValue().getParcelable(OPTIONS_PEOPLE_TILE); +        assertThat(tile.getNotificationPolicyState()).isEqualTo(expected | SHOW_CONVERSATIONS); +    } + +    private void setFinalField(String fieldName, int value) { +        try { +            Field field = NotificationManager.Policy.class.getDeclaredField(fieldName); +            field.setAccessible(true); +            field.set(mNotificationPolicy, value); +        } catch (Exception e) { +        } +    } +      /**       * Adds another widget for {@code PERSON_TILE} with widget ID: {@code       * SECOND_WIDGET_ID_WITH_SHORTCUT}. diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java index 68ed2a595a46..6f0ae223540d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java @@ -474,6 +474,22 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {      }      @Test +    public void transientIndication_visibleWhenDozing_ignoresFingerprintCancellation() { +        createController(); + +        mController.setVisible(true); +        reset(mRotateTextViewController); +        mController.getKeyguardCallback().onBiometricError( +                FingerprintManager.FINGERPRINT_ERROR_USER_CANCELED, "foo", +                BiometricSourceType.FINGERPRINT); +        mController.getKeyguardCallback().onBiometricError( +                FingerprintManager.FINGERPRINT_ERROR_CANCELED, "bar", +                BiometricSourceType.FINGERPRINT); + +        verifyNoTransientMessage(); +    } + +    @Test      public void transientIndication_swipeUpToRetry() {          createController();          String message = mContext.getString(R.string.keyguard_retry); @@ -668,4 +684,8 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {      private void verifyTransientMessage(String message) {          verify(mRotateTextViewController).showTransient(eq(message), anyBoolean());      } + +    private void verifyNoTransientMessage() { +        verify(mRotateTextViewController, never()).showTransient(any(), anyBoolean()); +    }  } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java index 5d29f520e8a9..e85e19fbd9b8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java @@ -21,6 +21,8 @@ import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED;  import static android.app.NotificationManager.IMPORTANCE_DEFAULT;  import static android.app.NotificationManager.IMPORTANCE_HIGH;  import static android.app.NotificationManager.IMPORTANCE_LOW; +import static android.app.NotificationManager.Policy.CONVERSATION_SENDERS_ANYONE; +import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_CONVERSATIONS;  import static android.print.PrintManager.PRINT_SPOOLER_PACKAGE_NAME;  import static android.view.View.GONE;  import static android.view.View.VISIBLE; @@ -150,9 +152,6 @@ public class NotificationConversationInfoTest extends SysuiTestCase {      private ShadeController mShadeController;      @Mock      private ConversationIconFactory mIconFactory; -    @Mock(answer = Answers.RETURNS_SELF) -    private PriorityOnboardingDialogController.Builder mBuilder; -    private Provider<PriorityOnboardingDialogController.Builder> mBuilderProvider = () -> mBuilder;      @Mock      private Notification.BubbleMetadata mBubbleMetadata;      private Handler mTestHandler; @@ -236,8 +235,6 @@ public class NotificationConversationInfoTest extends SysuiTestCase {          when(mMockINotificationManager.getConsolidatedNotificationPolicy())                  .thenReturn(mock(NotificationManager.Policy.class)); -        when(mBuilder.build()).thenReturn(mock(PriorityOnboardingDialogController.class)); -          when(mPeopleSpaceWidgetManager.requestPinAppWidget(any(), any())).thenReturn(true);      } @@ -258,7 +255,6 @@ public class NotificationConversationInfoTest extends SysuiTestCase {                  null,                  mIconFactory,                  mContext, -                mBuilderProvider,                  true,                  mTestHandler,                  mTestHandler, null, Optional.of(mBubblesManager), @@ -285,7 +281,6 @@ public class NotificationConversationInfoTest extends SysuiTestCase {                  null,                  mIconFactory,                  mContext, -                mBuilderProvider,                  true,                  mTestHandler,                  mTestHandler, null, Optional.of(mBubblesManager), @@ -340,7 +335,6 @@ public class NotificationConversationInfoTest extends SysuiTestCase {                  null,                  mIconFactory,                  mContext, -                mBuilderProvider,                  true,                  mTestHandler,                  mTestHandler, null, Optional.of(mBubblesManager), @@ -368,7 +362,6 @@ public class NotificationConversationInfoTest extends SysuiTestCase {                  null,                  mIconFactory,                  mContext, -                mBuilderProvider,                  true,                  mTestHandler,                  mTestHandler, null, Optional.of(mBubblesManager), @@ -395,7 +388,6 @@ public class NotificationConversationInfoTest extends SysuiTestCase {                  null,                  mIconFactory,                  mContext, -                mBuilderProvider,                  true,                  mTestHandler,                  mTestHandler, null, Optional.of(mBubblesManager), @@ -433,7 +425,6 @@ public class NotificationConversationInfoTest extends SysuiTestCase {                  null,                  mIconFactory,                  mContext, -                mBuilderProvider,                  true,                  mTestHandler,                  mTestHandler, null, Optional.of(mBubblesManager), @@ -464,7 +455,6 @@ public class NotificationConversationInfoTest extends SysuiTestCase {                  null,                  mIconFactory,                  mContext, -                mBuilderProvider,                  true,                  mTestHandler,                  mTestHandler, null, Optional.of(mBubblesManager), @@ -493,7 +483,6 @@ public class NotificationConversationInfoTest extends SysuiTestCase {                  null,                  mIconFactory,                  mContext, -                mBuilderProvider,                  true,                  mTestHandler,                  mTestHandler, null, Optional.of(mBubblesManager), @@ -523,7 +512,6 @@ public class NotificationConversationInfoTest extends SysuiTestCase {                  null,                  mIconFactory,                  mContext, -                mBuilderProvider,                  false,                  mTestHandler,                  mTestHandler, null, Optional.of(mBubblesManager), @@ -551,7 +539,6 @@ public class NotificationConversationInfoTest extends SysuiTestCase {                  null,                  mIconFactory,                  mContext, -                mBuilderProvider,                  true,                  mTestHandler,                  mTestHandler, null, Optional.of(mBubblesManager), @@ -582,7 +569,6 @@ public class NotificationConversationInfoTest extends SysuiTestCase {                  null,                  mIconFactory,                  mContext, -                mBuilderProvider,                  true,                  mTestHandler,                  mTestHandler, null, Optional.of(mBubblesManager), @@ -616,7 +602,6 @@ public class NotificationConversationInfoTest extends SysuiTestCase {                  null,                  mIconFactory,                  mContext, -                mBuilderProvider,                  true,                  mTestHandler,                  mTestHandler, null, Optional.of(mBubblesManager), @@ -626,6 +611,110 @@ public class NotificationConversationInfoTest extends SysuiTestCase {          assertThat(((TextView) view.findViewById(R.id.default_summary)).getText()).isEqualTo(                  mContext.getString(R.string.notification_channel_summary_default_with_bubbles,                          "App Name")); +        assertThat(((TextView) mNotificationInfo.findViewById(R.id.priority_summary)).getText()) +                .isEqualTo(mContext.getString( +                        R.string.notification_channel_summary_priority_bubble)); +    } + +    @Test +    public void testBindNotification_priorityDnd() throws Exception { +        NotificationManager.Policy policy = new NotificationManager.Policy( +                PRIORITY_CATEGORY_CONVERSATIONS, 0, 0, 0, CONVERSATION_SENDERS_ANYONE); +        when(mMockINotificationManager.getConsolidatedNotificationPolicy()) +                .thenReturn(policy); +        when(mMockPackageManager.getApplicationLabel(any())).thenReturn("App Name"); +        mConversationChannel.setImportance(IMPORTANCE_HIGH); +        mConversationChannel.setImportantConversation(false); +        mConversationChannel.setAllowBubbles(false); +        mNotificationInfo.bindNotification( +                -1, +                mShortcutManager, +                mMockPackageManager, +                mPeopleSpaceWidgetManager, +                mMockINotificationManager, +                mOnUserInteractionCallback, +                TEST_PACKAGE_NAME, +                mNotificationChannel, +                mEntry, +                null, +                null, +                null, +                mIconFactory, +                mContext, +                true, +                mTestHandler, +                mTestHandler, null, Optional.of(mBubblesManager), +                mShadeController); +        assertThat(((TextView) mNotificationInfo.findViewById(R.id.priority_summary)).getText()) +                .isEqualTo(mContext.getString( +                        R.string.notification_channel_summary_priority_dnd)); +    } + +    @Test +    public void testBindNotification_priorityBaseline() throws Exception { +        when(mMockPackageManager.getApplicationLabel(any())).thenReturn("App Name"); +        mConversationChannel.setImportance(IMPORTANCE_HIGH); +        mConversationChannel.setImportantConversation(false); +        mConversationChannel.setAllowBubbles(false); +        mNotificationInfo.bindNotification( +                -1, +                mShortcutManager, +                mMockPackageManager, +                mPeopleSpaceWidgetManager, +                mMockINotificationManager, +                mOnUserInteractionCallback, +                TEST_PACKAGE_NAME, +                mNotificationChannel, +                mEntry, +                null, +                null, +                null, +                mIconFactory, +                mContext, +                true, +                mTestHandler, +                mTestHandler, null, Optional.of(mBubblesManager), +                mShadeController); +        assertThat(((TextView) mNotificationInfo.findViewById(R.id.priority_summary)).getText()) +                .isEqualTo(mContext.getString( +                        R.string.notification_channel_summary_priority_baseline)); +    } + +    @Test +    public void testBindNotification_priorityDndAndBubble() throws Exception { +        NotificationManager.Policy policy = new NotificationManager.Policy( +                PRIORITY_CATEGORY_CONVERSATIONS, 0, 0, 0, CONVERSATION_SENDERS_ANYONE); +        when(mMockINotificationManager.getConsolidatedNotificationPolicy()) +                .thenReturn(policy); + +        when(mMockINotificationManager.getBubblePreferenceForPackage(anyString(), anyInt())) +                .thenReturn(BUBBLE_PREFERENCE_ALL); +        when(mMockPackageManager.getApplicationLabel(any())).thenReturn("App Name"); +        mConversationChannel.setImportance(IMPORTANCE_HIGH); +        mConversationChannel.setImportantConversation(false); +        mConversationChannel.setAllowBubbles(true); +        mNotificationInfo.bindNotification( +                -1, +                mShortcutManager, +                mMockPackageManager, +                mPeopleSpaceWidgetManager, +                mMockINotificationManager, +                mOnUserInteractionCallback, +                TEST_PACKAGE_NAME, +                mNotificationChannel, +                mEntry, +                mBubbleMetadata, +                null, +                null, +                mIconFactory, +                mContext, +                true, +                mTestHandler, +                mTestHandler, null, Optional.of(mBubblesManager), +                mShadeController); +        assertThat(((TextView) mNotificationInfo.findViewById(R.id.priority_summary)).getText()) +                .isEqualTo(mContext.getString( +                        R.string.notification_channel_summary_priority_all));      }      @Test @@ -649,7 +738,6 @@ public class NotificationConversationInfoTest extends SysuiTestCase {                  null,                  mIconFactory,                  mContext, -                mBuilderProvider,                  true,                  mTestHandler,                  mTestHandler, null, Optional.of(mBubblesManager), @@ -696,7 +784,6 @@ public class NotificationConversationInfoTest extends SysuiTestCase {                  null,                  mIconFactory,                  mContext, -                mBuilderProvider,                  true,                  mTestHandler,                  mTestHandler, null, Optional.of(mBubblesManager), @@ -742,7 +829,6 @@ public class NotificationConversationInfoTest extends SysuiTestCase {                  null,                  mIconFactory,                  mContext, -                mBuilderProvider,                  true,                  mTestHandler,                  mTestHandler, null, Optional.of(mBubblesManager), @@ -789,7 +875,6 @@ public class NotificationConversationInfoTest extends SysuiTestCase {                  null,                  mIconFactory,                  mContext, -                mBuilderProvider,                  true,                  mTestHandler,                  mTestHandler, null, Optional.of(mBubblesManager), @@ -829,7 +914,6 @@ public class NotificationConversationInfoTest extends SysuiTestCase {                  null,                  mIconFactory,                  mContext, -                mBuilderProvider,                  true,                  mTestHandler,                  mTestHandler, null, Optional.of(mBubblesManager), @@ -868,7 +952,6 @@ public class NotificationConversationInfoTest extends SysuiTestCase {                  null,                  mIconFactory,                  mContext, -                mBuilderProvider,                  true,                  mTestHandler,                  mTestHandler, null, Optional.of(mBubblesManager), @@ -911,7 +994,6 @@ public class NotificationConversationInfoTest extends SysuiTestCase {                  null,                  mIconFactory,                  mContext, -                mBuilderProvider,                  true,                  mTestHandler,                  mTestHandler, null, Optional.of(mBubblesManager), @@ -944,7 +1026,6 @@ public class NotificationConversationInfoTest extends SysuiTestCase {                  null,                  mIconFactory,                  mContext, -                mBuilderProvider,                  true,                  mTestHandler,                  mTestHandler, null, Optional.of(mBubblesManager), @@ -976,7 +1057,6 @@ public class NotificationConversationInfoTest extends SysuiTestCase {                  null,                  mIconFactory,                  mContext, -                mBuilderProvider,                  true,                  mTestHandler,                  mTestHandler, null, Optional.of(mBubblesManager), @@ -1015,7 +1095,6 @@ public class NotificationConversationInfoTest extends SysuiTestCase {                  null,                  mIconFactory,                  mContext, -                mBuilderProvider,                  true,                  mTestHandler,                  mTestHandler, null, Optional.of(mBubblesManager), @@ -1054,7 +1133,6 @@ public class NotificationConversationInfoTest extends SysuiTestCase {                  null,                  mIconFactory,                  mContext, -                mBuilderProvider,                  true,                  mTestHandler,                  mTestHandler, null, Optional.of(mBubblesManager), @@ -1092,7 +1170,6 @@ public class NotificationConversationInfoTest extends SysuiTestCase {                  null,                  mIconFactory,                  mContext, -                mBuilderProvider,                  true,                  mTestHandler,                  mTestHandler, null, Optional.of(mBubblesManager), @@ -1129,7 +1206,6 @@ public class NotificationConversationInfoTest extends SysuiTestCase {                  null,                  mIconFactory,                  mContext, -                mBuilderProvider,                  true,                  mTestHandler,                  mTestHandler, null, Optional.of(mBubblesManager), @@ -1157,7 +1233,6 @@ public class NotificationConversationInfoTest extends SysuiTestCase {                  null,                  mIconFactory,                  mContext, -                mBuilderProvider,                  true,                  mTestHandler,                  mTestHandler, null, Optional.of(mBubblesManager), @@ -1168,97 +1243,8 @@ public class NotificationConversationInfoTest extends SysuiTestCase {      }      @Test -    public void testSelectPriorityPresentsOnboarding_firstTime() { -        // GIVEN pref is false -        Prefs.putBoolean(mContext, Prefs.Key.HAS_SEEN_PRIORITY_ONBOARDING_IN_S, false); - -        // GIVEN the priority onboarding screen is present -        PriorityOnboardingDialogController.Builder b = -                mock(PriorityOnboardingDialogController.Builder.class, Answers.RETURNS_SELF); -        PriorityOnboardingDialogController controller = -                mock(PriorityOnboardingDialogController.class); -        when(b.build()).thenReturn(controller); - -        // GIVEN the user is changing conversation settings -        mNotificationInfo.bindNotification( -                -1, -                mShortcutManager, -                mMockPackageManager, -                mPeopleSpaceWidgetManager, -                mMockINotificationManager, -                mOnUserInteractionCallback, -                TEST_PACKAGE_NAME, -                mNotificationChannel, -                mEntry, -                mBubbleMetadata, -                null, -                null, -                mIconFactory, -                mContext, -                () -> b, -                true, -                mTestHandler, -                mTestHandler, null, Optional.of(mBubblesManager), -                mShadeController); - -        // WHEN user clicks "priority" -        mNotificationInfo.setSelectedAction(NotificationConversationInfo.ACTION_FAVORITE); -        verify(controller, never()).show(); - -        // and then done -        mNotificationInfo.findViewById(R.id.done).performClick(); - -        // THEN the user is presented with the priority onboarding screen -        verify(controller, atLeastOnce()).show(); -    } - -    @Test -    public void testSelectPriorityDoesNotShowOnboarding_secondTime() { -        //WHEN pref is true -        Prefs.putBoolean(mContext, Prefs.Key.HAS_SEEN_PRIORITY_ONBOARDING_IN_S, true); - -        PriorityOnboardingDialogController.Builder b = -                mock(PriorityOnboardingDialogController.Builder.class, Answers.RETURNS_SELF); -        PriorityOnboardingDialogController controller = -                mock(PriorityOnboardingDialogController.class); -        when(b.build()).thenReturn(controller); - -        mNotificationInfo.bindNotification( -                -1, -                mShortcutManager, -                mMockPackageManager, -                mPeopleSpaceWidgetManager, -                mMockINotificationManager, -                mOnUserInteractionCallback, -                TEST_PACKAGE_NAME, -                mNotificationChannel, -                mEntry, -                mBubbleMetadata, -                null, -                null, -                mIconFactory, -                mContext, -                () -> b, -                true, -                mTestHandler, -                mTestHandler, null, Optional.of(mBubblesManager), -                mShadeController); - -        // WHEN user clicks "priority" -        mNotificationInfo.setSelectedAction(NotificationConversationInfo.ACTION_FAVORITE); -        verify(controller, never()).show(); - -        // and then done -        mNotificationInfo.findViewById(R.id.done).performClick(); - -        // THEN the user is presented with the priority onboarding screen -        verify(controller, never()).show(); -    } - -    @Test      public void testSelectPriorityRequestsPinPeopleTile() { -        //WHEN pref is true and channel is default importance -        Prefs.putBoolean(mContext, Prefs.Key.HAS_SEEN_PRIORITY_ONBOARDING_IN_S, true); +        //WHEN channel is default importance          mNotificationChannel.setImportantConversation(false);          mNotificationInfo.bindNotification(                  -1, @@ -1275,7 +1261,6 @@ public class NotificationConversationInfoTest extends SysuiTestCase {                  null,                  mIconFactory,                  mContext, -                mBuilderProvider,                  true,                  mTestHandler,                  mTestHandler, null, Optional.of(mBubblesManager), @@ -1293,9 +1278,6 @@ public class NotificationConversationInfoTest extends SysuiTestCase {      @Test      public void testSelectDefaultDoesNotRequestPinPeopleTile() { -        //WHEN pref is true -        Prefs.putBoolean(mContext, Prefs.Key.HAS_SEEN_PRIORITY_ONBOARDING_IN_S, true); -          mNotificationInfo.bindNotification(                  -1,                  mShortcutManager, @@ -1311,7 +1293,6 @@ public class NotificationConversationInfoTest extends SysuiTestCase {                  null,                  mIconFactory,                  mContext, -                mBuilderProvider,                  true,                  mTestHandler,                  mTestHandler, null, Optional.of(mBubblesManager), @@ -1329,8 +1310,6 @@ public class NotificationConversationInfoTest extends SysuiTestCase {      @Test      public void testSelectPriority_AlreadyPriority_DoesNotRequestPinPeopleTile() { -        //WHEN pref is true and channel is priority -        Prefs.putBoolean(mContext, Prefs.Key.HAS_SEEN_PRIORITY_ONBOARDING_IN_S, true);          mConversationChannel.setOriginalImportance(IMPORTANCE_HIGH);          mConversationChannel.setImportance(IMPORTANCE_HIGH);          mConversationChannel.setImportantConversation(true); @@ -1350,7 +1329,6 @@ public class NotificationConversationInfoTest extends SysuiTestCase {                  null,                  mIconFactory,                  mContext, -                mBuilderProvider,                  true,                  mTestHandler,                  mTestHandler, null, Optional.of(mBubblesManager), diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java index bfce2a568c78..9f537f5b6afc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java @@ -139,9 +139,6 @@ public class NotificationGutsManagerTest extends SysuiTestCase {      @Mock private BubblesManager mBubblesManager;      @Mock private ShadeController mShadeController;      @Mock private PeopleSpaceWidgetManager mPeopleSpaceWidgetManager; -    @Mock(answer = Answers.RETURNS_SELF) -    private PriorityOnboardingDialogController.Builder mBuilder; -    private Provider<PriorityOnboardingDialogController.Builder> mProvider = () -> mBuilder;      @Mock private AssistantFeedbackController mAssistantFeedbackController;      @Before @@ -163,7 +160,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {                  () -> mStatusBar, mHandler, mHandler, mAccessibilityManager, mHighPriorityProvider,                  mINotificationManager, mNotificationEntryManager, mPeopleSpaceWidgetManager,                  mLauncherApps, mShortcutManager, mChannelEditorDialogController, mContextTracker, -                mProvider, mAssistantFeedbackController, Optional.of(mBubblesManager), +                mAssistantFeedbackController, Optional.of(mBubblesManager),                  new UiEventLoggerFake(), mOnUserInteractionCallback, mShadeController);          mGutsManager.setUpWithPresenter(mPresenter, mNotificationListContainer,                  mCheckSaveListener, mOnSettingsClickListener); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java index a01e0b1c3e3a..f485b465e486 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java @@ -38,7 +38,6 @@ import androidx.test.filters.SmallTest;  import com.android.systemui.R;  import com.android.systemui.SysuiBaseFragmentTest;  import com.android.systemui.plugins.statusbar.StatusBarStateController; -import com.android.systemui.statusbar.events.PrivacyDotViewController;  import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;  import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController; @@ -57,7 +56,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {      private StatusBarStateController mStatusBarStateController;      private OngoingCallController mOngoingCallController;      private SystemStatusAnimationScheduler mAnimationScheduler; -    private PrivacyDotViewController mDotViewController; +    private StatusBarLocationPublisher mLocationPublisher;      public CollapsedStatusBarFragmentTest() {          super(CollapsedStatusBarFragment.class); @@ -224,12 +223,12 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {      protected Fragment instantiate(Context context, String className, Bundle arguments) {          mOngoingCallController = mock(OngoingCallController.class);          mAnimationScheduler = mock(SystemStatusAnimationScheduler.class); -        mDotViewController = mock(PrivacyDotViewController.class); +        mLocationPublisher = mock(StatusBarLocationPublisher.class);          setUpNotificationIconAreaController();          return new CollapsedStatusBarFragment(                  mOngoingCallController,                  mAnimationScheduler, -                mDotViewController, +                mLocationPublisher,                  mMockNotificationAreaController);      } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java index b6eb4923ee4a..f98f00cd9187 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java @@ -20,6 +20,7 @@ import static com.android.systemui.statusbar.phone.ScrimController.OPAQUE;  import static com.android.systemui.statusbar.phone.ScrimController.SEMI_TRANSPARENT;  import static com.android.systemui.statusbar.phone.ScrimController.TRANSPARENT; +import static org.junit.Assert.assertEquals;  import static org.mockito.ArgumentMatchers.any;  import static org.mockito.ArgumentMatchers.anyFloat;  import static org.mockito.ArgumentMatchers.anyInt; @@ -165,7 +166,7 @@ public class ScrimControllerTest extends SysuiTestCase {          endAnimation(mScrimInFront);          endAnimation(mScrimForBubble); -        Assert.assertEquals("Animators did not finish", +        assertEquals("Animators did not finish",                  mAnimatorListener.getNumStarts(), mAnimatorListener.getNumEnds());      } @@ -422,7 +423,7 @@ public class ScrimControllerTest extends SysuiTestCase {          mScrimController.transitionTo(ScrimState.AOD);          finishAnimationsImmediately();          mScrimController.setAodFrontScrimAlpha(0.3f); -        Assert.assertEquals(ScrimState.AOD.getFrontAlpha(), mScrimInFront.getViewAlpha(), 0.001f); +        assertEquals(ScrimState.AOD.getFrontAlpha(), mScrimInFront.getViewAlpha(), 0.001f);          Assert.assertNotEquals(0.3f, mScrimInFront.getViewAlpha(), 0.001f);      } @@ -601,13 +602,13 @@ public class ScrimControllerTest extends SysuiTestCase {          ));          // Front scrim should be transparent -        Assert.assertEquals(ScrimController.TRANSPARENT, +        assertEquals(ScrimController.TRANSPARENT,                  mScrimInFront.getViewAlpha(), 0.0f);          // Back scrim should be visible -        Assert.assertEquals(ScrimController.BUSY_SCRIM_ALPHA, +        assertEquals(ScrimController.BUSY_SCRIM_ALPHA,                  mScrimBehind.getViewAlpha(), 0.0f);          // Bubble scrim should be visible -        Assert.assertEquals(ScrimController.BUBBLE_SCRIM_ALPHA, +        assertEquals(ScrimController.BUBBLE_SCRIM_ALPHA,                  mScrimForBubble.getViewAlpha(), 0.0f);      } @@ -615,15 +616,15 @@ public class ScrimControllerTest extends SysuiTestCase {      public void scrimStateCallback() {          mScrimController.transitionTo(ScrimState.UNLOCKED);          finishAnimationsImmediately(); -        Assert.assertEquals(mScrimState, ScrimState.UNLOCKED); +        assertEquals(mScrimState, ScrimState.UNLOCKED);          mScrimController.transitionTo(ScrimState.BOUNCER);          finishAnimationsImmediately(); -        Assert.assertEquals(mScrimState, ScrimState.BOUNCER); +        assertEquals(mScrimState, ScrimState.BOUNCER);          mScrimController.transitionTo(ScrimState.BOUNCER_SCRIMMED);          finishAnimationsImmediately(); -        Assert.assertEquals(mScrimState, ScrimState.BOUNCER_SCRIMMED); +        assertEquals(mScrimState, ScrimState.BOUNCER_SCRIMMED);      }      @Test @@ -638,13 +639,13 @@ public class ScrimControllerTest extends SysuiTestCase {          mScrimController.setPanelExpansion(1.0f);          finishAnimationsImmediately(); -        Assert.assertEquals("Scrim alpha should change after setPanelExpansion", +        assertEquals("Scrim alpha should change after setPanelExpansion",                  mScrimBehindAlpha, mScrimBehind.getViewAlpha(), 0.01f);          mScrimController.setPanelExpansion(0f);          finishAnimationsImmediately(); -        Assert.assertEquals("Scrim alpha should change after setPanelExpansion", +        assertEquals("Scrim alpha should change after setPanelExpansion",                  mScrimBehindAlpha, mScrimBehind.getViewAlpha(), 0.01f);      } @@ -698,7 +699,7 @@ public class ScrimControllerTest extends SysuiTestCase {          mScrimController.setExpansionAffectsAlpha(false);          mScrimController.setPanelExpansion(0.8f);          verifyZeroInteractions(mScrimBehind); -        Assert.assertEquals("Scrim opacity shouldn't change when setExpansionAffectsAlpha " +        assertEquals("Scrim opacity shouldn't change when setExpansionAffectsAlpha "                  + "is false", scrimAlpha, mScrimBehind.getViewAlpha(), 0.01f);          mScrimController.setExpansionAffectsAlpha(true); @@ -801,9 +802,9 @@ public class ScrimControllerTest extends SysuiTestCase {              }          });          finishAnimationsImmediately(); -        Assert.assertEquals("onStart called in wrong order", 1, callOrder[0]); -        Assert.assertEquals("onDisplayBlanked called in wrong order", 2, callOrder[1]); -        Assert.assertEquals("onFinished called in wrong order", 3, callOrder[2]); +        assertEquals("onStart called in wrong order", 1, callOrder[0]); +        assertEquals("onDisplayBlanked called in wrong order", 2, callOrder[1]); +        assertEquals("onFinished called in wrong order", 3, callOrder[2]);      }      @Test @@ -911,7 +912,7 @@ public class ScrimControllerTest extends SysuiTestCase {          mScrimController.transitionTo(ScrimState.UNLOCKED);          finishAnimationsImmediately(); -        Assert.assertEquals("Scrim expansion opacity wasn't conserved when transitioning back", +        assertEquals("Scrim expansion opacity wasn't conserved when transitioning back",                  expandedAlpha, mScrimBehind.getViewAlpha(), 0.01f);      } @@ -981,7 +982,7 @@ public class ScrimControllerTest extends SysuiTestCase {              }              mScrimController.transitionTo(state);              finishAnimationsImmediately(); -            Assert.assertEquals("Should be clickable unless AOD or PULSING, was: " + state, +            assertEquals("Should be clickable unless AOD or PULSING, was: " + state,                      mScrimBehind.getViewAlpha() != 0 && !eatsTouches.contains(state),                      mScrimBehind.isClickable());          } @@ -1035,9 +1036,9 @@ public class ScrimControllerTest extends SysuiTestCase {          mScrimController.setQsPosition(0, 300);          finishAnimationsImmediately(); -        Assert.assertEquals("Behind scrim should be opaque", +        assertEquals("Behind scrim should be opaque",                  mScrimBehind.getViewAlpha(), 1, 0.0); -        Assert.assertEquals("Notifications scrim should be opaque", +        assertEquals("Notifications scrim should be opaque",                  mNotificationsScrim.getViewAlpha(), 1, 0.0);      } @@ -1093,6 +1094,40 @@ public class ScrimControllerTest extends SysuiTestCase {                  mNotificationsScrim, TRANSPARENT));      } +    @Test +    public void testNotificationScrimVisible_afterOpeningShadeFromLockscreen() { +        mScrimController.setPanelExpansion(1); +        mScrimController.transitionTo(ScrimState.SHADE_LOCKED); +        finishAnimationsImmediately(); + +        assertScrimAlpha(Map.of( +                mScrimBehind, OPAQUE, +                mNotificationsScrim, OPAQUE)); +    } + +    @Test +    public void testNotificationTransparency_followsPanelExpansionInShadeLockedState() { +        mScrimController.transitionTo(ScrimState.SHADE_LOCKED); + +        assertAlphaAfterExpansion(mNotificationsScrim, /* alpha */ 0.8f, /* expansion */ 0.8f); +        assertAlphaAfterExpansion(mNotificationsScrim, /* alpha */ 0.2f, /* expansion */ 0.2f); +    } + +    @Test +    public void testNotificationTransparency_inKeyguardState() { +        mScrimController.transitionTo(ScrimState.KEYGUARD); + +        assertAlphaAfterExpansion(mNotificationsScrim, /* alpha */ 0.2f, /* expansion */ 0.8f); +        assertAlphaAfterExpansion(mNotificationsScrim, /* alpha */ 0.8f, /* expansion */ 0.2f); +    } + +    private void assertAlphaAfterExpansion(ScrimView scrim, float expectedAlpha, float expansion) { +        mScrimController.setPanelExpansion(expansion); +        finishAnimationsImmediately(); +        // alpha is not changing linearly thus 0.2 of leeway when asserting +        assertEquals(expectedAlpha, mNotificationsScrim.getViewAlpha(), 0.2); +    } +      private void assertScrimTinted(Map<ScrimView, Boolean> scrimToTint) {          scrimToTint.forEach((scrim, hasTint) -> assertScrimTint(scrim, hasTint));      } @@ -1101,7 +1136,7 @@ public class ScrimControllerTest extends SysuiTestCase {          String message = "Tint test failed at state " + mScrimController.getState()                  + " with scrim: " + getScrimName(scrim) + " and tint: "                  + Integer.toHexString(scrim.getTint()); -        Assert.assertEquals(message, hasTint, scrim.getTint() != Color.TRANSPARENT); +        assertEquals(message, hasTint, scrim.getTint() != Color.TRANSPARENT);      }      private String getScrimName(ScrimView scrim) { @@ -1146,13 +1181,13 @@ public class ScrimControllerTest extends SysuiTestCase {          } else {              visibility = TRANSPARENT;          } -        Assert.assertEquals("Invalid visibility.", +        assertEquals("Invalid visibility.",                  visibility /* expected */,                  mScrimVisibility);      }      private void assertScrimAlpha(ScrimView scrim, int expectedAlpha) { -        Assert.assertEquals("Unexpected " + getScrimName(scrim) + " scrim alpha: " +        assertEquals("Unexpected " + getScrimName(scrim) + " scrim alpha: "                          + scrim.getViewAlpha(),                  expectedAlpha != TRANSPARENT /* expected */,                  scrim.getViewAlpha() > TRANSPARENT /* actual */); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java index 545e2e08ec07..b2487e8e2444 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java @@ -115,7 +115,6 @@ import com.android.systemui.statusbar.StatusBarStateControllerImpl;  import com.android.systemui.statusbar.SuperStatusBarViewFactory;  import com.android.systemui.statusbar.VibratorHelper;  import com.android.systemui.statusbar.charging.WiredChargingRippleController; -import com.android.systemui.statusbar.events.PrivacyDotViewController;  import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;  import com.android.systemui.statusbar.notification.DynamicPrivacyController;  import com.android.systemui.statusbar.notification.NotificationEntryListener; @@ -267,7 +266,7 @@ public class StatusBarTest extends SysuiTestCase {      @Mock private WiredChargingRippleController mWiredChargingRippleController;      @Mock private OngoingCallController mOngoingCallController;      @Mock private SystemStatusAnimationScheduler mAnimationScheduler; -    @Mock private PrivacyDotViewController mDotViewController; +    @Mock private StatusBarLocationPublisher mLocationPublisher;      @Mock private FeatureFlags mFeatureFlags;      @Mock private IWallpaperManager mWallpaperManager;      @Mock private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController; @@ -437,7 +436,7 @@ public class StatusBarTest extends SysuiTestCase {                  mWiredChargingRippleController,                  mOngoingCallController,                  mAnimationScheduler, -                mDotViewController, +                mLocationPublisher,                  mFeatureFlags,                  mKeyguardUnlockAnimationController);          when(mKeyguardViewMediator.registerStatusBar(any(StatusBar.class), any(ViewGroup.class), diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/Android.bp b/packages/overlays/AvoidAppsInCutoutOverlay/Android.bp new file mode 100644 index 000000000000..4352c04f2022 --- /dev/null +++ b/packages/overlays/AvoidAppsInCutoutOverlay/Android.bp @@ -0,0 +1,29 @@ +// +//  Copyright 2021, The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +//     http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +package { +    // See: http://go/android-license-faq +    // A large-scale-change added 'default_applicable_licenses' to import +    // all of the 'license_kinds' from "frameworks_base_license" +    // to get the below license kinds: +    //   SPDX-license-identifier-Apache-2.0 +    default_applicable_licenses: ["frameworks_base_license"], +} + +runtime_resource_overlay { +    name: "AvoidAppsInCutoutOverlay", +    theme: "DisplayCutoutAvoidAppsInCutout", +    product_specific: true, +} diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/AndroidManifest.xml b/packages/overlays/AvoidAppsInCutoutOverlay/AndroidManifest.xml new file mode 100644 index 000000000000..e63c5c3fb554 --- /dev/null +++ b/packages/overlays/AvoidAppsInCutoutOverlay/AndroidManifest.xml @@ -0,0 +1,26 @@ +<!-- +  ~ 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. +  --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" +        package="com.android.internal.display.cutout.emulation.avoidAppsInCutout" +        android:versionCode="1" +        android:versionName="1.0"> +    <overlay android:targetPackage="android" +            android:category="com.android.internal.display_cutout_emulation" +            android:priority="0"/> + +    <application android:label="@string/display_cutout_emulation_overlay" android:hasCode="false"/> +</manifest> diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values/config.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values/config.xml new file mode 100644 index 000000000000..22eabf2f5927 --- /dev/null +++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values/config.xml @@ -0,0 +1,27 @@ +<!-- +  ~ 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. +  --> + +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + +    <!-- Whether the display cutout region of the main built-in display should be forced to +         black in software (to avoid aliasing or emulate a cutout that is not physically existent). +     --> +    <bool name="config_fillMainBuiltInDisplayCutout">false</bool> + +    <!-- If true, hide the display cutout with display area --> +    <bool name="config_hideDisplayCutoutWithDisplayArea">true</bool> + +</resources> diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values/strings.xml new file mode 100644 index 000000000000..a65fd43b7415 --- /dev/null +++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values/strings.xml @@ -0,0 +1,23 @@ +<?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. +  --> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + +    <!-- [CHAR_LIMIT=NONE] Developer Settings: Label for the option that masks the display cutout, i.e. avoid apps in cutout region.--> +    <string name="display_cutout_emulation_overlay">Hide (avoid apps in cutout region)</string> + +</resources> + diff --git a/packages/overlays/NoCutoutOverlay/Android.bp b/packages/overlays/NoCutoutOverlay/Android.bp new file mode 100644 index 000000000000..78f56273e223 --- /dev/null +++ b/packages/overlays/NoCutoutOverlay/Android.bp @@ -0,0 +1,30 @@ +// +//  Copyright 2021, The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +//     http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package { +    // See: http://go/android-license-faq +    // A large-scale-change added 'default_applicable_licenses' to import +    // all of the 'license_kinds' from "frameworks_base_license" +    // to get the below license kinds: +    //   SPDX-license-identifier-Apache-2.0 +    default_applicable_licenses: ["frameworks_base_license"], +} + +runtime_resource_overlay { +    name: "NoCutoutOverlay", +    theme: "DisplayCutoutNoCutout", +    product_specific: true, +} diff --git a/packages/overlays/NoCutoutOverlay/AndroidManifest.xml b/packages/overlays/NoCutoutOverlay/AndroidManifest.xml new file mode 100644 index 000000000000..c6224967b922 --- /dev/null +++ b/packages/overlays/NoCutoutOverlay/AndroidManifest.xml @@ -0,0 +1,26 @@ +<!-- +  ~ 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. +  --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" +        package="com.android.internal.display.cutout.emulation.noCutout" +        android:versionCode="1" +        android:versionName="1.0"> +    <overlay android:targetPackage="android" +            android:category="com.android.internal.display_cutout_emulation" +            android:priority="0"/> + +    <application android:label="@string/display_cutout_emulation_overlay" android:hasCode="false"/> +</manifest> diff --git a/packages/overlays/NoCutoutOverlay/res/values/config.xml b/packages/overlays/NoCutoutOverlay/res/values/config.xml new file mode 100644 index 000000000000..91576998cc54 --- /dev/null +++ b/packages/overlays/NoCutoutOverlay/res/values/config.xml @@ -0,0 +1,36 @@ +<!-- +  ~ 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. +  --> + +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + +    <!-- Whether the display cutout region of the main built-in display should be forced to +         black in software (to avoid aliasing or emulate a cutout that is not physically existent). +     --> +    <bool name="config_fillMainBuiltInDisplayCutout">false</bool> + +    <!-- If true, and there is a cutout on the main built in display, the cutout will be masked +         by shrinking the display such that it does not overlap the cutout area. --> +    <bool name="config_maskMainBuiltInDisplayCutout">true</bool> + +    <!-- Height of the status bar --> +    <dimen name="status_bar_height_portrait">28dp</dimen> +    <dimen name="status_bar_height_landscape">28dp</dimen> + +    <!-- Height of area above QQS where battery/time go (equal to status bar height if > 48dp) --> +    <dimen name="quick_qs_offset_height">48dp</dimen> +    <!-- Total height of QQS (quick_qs_offset_height + 128) --> +    <dimen name="quick_qs_total_height">176dp</dimen> +</resources> diff --git a/packages/overlays/NoCutoutOverlay/res/values/strings.xml b/packages/overlays/NoCutoutOverlay/res/values/strings.xml new file mode 100644 index 000000000000..dd01adabf81d --- /dev/null +++ b/packages/overlays/NoCutoutOverlay/res/values/strings.xml @@ -0,0 +1,24 @@ +<?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. +  --> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + +    <!-- [CHAR_LIMIT=NONE] Developer Settings: Label for the option that masks the display cutout, +         i.e. it shrinks the display such that the display cutout is no longer visible.--> +    <string name="display_cutout_emulation_overlay">Hide</string> + +</resources> + diff --git a/services/Android.bp b/services/Android.bp index 2281a159f6f7..1dd219264575 100644 --- a/services/Android.bp +++ b/services/Android.bp @@ -190,13 +190,13 @@ droidstubs {      defaults: ["services-stubs-default"],      check_api: {          current: { -            api_file: "api/non-updatable-current.txt", -            removed_api_file: "api/non-updatable-removed.txt", +            api_file: "api/current.txt", +            removed_api_file: "api/removed.txt",          },          api_lint: {              enabled: true,              new_since: ":android-non-updatable.api.system-server.latest", -            baseline_file: "api/non-updatable-lint-baseline.txt", +            baseline_file: "api/lint-baseline.txt",          },      },      dists: [ diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java index 61de53a2a483..7403af7605bc 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java @@ -16,6 +16,9 @@  package com.android.server.accessibility; +import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY; +import static android.view.WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY; +  import android.annotation.MainThread;  import android.content.Context;  import android.graphics.Region; @@ -557,12 +560,16 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo          MagnificationGestureHandler magnificationGestureHandler;          if (mAms.getMagnificationMode(displayId)                  == Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW) { -            magnificationGestureHandler = new WindowMagnificationGestureHandler(displayContext, +            final Context uiContext = displayContext.createWindowContext( +                    TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY, null /* options */); +            magnificationGestureHandler = new WindowMagnificationGestureHandler(uiContext,                      mAms.getWindowMagnificationMgr(), mAms.getMagnificationController(),                      detectControlGestures, triggerable,                      displayId);          } else { -            magnificationGestureHandler = new FullScreenMagnificationGestureHandler(displayContext, +            final Context uiContext = displayContext.createWindowContext( +                    TYPE_MAGNIFICATION_OVERLAY, null /* options */); +            magnificationGestureHandler = new FullScreenMagnificationGestureHandler(uiContext,                      mAms.getFullScreenMagnificationController(), mAms.getMagnificationController(),                      detectControlGestures, triggerable,                      new WindowMagnificationPromptController(displayContext, mUserId), displayId); diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java index 2434e2ca0b54..f7d1b9a311ba 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java @@ -34,6 +34,7 @@ import static java.util.Arrays.copyOfRange;  import android.annotation.NonNull;  import android.annotation.Nullable; +import android.annotation.UiContext;  import android.content.BroadcastReceiver;  import android.content.Context;  import android.content.Intent; @@ -139,7 +140,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH      private PointerCoords[] mTempPointerCoords;      private PointerProperties[] mTempPointerProperties; -    public FullScreenMagnificationGestureHandler(Context context, +    public FullScreenMagnificationGestureHandler(@UiContext Context context,              FullScreenMagnificationController fullScreenMagnificationController,              Callback callback,              boolean detectTripleTap, diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/PanningScalingHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/PanningScalingHandler.java index 07f22dcb2c95..c5495d98226e 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/PanningScalingHandler.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/PanningScalingHandler.java @@ -19,6 +19,7 @@ package com.android.server.accessibility.magnification;  import static java.lang.Math.abs;  import android.annotation.NonNull; +import android.annotation.UiContext;  import android.content.Context;  import android.os.Handler;  import android.util.Log; @@ -63,8 +64,8 @@ class PanningScalingHandler extends      private boolean mScaling;      private boolean mEnable; -    PanningScalingHandler(Context context, float maxScale, float minScale, boolean blockScroll, -            @NonNull MagnificationDelegate magnificationDelegate) { +    PanningScalingHandler(@UiContext Context context, float maxScale, float minScale, +            boolean blockScroll, @NonNull MagnificationDelegate magnificationDelegate) {          mDisplayId = context.getDisplayId();          mMaxScale = maxScale;          mMinScale = minScale; diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java index fa3406217fa8..4fb9a03b8ac1 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java @@ -24,6 +24,7 @@ import static java.util.Arrays.asList;  import static java.util.Arrays.copyOfRange;  import android.annotation.Nullable; +import android.annotation.UiContext;  import android.content.Context;  import android.graphics.Point;  import android.provider.Settings; @@ -86,7 +87,7 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl      private final Context mContext;      private final Point mTempPoint = new Point(); -    public WindowMagnificationGestureHandler(Context context, +    public WindowMagnificationGestureHandler(@UiContext Context context,              WindowMagnificationManager windowMagnificationMgr,              Callback callback,              boolean detectTripleTap, boolean detectShortcutTrigger, int displayId) { @@ -342,7 +343,7 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl           */          private final boolean mDetectTripleTap; -        DetectingState(Context context, boolean detectTripleTap) { +        DetectingState(@UiContext Context context, boolean detectTripleTap) {              mDetectTripleTap = detectTripleTap;              final MultiTap multiTap = new MultiTap(context, mDetectTripleTap ? 3 : 1,                      mDetectTripleTap diff --git a/services/api/Android.bp b/services/api/Android.bp index bbc8c72b2eef..ee7d49fc99c8 100644 --- a/services/api/Android.bp +++ b/services/api/Android.bp @@ -24,12 +24,12 @@ package {  filegroup {      name: "non-updatable-system-server-current.txt", -    srcs: ["non-updatable-current.txt"], +    srcs: ["current.txt"],      visibility: ["//frameworks/base/api"],  }  filegroup {      name: "non-updatable-system-server-removed.txt", -    srcs: ["non-updatable-removed.txt"], +    srcs: ["removed.txt"],      visibility: ["//frameworks/base/api"],  } diff --git a/services/api/current.txt b/services/api/current.txt index a0b1e3349e77..475dcf5eb20e 100644 --- a/services/api/current.txt +++ b/services/api/current.txt @@ -1,57 +1,4 @@  // Signature format: 2.0 -package com.android.permission.persistence { - -  public interface RuntimePermissionsPersistence { -    method @NonNull public static com.android.permission.persistence.RuntimePermissionsPersistence createInstance(); -    method public void deleteForUser(@NonNull android.os.UserHandle); -    method @Nullable public com.android.permission.persistence.RuntimePermissionsState readForUser(@NonNull android.os.UserHandle); -    method public void writeForUser(@NonNull com.android.permission.persistence.RuntimePermissionsState, @NonNull android.os.UserHandle); -  } - -  public final class RuntimePermissionsState { -    ctor public RuntimePermissionsState(int, @Nullable String, @NonNull java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>>, @NonNull java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>>); -    method @Nullable public String getFingerprint(); -    method @NonNull public java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>> getPackagePermissions(); -    method @NonNull public java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>> getSharedUserPermissions(); -    method public int getVersion(); -    field public static final int NO_VERSION = -1; // 0xffffffff -  } - -  public static final class RuntimePermissionsState.PermissionState { -    ctor public RuntimePermissionsState.PermissionState(@NonNull String, boolean, int); -    method public int getFlags(); -    method @NonNull public String getName(); -    method public boolean isGranted(); -  } - -} - -package com.android.role { - -  public interface RoleManagerLocal { -    method @NonNull public java.util.Map<java.lang.String,java.util.Set<java.lang.String>> getRolesAndHolders(int); -  } - -} - -package com.android.role.persistence { - -  public interface RolesPersistence { -    method @NonNull public static com.android.role.persistence.RolesPersistence createInstance(); -    method public void deleteForUser(@NonNull android.os.UserHandle); -    method @Nullable public com.android.role.persistence.RolesState readForUser(@NonNull android.os.UserHandle); -    method public void writeForUser(@NonNull com.android.role.persistence.RolesState, @NonNull android.os.UserHandle); -  } - -  public final class RolesState { -    ctor public RolesState(int, @Nullable String, @NonNull java.util.Map<java.lang.String,java.util.Set<java.lang.String>>); -    method @Nullable public String getPackagesHash(); -    method @NonNull public java.util.Map<java.lang.String,java.util.Set<java.lang.String>> getRoles(); -    method public int getVersion(); -  } - -} -  package com.android.server {    public final class LocalManagerRegistry { diff --git a/services/api/lint-baseline.txt b/services/api/lint-baseline.txt index e985ddb5352b..b46d21edd44c 100644 --- a/services/api/lint-baseline.txt +++ b/services/api/lint-baseline.txt @@ -1,4 +1,8 @@  // Baseline format: 1.0 +NotCloseable: com.android.server.wifi.SupplicantManager: +    Classes that release resources (stop()) should implement AutoClosable and CloseGuard: class com.android.server.wifi.SupplicantManager + +  ProtectedMember: com.android.server.SystemService#publishBinderService(String, android.os.IBinder):      Protected methods not allowed; must be public: method com.android.server.SystemService.publishBinderService(String,android.os.IBinder)}  ProtectedMember: com.android.server.SystemService#publishBinderService(String, android.os.IBinder, boolean): diff --git a/services/api/non-updatable-current.txt b/services/api/non-updatable-current.txt deleted file mode 100644 index 475dcf5eb20e..000000000000 --- a/services/api/non-updatable-current.txt +++ /dev/null @@ -1,71 +0,0 @@ -// Signature format: 2.0 -package com.android.server { - -  public final class LocalManagerRegistry { -    method public static <T> void addManager(@NonNull Class<T>, @NonNull T); -    method @Nullable public static <T> T getManager(@NonNull Class<T>); -  } - -  public abstract class SystemService { -    ctor public SystemService(@NonNull android.content.Context); -    method @NonNull public final android.content.Context getContext(); -    method public boolean isUserSupported(@NonNull com.android.server.SystemService.TargetUser); -    method public void onBootPhase(int); -    method public abstract void onStart(); -    method public void onUserStarting(@NonNull com.android.server.SystemService.TargetUser); -    method public void onUserStopped(@NonNull com.android.server.SystemService.TargetUser); -    method public void onUserStopping(@NonNull com.android.server.SystemService.TargetUser); -    method public void onUserSwitching(@Nullable com.android.server.SystemService.TargetUser, @NonNull com.android.server.SystemService.TargetUser); -    method public void onUserUnlocked(@NonNull com.android.server.SystemService.TargetUser); -    method public void onUserUnlocking(@NonNull com.android.server.SystemService.TargetUser); -    method protected final void publishBinderService(@NonNull String, @NonNull android.os.IBinder); -    method protected final void publishBinderService(@NonNull String, @NonNull android.os.IBinder, boolean); -    field public static final int PHASE_ACTIVITY_MANAGER_READY = 550; // 0x226 -    field public static final int PHASE_BOOT_COMPLETED = 1000; // 0x3e8 -    field public static final int PHASE_DEVICE_SPECIFIC_SERVICES_READY = 520; // 0x208 -    field public static final int PHASE_LOCK_SETTINGS_READY = 480; // 0x1e0 -    field public static final int PHASE_SYSTEM_SERVICES_READY = 500; // 0x1f4 -    field public static final int PHASE_THIRD_PARTY_APPS_CAN_START = 600; // 0x258 -    field public static final int PHASE_WAIT_FOR_DEFAULT_DISPLAY = 100; // 0x64 -  } - -  public static final class SystemService.TargetUser { -    method @NonNull public android.os.UserHandle getUserHandle(); -  } - -} - -package com.android.server.am { - -  public interface ActivityManagerLocal { -    method public boolean canStartForegroundService(int, int, @NonNull String); -  } - -} - -package com.android.server.role { - -  public interface RoleServicePlatformHelper { -    method @NonNull public String computePackageStateHash(int); -    method @NonNull public java.util.Map<java.lang.String,java.util.Set<java.lang.String>> getLegacyRoleState(int); -  } - -} - -package com.android.server.stats { - -  public final class StatsHelper { -    method public static void sendStatsdReadyBroadcast(@NonNull android.content.Context); -  } - -} - -package com.android.server.wifi { - -  public class SupplicantManager { -    method public static void start(); -    method public static void stop(); -  } - -} - diff --git a/services/api/non-updatable-lint-baseline.txt b/services/api/non-updatable-lint-baseline.txt deleted file mode 100644 index b46d21edd44c..000000000000 --- a/services/api/non-updatable-lint-baseline.txt +++ /dev/null @@ -1,9 +0,0 @@ -// Baseline format: 1.0 -NotCloseable: com.android.server.wifi.SupplicantManager: -    Classes that release resources (stop()) should implement AutoClosable and CloseGuard: class com.android.server.wifi.SupplicantManager - - -ProtectedMember: com.android.server.SystemService#publishBinderService(String, android.os.IBinder): -    Protected methods not allowed; must be public: method com.android.server.SystemService.publishBinderService(String,android.os.IBinder)} -ProtectedMember: com.android.server.SystemService#publishBinderService(String, android.os.IBinder, boolean): -    Protected methods not allowed; must be public: method com.android.server.SystemService.publishBinderService(String,android.os.IBinder,boolean)} diff --git a/services/api/non-updatable-removed.txt b/services/api/non-updatable-removed.txt deleted file mode 100644 index d802177e249b..000000000000 --- a/services/api/non-updatable-removed.txt +++ /dev/null @@ -1 +0,0 @@ -// Signature format: 2.0 diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java index 816c50dde2a8..76a6c0eecd3e 100644 --- a/services/core/java/android/content/pm/PackageManagerInternal.java +++ b/services/core/java/android/content/pm/PackageManagerInternal.java @@ -1133,7 +1133,7 @@ public abstract class PackageManagerInternal implements PackageSettingsSnapshotP       * @param handler to use for postponed calculations.       */      public abstract void requestChecksums(@NonNull String packageName, boolean includeSplits, -            @Checksum.Type int optional, @Checksum.Type int required, +            @Checksum.TypeMask int optional, @Checksum.TypeMask int required,              @Nullable List trustedInstallers,              @NonNull IOnChecksumsReadyListener onChecksumsReadyListener, int userId,              @NonNull Executor executor, @NonNull Handler handler); diff --git a/services/core/java/com/android/server/IntentResolver.java b/services/core/java/com/android/server/IntentResolver.java index 906702866889..047aae772f44 100644 --- a/services/core/java/com/android/server/IntentResolver.java +++ b/services/core/java/com/android/server/IntentResolver.java @@ -839,33 +839,45 @@ public abstract class IntentResolver<F, R extends Object> {          }      }; +    // Method to take the snapshot of an F. +    protected F snapshot(F f) { +        return f; +    } +      // Helper method to copy some of the maps. -    private static <E> void copyInto(ArrayMap<String, E[]> l, ArrayMap<String, E[]> r) { +    protected void copyInto(ArrayMap<String, F[]> l, ArrayMap<String, F[]> r) {          final int end = r.size(); +        l.clear();          l.ensureCapacity(end);          for (int i = 0; i < end; i++) { -            final E[] val = r.valueAt(i); +            final F[] val = r.valueAt(i);              final String key = r.keyAt(i); -            l.put(key, Arrays.copyOf(val, val.length)); +            final F[] newval = Arrays.copyOf(val, val.length); +            for (int j = 0; j < newval.length; j++) { +                newval[j] = snapshot(newval[j]); +            } +            l.put(key, newval); +        } +    } + +    protected void copyInto(ArraySet<F> l, ArraySet<F> r) { +        l.clear(); +        final int end = r.size(); +        l.ensureCapacity(end); +        for (int i = 0; i < end; i++) { +            l.append(snapshot(r.valueAt(i)));          }      }      // Make <this> a copy of <orig>.  The presumption is that <this> is empty but all      // arrays are cleared out explicitly, just to be sure.      protected void copyFrom(IntentResolver orig) { -        mFilters.clear(); -        mFilters.addAll(orig.mFilters); -        mTypeToFilter.clear(); +        copyInto(mFilters, orig.mFilters);          copyInto(mTypeToFilter, orig.mTypeToFilter); -        mBaseTypeToFilter.clear();          copyInto(mBaseTypeToFilter, orig.mBaseTypeToFilter); -        mWildTypeToFilter.clear();          copyInto(mWildTypeToFilter, orig.mWildTypeToFilter); -        mSchemeToFilter.clear();          copyInto(mSchemeToFilter, orig.mSchemeToFilter); -        mActionToFilter.clear();          copyInto(mActionToFilter, orig.mActionToFilter); -        mTypedActionToFilter.clear();          copyInto(mTypedActionToFilter, orig.mTypedActionToFilter);      } diff --git a/services/core/java/com/android/server/TEST_MAPPING b/services/core/java/com/android/server/TEST_MAPPING index ceb12c8f483e..9e8b9c62ff51 100644 --- a/services/core/java/com/android/server/TEST_MAPPING +++ b/services/core/java/com/android/server/TEST_MAPPING @@ -36,6 +36,15 @@                  }              ],              "file_patterns": ["ClipboardService\\.java"] +        }, +        { +            "name": "FrameworksMockingServicesTests", +            "options": [ +                { +                    "include-filter": "com.android.server.sensorprivacy" +                } +            ], +            "file_patterns": ["SensorPrivacyService\\.java"]          }      ],      "presubmit-large": [ diff --git a/services/core/java/com/android/server/WatchedIntentResolver.java b/services/core/java/com/android/server/WatchedIntentResolver.java index e514f3c6fd59..0831c36d2bf6 100644 --- a/services/core/java/com/android/server/WatchedIntentResolver.java +++ b/services/core/java/com/android/server/WatchedIntentResolver.java @@ -19,10 +19,13 @@ package com.android.server;  import android.annotation.NonNull;  import android.annotation.Nullable; +import com.android.server.pm.WatchedIntentFilter; +import com.android.server.utils.Snappable;  import com.android.server.utils.Watchable;  import com.android.server.utils.WatchableImpl;  import com.android.server.utils.Watcher; +import java.util.ArrayList;  import java.util.List;  /** @@ -31,9 +34,9 @@ import java.util.List;   * @param <R> The resolver type.   * {@hide}   */ -public abstract class WatchedIntentResolver<F, R extends Object> +public abstract class WatchedIntentResolver<F extends Watchable, R extends Object>          extends IntentResolver<F, R> -        implements Watchable { +        implements Watchable, Snappable {      /**       * Watchable machinery @@ -78,6 +81,13 @@ public abstract class WatchedIntentResolver<F, R extends Object>          mWatchable.dispatchChange(what);      } +    private final Watcher mWatcher = new Watcher() { +            @Override +            public void onChange(@Nullable Watchable what) { +                dispatchChange(what); +            } +        }; +      /**       * Notify listeners that this object has changed.       */ @@ -88,17 +98,20 @@ public abstract class WatchedIntentResolver<F, R extends Object>      @Override      public void addFilter(F f) {          super.addFilter(f); +        f.registerObserver(mWatcher);          onChanged();      }      @Override      public void removeFilter(F f) { +        f.unregisterObserver(mWatcher);          super.removeFilter(f);          onChanged();      }      @Override      protected void removeFilterInternal(F f) { +        f.unregisterObserver(mWatcher);          super.removeFilterInternal(f);          onChanged();      } @@ -109,4 +122,17 @@ public abstract class WatchedIntentResolver<F, R extends Object>          super.sortResults(results);          onChanged();      } + +    /** +     * @see IntentResolver#findFilters(IntentFilter) +     */ +    public ArrayList<F> findFilters(WatchedIntentFilter matching) { +        return super.findFilters(matching.getIntentFilter()); +    } + +    // Make <this> a copy of <orig>.  The presumption is that <this> is empty but all +    // arrays are cleared out explicitly, just to be sure. +    protected void copyFrom(WatchedIntentResolver orig) { +        super.copyFrom(orig); +    }  } diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 206f135aef99..5700bb367b04 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -5934,7 +5934,7 @@ public final class ActiveServices {       */      private void logForegroundServiceStateChanged(ServiceRecord r, int state, int durationMs) {          if (!ActivityManagerUtils.shouldSamplePackageForAtom( -                r.packageName, mAm.mConstants.mDefaultFgsAtomSampleRate)) { +                r.packageName, mAm.mConstants.mFgsAtomSampleRate)) {              return;          }          FrameworkStatsLog.write(FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED, diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java index d8eccef8488e..f7ce6dd0144d 100644 --- a/services/core/java/com/android/server/am/ActivityManagerConstants.java +++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java @@ -73,10 +73,16 @@ final class ActivityManagerConstants extends ContentObserver {      private static final String KEY_POWER_CHECK_MAX_CPU_2 = "power_check_max_cpu_2";      private static final String KEY_POWER_CHECK_MAX_CPU_3 = "power_check_max_cpu_3";      private static final String KEY_POWER_CHECK_MAX_CPU_4 = "power_check_max_cpu_4"; -    private static final String KEY_SERVICE_USAGE_INTERACTION_TIME -            = "service_usage_interaction_time"; -    private static final String KEY_USAGE_STATS_INTERACTION_INTERVAL -            = "usage_stats_interaction_interval"; +    /** Used for all apps on R and earlier versions. */ +    private static final String KEY_SERVICE_USAGE_INTERACTION_TIME_PRE_S = +            "service_usage_interaction_time"; +    private static final String KEY_SERVICE_USAGE_INTERACTION_TIME_POST_S = +            "service_usage_interaction_time_post_s"; +    /** Used for all apps on R and earlier versions. */ +    private static final String KEY_USAGE_STATS_INTERACTION_INTERVAL_PRE_S = +            "usage_stats_interaction_interval"; +    private static final String KEY_USAGE_STATS_INTERACTION_INTERVAL_POST_S = +            "usage_stats_interaction_interval_post_s";      private static final String KEY_IMPERCEPTIBLE_KILL_EXEMPT_PACKAGES =              "imperceptible_kill_exempt_packages";      private static final String KEY_IMPERCEPTIBLE_KILL_EXEMPT_PROC_STATES = @@ -120,8 +126,10 @@ final class ActivityManagerConstants extends ContentObserver {      private static final int DEFAULT_POWER_CHECK_MAX_CPU_2 = 25;      private static final int DEFAULT_POWER_CHECK_MAX_CPU_3 = 10;      private static final int DEFAULT_POWER_CHECK_MAX_CPU_4 = 2; -    private static final long DEFAULT_SERVICE_USAGE_INTERACTION_TIME = 30*60*1000; -    private static final long DEFAULT_USAGE_STATS_INTERACTION_INTERVAL = 2*60*60*1000L; +    private static final long DEFAULT_SERVICE_USAGE_INTERACTION_TIME_PRE_S = 30 * 60 * 1000; +    private static final long DEFAULT_SERVICE_USAGE_INTERACTION_TIME_POST_S = 60 * 1000; +    private static final long DEFAULT_USAGE_STATS_INTERACTION_INTERVAL_PRE_S = 2 * 60 * 60 * 1000; +    private static final long DEFAULT_USAGE_STATS_INTERACTION_INTERVAL_POST_S = 10 * 60 * 1000;      private static final long DEFAULT_SERVICE_RESTART_DURATION = 1*1000;      private static final long DEFAULT_SERVICE_RESET_RUN_DURATION = 60*1000;      private static final int DEFAULT_SERVICE_RESTART_DURATION_FACTOR = 4; @@ -303,11 +311,23 @@ final class ActivityManagerConstants extends ContentObserver {      // This is the amount of time an app needs to be running a foreground service before      // we will consider it to be doing interaction for usage stats. -    long SERVICE_USAGE_INTERACTION_TIME = DEFAULT_SERVICE_USAGE_INTERACTION_TIME; +    // Only used for apps targeting pre-S versions. +    long SERVICE_USAGE_INTERACTION_TIME_PRE_S = DEFAULT_SERVICE_USAGE_INTERACTION_TIME_PRE_S; + +    // This is the amount of time an app needs to be running a foreground service before +    // we will consider it to be doing interaction for usage stats. +    // Only used for apps targeting versions S and above. +    long SERVICE_USAGE_INTERACTION_TIME_POST_S = DEFAULT_SERVICE_USAGE_INTERACTION_TIME_POST_S; + +    // Maximum amount of time we will allow to elapse before re-reporting usage stats +    // interaction with foreground processes. +    // Only used for apps targeting pre-S versions. +    long USAGE_STATS_INTERACTION_INTERVAL_PRE_S = DEFAULT_USAGE_STATS_INTERACTION_INTERVAL_PRE_S;      // Maximum amount of time we will allow to elapse before re-reporting usage stats      // interaction with foreground processes. -    long USAGE_STATS_INTERACTION_INTERVAL = DEFAULT_USAGE_STATS_INTERACTION_INTERVAL; +    // Only used for apps targeting versions S and above. +    long USAGE_STATS_INTERACTION_INTERVAL_POST_S = DEFAULT_USAGE_STATS_INTERACTION_INTERVAL_POST_S;      // How long a service needs to be running until restarting its process      // is no longer considered to be a relaunch of the service. @@ -460,7 +480,7 @@ final class ActivityManagerConstants extends ContentObserver {       *       * If the value is 0.1, 10% of the installed packages would be sampled.       */ -    volatile float mDefaultFgsAtomSampleRate = DEFAULT_FGS_ATOM_SAMPLE_RATE; +    volatile float mFgsAtomSampleRate = DEFAULT_FGS_ATOM_SAMPLE_RATE;      private final ActivityManagerService mService;      private ContentResolver mResolver; @@ -817,10 +837,18 @@ final class ActivityManagerConstants extends ContentObserver {                      DEFAULT_POWER_CHECK_MAX_CPU_3);              POWER_CHECK_MAX_CPU_4 = mParser.getInt(KEY_POWER_CHECK_MAX_CPU_4,                      DEFAULT_POWER_CHECK_MAX_CPU_4); -            SERVICE_USAGE_INTERACTION_TIME = mParser.getLong(KEY_SERVICE_USAGE_INTERACTION_TIME, -                    DEFAULT_SERVICE_USAGE_INTERACTION_TIME); -            USAGE_STATS_INTERACTION_INTERVAL = mParser.getLong(KEY_USAGE_STATS_INTERACTION_INTERVAL, -                    DEFAULT_USAGE_STATS_INTERACTION_INTERVAL); +            SERVICE_USAGE_INTERACTION_TIME_PRE_S = mParser.getLong( +                    KEY_SERVICE_USAGE_INTERACTION_TIME_PRE_S, +                    DEFAULT_SERVICE_USAGE_INTERACTION_TIME_PRE_S); +            SERVICE_USAGE_INTERACTION_TIME_POST_S = mParser.getLong( +                    KEY_SERVICE_USAGE_INTERACTION_TIME_POST_S, +                    DEFAULT_SERVICE_USAGE_INTERACTION_TIME_POST_S); +            USAGE_STATS_INTERACTION_INTERVAL_PRE_S = mParser.getLong( +                    KEY_USAGE_STATS_INTERACTION_INTERVAL_PRE_S, +                    DEFAULT_USAGE_STATS_INTERACTION_INTERVAL_PRE_S); +            USAGE_STATS_INTERACTION_INTERVAL_POST_S = mParser.getLong( +                    KEY_USAGE_STATS_INTERACTION_INTERVAL_POST_S, +                    DEFAULT_USAGE_STATS_INTERACTION_INTERVAL_POST_S);              SERVICE_RESTART_DURATION = mParser.getLong(KEY_SERVICE_RESTART_DURATION,                      DEFAULT_SERVICE_RESTART_DURATION);              SERVICE_RESET_RUN_DURATION = mParser.getLong(KEY_SERVICE_RESET_RUN_DURATION, @@ -985,7 +1013,7 @@ final class ActivityManagerConstants extends ContentObserver {      }      private void updateFgsAtomSamplePercent() { -        mDefaultFgsAtomSampleRate = DeviceConfig.getFloat( +        mFgsAtomSampleRate = DeviceConfig.getFloat(                  DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,                  KEY_FGS_ATOM_SAMPLE_RATE,                  DEFAULT_FGS_ATOM_SAMPLE_RATE); @@ -1135,10 +1163,14 @@ final class ActivityManagerConstants extends ContentObserver {          pw.println(POWER_CHECK_MAX_CPU_3);          pw.print("  "); pw.print(KEY_POWER_CHECK_MAX_CPU_4); pw.print("=");          pw.println(POWER_CHECK_MAX_CPU_4); -        pw.print("  "); pw.print(KEY_SERVICE_USAGE_INTERACTION_TIME); pw.print("="); -        pw.println(SERVICE_USAGE_INTERACTION_TIME); -        pw.print("  "); pw.print(KEY_USAGE_STATS_INTERACTION_INTERVAL); pw.print("="); -        pw.println(USAGE_STATS_INTERACTION_INTERVAL); +        pw.print("  "); pw.print(KEY_SERVICE_USAGE_INTERACTION_TIME_PRE_S); pw.print("="); +        pw.println(SERVICE_USAGE_INTERACTION_TIME_PRE_S); +        pw.print("  "); pw.print(KEY_SERVICE_USAGE_INTERACTION_TIME_POST_S); pw.print("="); +        pw.println(SERVICE_USAGE_INTERACTION_TIME_POST_S); +        pw.print("  "); pw.print(KEY_USAGE_STATS_INTERACTION_INTERVAL_PRE_S); pw.print("="); +        pw.println(USAGE_STATS_INTERACTION_INTERVAL_PRE_S); +        pw.print("  "); pw.print(KEY_USAGE_STATS_INTERACTION_INTERVAL_POST_S); pw.print("="); +        pw.println(USAGE_STATS_INTERACTION_INTERVAL_POST_S);          pw.print("  "); pw.print(KEY_SERVICE_RESTART_DURATION); pw.print("=");          pw.println(SERVICE_RESTART_DURATION);          pw.print("  "); pw.print(KEY_SERVICE_RESET_RUN_DURATION); pw.print("="); @@ -1204,7 +1236,7 @@ final class ActivityManagerConstants extends ContentObserver {          pw.print("  "); pw.print(KEY_DEFAULT_FGS_STARTS_RESTRICTION_CHECK_CALLER_TARGET_SDK);          pw.print("="); pw.println(mFgsStartRestrictionCheckCallerTargetSdk);          pw.print("  "); pw.print(KEY_FGS_ATOM_SAMPLE_RATE); -        pw.print("="); pw.println(mDefaultFgsAtomSampleRate); +        pw.print("="); pw.println(mFgsAtomSampleRate);          pw.print("  "); pw.print(KEY_PUSH_MESSAGING_OVER_QUOTA_BEHAVIOR);          pw.print("="); pw.println(mPushMessagingOverQuotaBehavior); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 9aedf1504df5..d526ebc8e581 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -14831,7 +14831,7 @@ public class ActivityManagerService extends IActivityManager.Stub                  throw new IllegalArgumentException("null fd");              } -            synchronized (mProcLock) { +            synchronized (this) {                  ProcessRecord proc = findProcessLOSP(process, userId, "dumpHeap");                  IApplicationThread thread;                  if (proc == null || (thread = proc.getThread()) == null) { diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index 649d05036027..b413010772a4 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -80,6 +80,7 @@ import android.app.ApplicationExitInfo;  import android.app.usage.UsageEvents;  import android.compat.annotation.ChangeId;  import android.compat.annotation.EnabledAfter; +import android.compat.annotation.EnabledSince;  import android.content.BroadcastReceiver;  import android.content.ComponentName;  import android.content.Context; @@ -122,7 +123,7 @@ import java.util.Arrays;  /**   * All of the code required to compute proc states and oom_adj values.   */ -public final class OomAdjuster { +public class OomAdjuster {      static final String TAG = "OomAdjuster";      static final String OOM_ADJ_REASON_METHOD = "updateOomAdj";      static final String OOM_ADJ_REASON_NONE = OOM_ADJ_REASON_METHOD + "_meh"; @@ -164,6 +165,14 @@ public final class OomAdjuster {      static final long CAMERA_MICROPHONE_CAPABILITY_CHANGE_ID = 136219221L;      /** +     * For apps targeting S+, this determines whether to use a shorter timeout before elevating the +     * standby bucket to ACTIVE when apps start a foreground service. +     */ +    @ChangeId +    @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.S) +    static final long USE_SHORT_FGS_USAGE_INTERACTION_TIME = 183972877L; + +    /**       * For some direct access we need to power manager.       */      PowerManagerInternal mLocalPowerManager; @@ -249,7 +258,9 @@ public final class OomAdjuster {      private final PlatformCompatCache mPlatformCompatCache; -    private static class PlatformCompatCache { +    /** Overrideable by a test */ +    @VisibleForTesting +    static class PlatformCompatCache {          private final PlatformCompat mPlatformCompat;          private final IPlatformCompat mIPlatformCompatProxy;          private final LongSparseArray<CacheItem> mCaches = new LongSparseArray<>(); @@ -278,6 +289,20 @@ public final class OomAdjuster {                      : mIPlatformCompatProxy.isChangeEnabled(changeId, app);          } +        /** +         * Same as {@link #isChangeEnabled(long, ApplicationInfo)} but instead of throwing a +         * RemoteException from platform compat, it returns the default value provided. +         */ +        boolean isChangeEnabled(long changeId, ApplicationInfo app, boolean defaultValue) { +            try { +                return mCacheEnabled ? mCaches.get(changeId).isChangeEnabled(app) +                        : mIPlatformCompatProxy.isChangeEnabled(changeId, app); +            } catch (RemoteException e) { +                Slog.w(TAG, "Error reading platform compat change " + changeId, e); +                return defaultValue; +            } +        } +          void invalidate(ApplicationInfo app) {              for (int i = mCaches.size() - 1; i >= 0; i--) {                  mCaches.valueAt(i).invalidate(app); @@ -335,6 +360,12 @@ public final class OomAdjuster {          }      } +    /** Overrideable by a test */ +    @VisibleForTesting +    protected PlatformCompatCache getPlatformCompatCache() { +        return mPlatformCompatCache; +    } +      OomAdjuster(ActivityManagerService service, ProcessList processList, ActiveUids activeUids) {          this(service, processList, activeUids, createAdjusterThread());      } @@ -383,7 +414,8 @@ public final class OomAdjuster {          mNumSlots = ((ProcessList.CACHED_APP_MAX_ADJ - ProcessList.CACHED_APP_MIN_ADJ + 1) >> 1)                  / ProcessList.CACHED_APP_IMPORTANCE_LEVELS;          mPlatformCompatCache = new PlatformCompatCache(new long[] { -                PROCESS_CAPABILITY_CHANGE_ID, CAMERA_MICROPHONE_CAPABILITY_CHANGE_ID +                PROCESS_CAPABILITY_CHANGE_ID, CAMERA_MICROPHONE_CAPABILITY_CHANGE_ID, +                USE_SHORT_FGS_USAGE_INTERACTION_TIME          });      } @@ -755,7 +787,7 @@ public final class OomAdjuster {          if (app != null) {              mPendingProcessSet.remove(app);              if (procDied) { -                mPlatformCompatCache.invalidate(app.info); +                getPlatformCompatCache().invalidate(app.info);              }          }      } @@ -1924,7 +1956,7 @@ public final class OomAdjuster {                      boolean enabled = false;                      try { -                        enabled = mPlatformCompatCache.isChangeEnabled( +                        enabled = getPlatformCompatCache().isChangeEnabled(                                  CAMERA_MICROPHONE_CAPABILITY_CHANGE_ID, s.appInfo);                      } catch (RemoteException e) {                      } @@ -2147,7 +2179,7 @@ public final class OomAdjuster {                                  state.bumpAllowStartFgsState(PROCESS_STATE_BOUND_TOP);                                  boolean enabled = false;                                  try { -                                    enabled = mPlatformCompatCache.isChangeEnabled( +                                    enabled = getPlatformCompatCache().isChangeEnabled(                                              PROCESS_CAPABILITY_CHANGE_ID, client.info);                                  } catch (RemoteException e) {                                  } @@ -2787,15 +2819,27 @@ public final class OomAdjuster {              } else {                  state.setProcStateChanged(true);              } -        } else if (state.hasReportedInteraction() && (nowElapsed - state.getInteractionEventTime()) -                > mConstants.USAGE_STATS_INTERACTION_INTERVAL) { +        } else if (state.hasReportedInteraction()) { +            final boolean fgsInteractionChangeEnabled = getPlatformCompatCache().isChangeEnabled( +                    USE_SHORT_FGS_USAGE_INTERACTION_TIME, app.info, false); +            final long interactionThreshold = fgsInteractionChangeEnabled +                    ? mConstants.USAGE_STATS_INTERACTION_INTERVAL_POST_S +                    : mConstants.USAGE_STATS_INTERACTION_INTERVAL_PRE_S;              // For apps that sit around for a long time in the interactive state, we need              // to report this at least once a day so they don't go idle. -            maybeUpdateUsageStatsLSP(app, nowElapsed); -        } else if (!state.hasReportedInteraction() && (nowElapsed - state.getFgInteractionTime()) -                > mConstants.SERVICE_USAGE_INTERACTION_TIME) { +            if ((nowElapsed - state.getInteractionEventTime()) > interactionThreshold) { +                maybeUpdateUsageStatsLSP(app, nowElapsed); +            } +        } else { +            final boolean fgsInteractionChangeEnabled = getPlatformCompatCache().isChangeEnabled( +                    USE_SHORT_FGS_USAGE_INTERACTION_TIME, app.info, false); +            final long interactionThreshold = fgsInteractionChangeEnabled +                    ? mConstants.SERVICE_USAGE_INTERACTION_TIME_POST_S +                    : mConstants.SERVICE_USAGE_INTERACTION_TIME_PRE_S;              // For foreground services that sit around for a long time but are not interacted with. -            maybeUpdateUsageStatsLSP(app, nowElapsed); +            if ((nowElapsed - state.getFgInteractionTime()) > interactionThreshold) { +                maybeUpdateUsageStatsLSP(app, nowElapsed); +            }          }          if (state.getCurCapability() != state.getSetCapability()) { @@ -2877,6 +2921,8 @@ public final class OomAdjuster {          if (mService.mUsageStatsService == null) {              return;          } +        final boolean fgsInteractionChangeEnabled = getPlatformCompatCache().isChangeEnabled( +                USE_SHORT_FGS_USAGE_INTERACTION_TIME, app.info, false);          boolean isInteraction;          // To avoid some abuse patterns, we are going to be careful about what we consider          // to be an app interaction.  Being the top activity doesn't count while the display @@ -2890,18 +2936,22 @@ public final class OomAdjuster {                  state.setFgInteractionTime(nowElapsed);                  isInteraction = false;              } else { -                isInteraction = nowElapsed > state.getFgInteractionTime() -                        + mConstants.SERVICE_USAGE_INTERACTION_TIME; +                final long interactionTime = fgsInteractionChangeEnabled +                        ? mConstants.SERVICE_USAGE_INTERACTION_TIME_POST_S +                        : mConstants.SERVICE_USAGE_INTERACTION_TIME_PRE_S; +                isInteraction = nowElapsed > state.getFgInteractionTime() + interactionTime;              }          } else {              isInteraction =                      state.getCurProcState() <= PROCESS_STATE_IMPORTANT_FOREGROUND;              state.setFgInteractionTime(0);          } +        final long interactionThreshold = fgsInteractionChangeEnabled +                ? mConstants.USAGE_STATS_INTERACTION_INTERVAL_POST_S +                : mConstants.USAGE_STATS_INTERACTION_INTERVAL_PRE_S;          if (isInteraction                  && (!state.hasReportedInteraction() -                    || (nowElapsed - state.getInteractionEventTime()) -                    > mConstants.USAGE_STATS_INTERACTION_INTERVAL)) { +                    || (nowElapsed - state.getInteractionEventTime()) > interactionThreshold)) {              state.setInteractionEventTime(nowElapsed);              String[] packages = app.getPackageList();              if (packages != null) { diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 6765ad02efa9..cc98abfc17f2 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -135,6 +135,7 @@ import com.android.server.pm.dex.DexManager;  import com.android.server.pm.parsing.pkg.AndroidPackage;  import com.android.server.wm.ActivityServiceConnectionsHolder;  import com.android.server.wm.WindowManagerService; +import com.android.server.wm.WindowProcessController;  import dalvik.system.VMRuntime; @@ -4626,6 +4627,7 @@ public final class ProcessList {      @GuardedBy(anyOf = {"mService", "mProcLock"})      void updateApplicationInfoLOSP(List<String> packagesToUpdate, int userId,              boolean updateFrameworkRes) { +        final ArrayList<WindowProcessController> targetProcesses = new ArrayList<>();          for (int i = mLruProcesses.size() - 1; i >= 0; i--) {              final ProcessRecord app = mLruProcesses.get(i);              if (app.getThread() == null) { @@ -4646,6 +4648,7 @@ public final class ProcessList {                              if (ai.packageName.equals(app.info.packageName)) {                                  app.info = ai;                              } +                            targetProcesses.add(app.getWindowProcessController());                          }                      } catch (RemoteException e) {                          Slog.w(TAG, String.format("Failed to update %s ApplicationInfo for %s", @@ -4654,6 +4657,9 @@ public final class ProcessList {                  }              });          } + +        mService.mActivityTaskManager.updateAssetConfiguration( +                updateFrameworkRes ? null : targetProcesses);      }      @GuardedBy("mService") diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java index b7ef10a5d45d..d2c6c6c620dd 100644 --- a/services/core/java/com/android/server/app/GameManagerService.java +++ b/services/core/java/com/android/server/app/GameManagerService.java @@ -56,6 +56,7 @@ import android.os.ShellCallback;  import android.provider.DeviceConfig;  import android.provider.DeviceConfig.Properties;  import android.util.ArrayMap; +import android.util.ArraySet;  import android.util.KeyValueListParser;  import android.util.Slog; @@ -180,9 +181,14 @@ public final class GameManagerService extends IGameManagerService.Stub {                      break;                  }                  case POPULATE_GAME_MODE_SETTINGS: { +                    // Scan all game packages and re-enforce the configured compat mode overrides +                    // as the DeviceConfig may have be wiped/since last reboot and we can't risk +                    // having overrides configured for packages that no longer have any DeviceConfig +                    // and thus any way to escape compat mode.                      removeMessages(POPULATE_GAME_MODE_SETTINGS, msg.obj); -                    loadDeviceConfigLocked(); -                    break; +                    final int userId = (int) msg.obj; +                    final String[] packageNames = getInstalledGamePackageNames(userId); +                    updateConfigsForUser(userId, packageNames);                  }              }          } @@ -198,28 +204,8 @@ public final class GameManagerService extends IGameManagerService.Stub {          @Override          public void onPropertiesChanged(Properties properties) { -            synchronized (mDeviceConfigLock) { -                for (final String packageName : properties.getKeyset()) { -                    try { -                        // Check if the package is installed before caching it. -                        mPackageManager.getPackageInfo(packageName, 0); -                        final GamePackageConfiguration config = -                                GamePackageConfiguration.fromProperties(packageName, properties); -                        if (config.isValid()) { -                            putConfig(config); -                        } else { -                            // This means that we received a bad config, or the config was deleted. -                            Slog.i(TAG, "Removing config for: " + packageName); -                            mConfigs.remove(packageName); -                            disableCompatScale(packageName); -                        } -                    } catch (PackageManager.NameNotFoundException e) { -                        if (DEBUG) { -                            Slog.v(TAG, "Package name not found", e); -                        } -                    } -                } -            } +            final String[] packageNames = properties.getKeyset().toArray(new String[0]); +            updateConfigsForUser(mContext.getUserId(), packageNames);          }          @Override @@ -228,80 +214,166 @@ public final class GameManagerService extends IGameManagerService.Stub {          }      } -    private static class GameModeConfiguration { -        public static final String TAG = "GameManagerService_GameModeConfiguration"; -        public static final String MODE_KEY = "mode"; -        public static final String SCALING_KEY = "downscaleFactor"; +    /** +     * GamePackageConfiguration manages all game mode config details for its associated package. +     */ +    @VisibleForTesting +    public class GamePackageConfiguration { +        public static final String TAG = "GameManagerService_GamePackageConfiguration"; -        private final @GameMode int mGameMode; -        private final String mScaling; +        /** +         * Metadata that can be included in the app manifest to allow/disallow any window manager +         * downscaling interventions. Default value is TRUE. +         */ +        public static final String METADATA_WM_ALLOW_DOWNSCALE = +                "com.android.graphics.intervention.wm.allowDownscale"; -        private GameModeConfiguration(@NonNull int gameMode, -                @NonNull String scaling) { -            mGameMode = gameMode; -            mScaling = scaling; -        } +        /** +         * Metadata that needs to be included in the app manifest to OPT-IN to PERFORMANCE mode. +         * This means the app will assume full responsibility for the experience provided by this +         * mode and the system will enable no window manager downscaling. +         * Default value is FALSE +         */ +        public static final String METADATA_PERFORMANCE_MODE_ENABLE = +                "com.android.app.gamemode.performance.enabled"; -        public static GameModeConfiguration fromKeyValueListParser(KeyValueListParser parser) { -            return new GameModeConfiguration( -                    parser.getInt(MODE_KEY, GameManager.GAME_MODE_UNSUPPORTED), -                    parser.getString(SCALING_KEY, "1.0") -            ); -        } +        /** +         * Metadata that needs to be included in the app manifest to OPT-IN to BATTERY mode. +         * This means the app will assume full responsibility for the experience provided by this +         * mode and the system will enable no window manager downscaling. +         * Default value is FALSE +         */ +        public static final String METADATA_BATTERY_MODE_ENABLE = +                "com.android.app.gamemode.battery.enabled"; -        public int getGameMode() { -            return mGameMode; -        } +        private final String mPackageName; +        private final ArrayMap<Integer, GameModeConfiguration> mModeConfigs; +        private boolean mPerfModeOptedIn; +        private boolean mBatteryModeOptedIn; +        private boolean mAllowDownscale; -        public String getScaling() { -            return mScaling; +        GamePackageConfiguration(String packageName, int userId) { +            mPackageName = packageName; +            mModeConfigs = new ArrayMap<>(); +            try { +                final ApplicationInfo ai = mPackageManager.getApplicationInfoAsUser(packageName, +                        PackageManager.GET_META_DATA, userId); +                if (ai.metaData != null) { +                    mPerfModeOptedIn = ai.metaData.getBoolean(METADATA_PERFORMANCE_MODE_ENABLE); +                    mBatteryModeOptedIn = ai.metaData.getBoolean(METADATA_BATTERY_MODE_ENABLE); +                    mAllowDownscale = ai.metaData.getBoolean(METADATA_WM_ALLOW_DOWNSCALE, true); +                } else { +                    mPerfModeOptedIn = false; +                    mBatteryModeOptedIn = false; +                    mAllowDownscale = true; +                } +            } catch (PackageManager.NameNotFoundException e) { +                Slog.e(TAG, "Failed to get package metadata", e); +            } +            final String configString = DeviceConfig.getProperty( +                    DeviceConfig.NAMESPACE_GAME_OVERLAY, packageName); +            if (configString != null) { +                final String[] gameModeConfigStrings = configString.split(":"); +                for (String gameModeConfigString : gameModeConfigStrings) { +                    try { +                        final KeyValueListParser parser = new KeyValueListParser(','); +                        parser.setString(gameModeConfigString); +                        addModeConfig(new GameModeConfiguration(parser)); +                    } catch (IllegalArgumentException e) { +                        Slog.e(TAG, "Invalid config string"); +                    } +                } +            }          } -        public boolean isValid() { -            return (mGameMode == GameManager.GAME_MODE_PERFORMANCE -                    || mGameMode == GameManager.GAME_MODE_BATTERY) && getCompatChangeId() != 0; -        } +        /** +         * GameModeConfiguration contains all the values for all the interventions associated with +         * a game mode. +         */ +        @VisibleForTesting +        public class GameModeConfiguration { +            public static final String TAG = "GameManagerService_GameModeConfiguration"; +            public static final String MODE_KEY = "mode"; +            public static final String SCALING_KEY = "downscaleFactor"; +            public static final String DEFAULT_SCALING = "1.0"; + +            private final @GameMode int mGameMode; +            private final String mScaling; + +            GameModeConfiguration(KeyValueListParser parser) { +                mGameMode = parser.getInt(MODE_KEY, GameManager.GAME_MODE_UNSUPPORTED); +                mScaling = !mAllowDownscale || isGameModeOptedIn(mGameMode) +                        ? DEFAULT_SCALING : parser.getString(SCALING_KEY, DEFAULT_SCALING); +            } -        public String toString() { -            return "[Game Mode:" + mGameMode + ",Scaling:" + mScaling + "]"; -        } +            public int getGameMode() { +                return mGameMode; +            } -        public long getCompatChangeId() { -            switch (mScaling) { -                case "0.5": -                    return DOWNSCALE_50; -                case "0.6": -                    return DOWNSCALE_60; -                case "0.7": -                    return DOWNSCALE_70; -                case "0.8": -                    return DOWNSCALE_80; -                case "0.9": -                    return DOWNSCALE_90; +            public String getScaling() { +                return mScaling;              } -            return 0; -        } -    } -    private static class GamePackageConfiguration { -        public static final String TAG = "GameManagerService_GamePackageConfiguration"; +            public boolean isValid() { +                return (mGameMode == GameManager.GAME_MODE_PERFORMANCE +                        || mGameMode == GameManager.GAME_MODE_BATTERY) +                        && (!mAllowDownscale || getCompatChangeId() != 0); +            } -        private final String mPackageName; -        private final ArrayMap<Integer, GameModeConfiguration> mModeConfigs; +            /** +             * @hide +             */ +            public String toString() { +                return "[Game Mode:" + mGameMode + ",Scaling:" + mScaling + "]"; +            } -        private GamePackageConfiguration(String packageName) { -            mPackageName = packageName; -            mModeConfigs = new ArrayMap<>(); +            /** +             * Get the corresponding compat change id for the current scaling string. +             */ +            public long getCompatChangeId() { +                switch (mScaling) { +                    case "0.5": +                        return DOWNSCALE_50; +                    case "0.6": +                        return DOWNSCALE_60; +                    case "0.7": +                        return DOWNSCALE_70; +                    case "0.8": +                        return DOWNSCALE_80; +                    case "0.9": +                        return DOWNSCALE_90; +                } +                return 0; +            }          }          public String getPackageName() {              return mPackageName;          } +        /** +         * Gets whether a package has opted into a game mode via its manifest. +         * +         * @return True if the app package has specified in its metadata either: +         * "com.android.app.gamemode.performance.enabled" or +         * "com.android.app.gamemode.battery.enabled" with a value of "true" +         */ +        public boolean isGameModeOptedIn(@GameMode int gameMode) { +            return (mBatteryModeOptedIn && gameMode == GameManager.GAME_MODE_BATTERY) +                    || (mPerfModeOptedIn && gameMode == GameManager.GAME_MODE_PERFORMANCE); +        } +          public @GameMode int[] getAvailableGameModes() { -            if (mModeConfigs.keySet().size() > 0) { -                return mModeConfigs.keySet().stream() -                            .mapToInt(Integer::intValue).toArray(); +            ArraySet<Integer> modeSet = new ArraySet<>(mModeConfigs.keySet()); +            if (mBatteryModeOptedIn) { +                modeSet.add(GameManager.GAME_MODE_BATTERY); +            } +            if (mPerfModeOptedIn) { +                modeSet.add(GameManager.GAME_MODE_PERFORMANCE); +            } +            if (modeSet.size() > 0) { +                modeSet.add(GameManager.GAME_MODE_STANDARD); +                return modeSet.stream().mapToInt(Integer::intValue).toArray();              }              return new int[]{GameManager.GAME_MODE_UNSUPPORTED};          } @@ -327,30 +399,8 @@ public final class GameManagerService extends IGameManagerService.Stub {              }          } -        /** -         * Create a new instance from a package name and DeviceConfig.Properties instance -         */ -        public static GamePackageConfiguration fromProperties(String key, -                Properties properties) { -            final GamePackageConfiguration packageConfig = new GamePackageConfiguration(key); -            final String configString = properties.getString(key, ""); -            final String[] gameModeConfigStrings = configString.split(":"); -            for (String gameModeConfigString : gameModeConfigStrings) { -                try { -                    final KeyValueListParser parser = new KeyValueListParser(','); -                    parser.setString(gameModeConfigString); -                    final GameModeConfiguration config = -                            GameModeConfiguration.fromKeyValueListParser(parser); -                    packageConfig.addModeConfig(config); -                } catch (IllegalArgumentException e) { -                    Slog.e(TAG, "Invalid config string"); -                } -            } -            return packageConfig; -        } -          public boolean isValid() { -            return mModeConfigs.size() > 0; +            return mModeConfigs.size() > 0 || mBatteryModeOptedIn || mPerfModeOptedIn;          }          public String toString() { @@ -534,8 +584,6 @@ public final class GameManagerService extends IGameManagerService.Stub {      @VisibleForTesting      void onBootCompleted() {          Slog.d(TAG, "onBootCompleted"); -        final Message msg = mHandler.obtainMessage(POPULATE_GAME_MODE_SETTINGS); -        mHandler.sendMessage(msg);      }      void onUserStarting(int userId) { @@ -549,6 +597,9 @@ public final class GameManagerService extends IGameManagerService.Stub {              mSettings.put(userId, userSettings);              userSettings.readPersistentDataLocked();          } +        final Message msg = mHandler.obtainMessage(POPULATE_GAME_MODE_SETTINGS); +        msg.obj = userId; +        mHandler.sendMessage(msg);      }      void onUserStopping(int userId) { @@ -562,24 +613,14 @@ public final class GameManagerService extends IGameManagerService.Stub {          }      } -    void loadDeviceConfigLocked() { -        final List<PackageInfo> packages = mPackageManager.getInstalledPackages(0); -        final String[] packageNames = packages.stream().map(e -> e.packageName) -                .toArray(String[]::new); -        synchronized (mDeviceConfigLock) { -            final Properties properties = DeviceConfig.getProperties( -                    DeviceConfig.NAMESPACE_GAME_OVERLAY, packageNames); -            for (String key : properties.getKeyset()) { -                final GamePackageConfiguration config = -                        GamePackageConfiguration.fromProperties(key, properties); -                putConfig(config); -            } -        } -    } - -    private void disableCompatScale(String packageName) { +    /** +     * @hide +     */ +    @VisibleForTesting +    public void disableCompatScale(String packageName) {          final long uid = Binder.clearCallingIdentity();          try { +            Slog.i(TAG, "Disabling downscale for " + packageName);              final ArrayMap<Long, PackageOverride> overrides = new ArrayMap<>();              overrides.put(DOWNSCALED, COMPAT_DISABLED);              final CompatibilityOverrideConfig changeConfig = new CompatibilityOverrideConfig( @@ -597,6 +638,7 @@ public final class GameManagerService extends IGameManagerService.Stub {      private void enableCompatScale(String packageName, long scaleId) {          final long uid = Binder.clearCallingIdentity();          try { +            Slog.i(TAG, "Enabling downscale: " + scaleId + " for " + packageName);              final ArrayMap<Long, PackageOverride> overrides = new ArrayMap<>();              overrides.put(DOWNSCALED, COMPAT_ENABLED);              overrides.put(DOWNSCALE_50, COMPAT_DISABLED); @@ -622,21 +664,25 @@ public final class GameManagerService extends IGameManagerService.Stub {              if (gameMode == GameManager.GAME_MODE_STANDARD                      || gameMode == GameManager.GAME_MODE_UNSUPPORTED) {                  disableCompatScale(packageName); -                Slog.v(TAG, "Disabling downscale"); +                return; +            } +            final GamePackageConfiguration packageConfig = mConfigs.get(packageName); +            if (packageConfig == null) { +                disableCompatScale(packageName); +                Slog.v(TAG, "Package configuration not found for " + packageName);                  return;              }              if (DEBUG) {                  Slog.v(TAG, dumpDeviceConfigs());              } -            final GamePackageConfiguration packageConfig = mConfigs.get(packageName); -            if (packageConfig == null) { -                Slog.w(TAG, "Package configuration not found for " + packageName); +            if (packageConfig.isGameModeOptedIn(gameMode)) { +                disableCompatScale(packageName);                  return;              } -            final GameModeConfiguration modeConfig = packageConfig.getGameModeConfiguration( -                    gameMode); +            final GamePackageConfiguration.GameModeConfiguration modeConfig = +                    packageConfig.getGameModeConfiguration(gameMode);              if (modeConfig == null) { -                Slog.w(TAG, "Game mode " + gameMode + " not found for " + packageName); +                Slog.i(TAG, "Game mode " + gameMode + " not found for " + packageName);                  return;              }              long scaleId = modeConfig.getCompatChangeId(); @@ -645,23 +691,64 @@ public final class GameManagerService extends IGameManagerService.Stub {                          + packageName);                  return;              } -            Slog.i(TAG, "Enabling downscale: " + scaleId + " for " + packageName); +              enableCompatScale(packageName, scaleId);          }      } -    private void putConfig(GamePackageConfiguration config) { -        if (config.isValid()) { -            if (DEBUG) { -                Slog.i(TAG, "Adding config: " + config.toString()); +    /** +     * @hide +     */ +    @VisibleForTesting +    public void updateConfigsForUser(int userId, String ...packageNames) { +        try { +            synchronized (mDeviceConfigLock) { +                for (String packageName : packageNames) { +                    GamePackageConfiguration config = +                            new GamePackageConfiguration(packageName, userId); +                    if (config.isValid()) { +                        if (DEBUG) { +                            Slog.i(TAG, "Adding config: " + config.toString()); +                        } +                        mConfigs.put(packageName, config); +                    } else { +                        Slog.w(TAG, "Invalid package config for " +                                + config.getPackageName() + ":" + config.toString()); +                        mConfigs.remove(packageName); +                    } +                }              } -            mConfigs.put(config.getPackageName(), config); -        } else { -            Slog.w(TAG, "Invalid package config for " -                    + config.getPackageName() + ":" + config.toString()); +            for (String packageName : packageNames) { +                synchronized (mLock) { +                    if (mSettings.containsKey(userId)) { +                        GameManagerSettings userSettings = mSettings.get(userId); +                        updateCompatModeDownscale(packageName, +                                userSettings.getGameModeLocked(packageName)); +                    } +                } +            } +        } catch (Exception e) { +            Slog.e(TAG, "Failed to update compat modes for user: " + userId);          }      } +    private String[] getInstalledGamePackageNames(int userId) { +        final List<PackageInfo> packages = +                mPackageManager.getInstalledPackagesAsUser(0, userId); +        return packages.stream().filter(e -> e.applicationInfo != null && e.applicationInfo.category +                        == ApplicationInfo.CATEGORY_GAME) +                .map(e -> e.packageName) +                .toArray(String[]::new); +    } + +    /** +     * @hide +     */ +    @VisibleForTesting +    public GamePackageConfiguration getConfig(String packageName) { +        return mConfigs.get(packageName); +    } +      private void registerPackageReceiver() {          final IntentFilter packageFilter = new IntentFilter();          packageFilter.addAction(ACTION_PACKAGE_ADDED); @@ -677,16 +764,7 @@ public final class GameManagerService extends IGameManagerService.Stub {                      switch (intent.getAction()) {                          case ACTION_PACKAGE_ADDED:                          case ACTION_PACKAGE_CHANGED: -                            synchronized (mDeviceConfigLock) { -                                Properties properties = DeviceConfig.getProperties( -                                        DeviceConfig.NAMESPACE_GAME_OVERLAY, packageName); -                                for (String key : properties.getKeyset()) { -                                    GamePackageConfiguration config = -                                            GamePackageConfiguration.fromProperties(key, -                                                    properties); -                                    putConfig(config); -                                } -                            } +                            updateConfigsForUser(mContext.getUserId(), packageName);                              break;                          case ACTION_PACKAGE_REMOVED:                              disableCompatScale(packageName); diff --git a/services/core/java/com/android/server/appop/DiscreteRegistry.java b/services/core/java/com/android/server/appop/DiscreteRegistry.java index 63b41b789280..e9b61b3ab7fb 100644 --- a/services/core/java/com/android/server/appop/DiscreteRegistry.java +++ b/services/core/java/com/android/server/appop/DiscreteRegistry.java @@ -69,18 +69,47 @@ import java.util.Date;  import java.util.List;  /** - * This class manages information about recent accesses to ops for - * permission usage timeline. + * This class manages information about recent accesses to ops for permission usage timeline.   * - * The timeline history is kept for limited time (initial default is 24 hours) and - * discarded after that. + * The discrete history is kept for limited time (initial default is 24 hours, set in + * {@link DiscreteRegistry#sDiscreteHistoryCutoff) and discarded after that. + * + * Discrete history is quantized to reduce resources footprint. By default quantization is set to + * one minute in {@link DiscreteRegistry#sDiscreteHistoryQuantization}. All access times are aligned + * to the closest quantized time. All durations (except -1, meaning no duration) are rounded up to + * the closest quantized interval. + * + * When data is queried through API, events are deduplicated and for every time quant there can + * be only one {@link AppOpsManager.AttributedOpEntry}. Each entry contains information about + * different accesses which happened in specified time quant - across dimensions of + * {@link AppOpsManager.UidState} and {@link AppOpsManager.OpFlags}. For each dimension + * it is only possible to know if at least one access happened in the time quant.   *   * Every time state is saved (default is 30 minutes), memory state is dumped to a   * new file and memory state is cleared. Files older than time limit are deleted   * during the process.   *   * When request comes in, files are read and requested information is collected - * and delivered. + * and delivered. Information is cached in memory until the next state save (up to 30 minutes), to + * avoid reading disk if more API calls come in a quick succession. + * + * THREADING AND LOCKING: + * For in-memory transactions this class relies on {@link DiscreteRegistry#mInMemoryLock}. It is + * assumed that the same lock is used for in-memory transactions in {@link AppOpsService}, + * {@link HistoricalRegistry}, and {@link DiscreteRegistry}. + * {@link DiscreteRegistry#recordDiscreteAccess(int, String, int, String, int, int, long, long)} + * must only be called while holding this lock. + * {@link DiscreteRegistry#mOnDiskLock} is used when disk transactions are performed. + * It is very important to release {@link DiscreteRegistry#mInMemoryLock} as soon as possible, as + * no AppOps related transactions across the system can be performed while it is held. + * + * INITIALIZATION: We can initialize persistence only after the system is ready + * as we need to check the optional configuration override from the settings + * database which is not initialized at the time the app ops service is created. This class + * relies on {@link HistoricalRegistry} for controlling that no calls are allowed until then. All + * outside calls are going through {@link HistoricalRegistry}, where + * {@link HistoricalRegistry#isPersistenceInitializedMLocked()} check is done. + *   */  final class DiscreteRegistry { diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java index f566080b3fca..a1395890fd3c 100644 --- a/services/core/java/com/android/server/attention/AttentionManagerService.java +++ b/services/core/java/com/android/server/attention/AttentionManagerService.java @@ -257,8 +257,8 @@ public class AttentionManagerService extends SystemService {              return false;          } -        // don't allow attention check in screen off state -        if (!mPowerManager.isInteractive()) { +        // don't allow attention check in screen off state or power save mode +        if (!mPowerManager.isInteractive() || mPowerManager.isPowerSaveMode()) {              return false;          } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java index 39b7a74caa52..ce06d06afe4e 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java @@ -811,7 +811,7 @@ public class FingerprintService extends SystemService {              for (String instance : instances) {                  final String fqName = IFingerprint.DESCRIPTOR + "/" + instance;                  final IFingerprint fp = IFingerprint.Stub.asInterface( -                        ServiceManager.waitForDeclaredService(fqName)); +                        Binder.allowBlocking(ServiceManager.waitForDeclaredService(fqName)));                  if (fp == null) {                      Slog.e(TAG, "Unable to get declared service: " + fqName);                      continue; diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java index c23c113b5672..083df1929326 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java @@ -37,6 +37,7 @@ import android.hardware.fingerprint.FingerprintManager;  import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;  import android.hardware.fingerprint.IFingerprintServiceReceiver;  import android.hardware.fingerprint.IUdfpsOverlayController; +import android.os.Binder;  import android.os.Handler;  import android.os.IBinder;  import android.os.Looper; @@ -186,8 +187,9 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi          Slog.d(getTag(), "Daemon was null, reconnecting");          mDaemon = IFingerprint.Stub.asInterface( -                ServiceManager.waitForDeclaredService(IFingerprint.DESCRIPTOR -                        + "/" + mHalInstanceName)); +                Binder.allowBlocking( +                        ServiceManager.waitForDeclaredService( +                                IFingerprint.DESCRIPTOR + "/" + mHalInstanceName)));          if (mDaemon == null) {              Slog.e(getTag(), "Unable to get daemon");              return null; diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java index 4bd1fd8e44cc..0314510b2b5a 100644 --- a/services/core/java/com/android/server/content/SyncManager.java +++ b/services/core/java/com/android/server/content/SyncManager.java @@ -1478,12 +1478,11 @@ public class SyncManager {                          + logSafe(syncOperation.target));                  backoff = new Pair<Long, Long>(SyncStorageEngine.NOT_IN_BACKOFF_MODE,                          SyncStorageEngine.NOT_IN_BACKOFF_MODE); -            } else { +            } else if (backoff.first != SyncStorageEngine.NOT_IN_BACKOFF_MODE) {                  // if an EJ is being backed-off but doesn't have SYNC_EXTRAS_IGNORE_BACKOFF set, -                // reschedule it as a regular job -                if (syncOperation.isScheduledAsExpeditedJob()) { -                    syncOperation.scheduleEjAsRegularJob = true; -                } +                // reschedule it as a regular job. Immediately downgrade here in case minDelay is +                // set to 0. +                syncOperation.scheduleEjAsRegularJob = true;              }              long now = SystemClock.elapsedRealtime();              long backoffDelay = backoff.first == SyncStorageEngine.NOT_IN_BACKOFF_MODE ? 0 diff --git a/services/core/java/com/android/server/content/SyncOperation.java b/services/core/java/com/android/server/content/SyncOperation.java index c8654d1b36ee..f6fad2500626 100644 --- a/services/core/java/com/android/server/content/SyncOperation.java +++ b/services/core/java/com/android/server/content/SyncOperation.java @@ -258,6 +258,7 @@ public class SyncOperation {          jobInfoExtras.putLong("expectedRuntime", expectedRuntime);          jobInfoExtras.putInt("retries", retries);          jobInfoExtras.putInt("syncExemptionFlag", syncExemptionFlag); +        jobInfoExtras.putBoolean("ejDowngradedToRegular", scheduleEjAsRegularJob);          return jobInfoExtras;      } @@ -325,6 +326,7 @@ public class SyncOperation {          op.jobId = jobExtras.getInt("jobId");          op.expectedRuntime = jobExtras.getLong("expectedRuntime");          op.retries = jobExtras.getInt("retries"); +        op.scheduleEjAsRegularJob = jobExtras.getBoolean("ejDowngradedToRegular");          return op;      } diff --git a/services/core/java/com/android/server/inputmethod/InputContentUriTokenHandler.java b/services/core/java/com/android/server/inputmethod/InputContentUriTokenHandler.java index 78c414452ddd..5a0069ac8e06 100644 --- a/services/core/java/com/android/server/inputmethod/InputContentUriTokenHandler.java +++ b/services/core/java/com/android/server/inputmethod/InputContentUriTokenHandler.java @@ -104,7 +104,8 @@ final class InputContentUriTokenHandler extends IInputContentUriToken.Stub {      }      /** -     * {@inheritDoc} +     * If permissions are not released explicitly via {@link #release()}, release automatically +     * whenever there are no more references to this object.       */      @Override      protected void finalize() throws Throwable { diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java index 864aa33a58d0..172a68a27571 100644 --- a/services/core/java/com/android/server/location/LocationManagerService.java +++ b/services/core/java/com/android/server/location/LocationManagerService.java @@ -171,8 +171,7 @@ public class LocationManagerService extends ILocationManager.Stub {              // client caching behavior is only enabled after seeing the first invalidate              LocationManager.invalidateLocalLocationEnabledCaches();              // disable caching for our own process -            Objects.requireNonNull(getContext().getSystemService(LocationManager.class)) -                    .disableLocalLocationEnabledCaches(); +            LocationManager.disableLocalLocationEnabledCaches();          }          @Override 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 0be325fb6aa7..4b772f29e250 100644 --- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java +++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java @@ -2271,22 +2271,28 @@ public class LocationProviderManager extends          }          if (mOnLocationTagsChangeListener != null) { -            if (!oldState.extraAttributionTags.equals(newState.extraAttributionTags)) { +            if (!oldState.extraAttributionTags.equals(newState.extraAttributionTags) +                    || !Objects.equals(oldState.identity, newState.identity)) {                  if (oldState.identity != null) {                      FgThread.getHandler().sendMessage(PooledLambda.obtainMessage(                              OnProviderLocationTagsChangeListener::onLocationTagsChanged,                              mOnLocationTagsChangeListener, new LocationTagInfo(                                      oldState.identity.getUid(), oldState.identity.getPackageName(),                                      Collections.emptySet()) -                            )); +                    ));                  }                  if (newState.identity != null) { +                    ArraySet<String> attributionTags = new ArraySet<>( +                            newState.extraAttributionTags.size() + 1); +                    attributionTags.addAll(newState.extraAttributionTags); +                    attributionTags.add(newState.identity.getAttributionTag()); +                      FgThread.getHandler().sendMessage(PooledLambda.obtainMessage(                              OnProviderLocationTagsChangeListener::onLocationTagsChanged,                              mOnLocationTagsChangeListener, new LocationTagInfo(                                      newState.identity.getUid(), newState.identity.getPackageName(), -                                    newState.extraAttributionTags) -                            )); +                                    attributionTags) +                    ));                  }              }          } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 08a7d9e38d96..0840e75823b5 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -123,7 +123,7 @@ import static com.android.server.utils.PriorityDump.PRIORITY_ARG_NORMAL;  import android.Manifest;  import android.Manifest.permission; -import android.annotation.CallbackExecutor; +import android.annotation.MainThread;  import android.annotation.NonNull;  import android.annotation.Nullable;  import android.annotation.RequiresPermission; @@ -492,7 +492,7 @@ public class NotificationManagerService extends SystemService {      private DeviceIdleManager mDeviceIdleManager;      private IUriGrantsManager mUgm;      private UriGrantsManagerInternal mUgmInternal; -    private RoleObserver mRoleObserver; +    private volatile RoleObserver mRoleObserver;      private UserManager mUm;      private IPlatformCompat mPlatformCompat;      private ShortcutHelper mShortcutHelper; @@ -629,6 +629,8 @@ public class NotificationManagerService extends SystemService {      static class Archive {          final SparseArray<Boolean> mEnabled;          final int mBufferSize; +        final Object mBufferLock = new Object(); +        @GuardedBy("mBufferLock")          final LinkedList<Pair<StatusBarNotification, Integer>> mBuffer;          public Archive(int size) { @@ -651,14 +653,16 @@ public class NotificationManagerService extends SystemService {              if (!mEnabled.get(sbn.getNormalizedUserId(), false)) {                  return;              } -            if (mBuffer.size() == mBufferSize) { -                mBuffer.removeFirst(); -            } +            synchronized (mBufferLock) { +                if (mBuffer.size() == mBufferSize) { +                    mBuffer.removeFirst(); +                } -            // We don't want to store the heavy bits of the notification in the archive, -            // but other clients in the system process might be using the object, so we -            // store a (lightened) copy. -            mBuffer.addLast(new Pair<>(sbn.cloneLight(), reason)); +                // We don't want to store the heavy bits of the notification in the archive, +                // but other clients in the system process might be using the object, so we +                // store a (lightened) copy. +                mBuffer.addLast(new Pair<>(sbn.cloneLight(), reason)); +            }          }          public Iterator<Pair<StatusBarNotification, Integer>> descendingIterator() { @@ -666,27 +670,31 @@ public class NotificationManagerService extends SystemService {          }          public StatusBarNotification[] getArray(int count, boolean includeSnoozed) { -            if (count == 0) count = mBufferSize; -            List<StatusBarNotification> a = new ArrayList(); -            Iterator<Pair<StatusBarNotification, Integer>> iter = descendingIterator(); -            int i=0; -            while (iter.hasNext() && i < count) { -                Pair<StatusBarNotification, Integer> pair = iter.next(); -                if (pair.second != REASON_SNOOZED || includeSnoozed) { -                    i++; -                    a.add(pair.first); +            synchronized (mBufferLock) { +                if (count == 0) count = mBufferSize; +                List<StatusBarNotification> a = new ArrayList(); +                Iterator<Pair<StatusBarNotification, Integer>> iter = descendingIterator(); +                int i = 0; +                while (iter.hasNext() && i < count) { +                    Pair<StatusBarNotification, Integer> pair = iter.next(); +                    if (pair.second != REASON_SNOOZED || includeSnoozed) { +                        i++; +                        a.add(pair.first); +                    }                  } +                return a.toArray(new StatusBarNotification[a.size()]);              } -            return  a.toArray(new StatusBarNotification[a.size()]);          }          public void updateHistoryEnabled(@UserIdInt int userId, boolean enabled) {              mEnabled.put(userId, enabled);              if (!enabled) { -                for (int i = mBuffer.size() - 1; i >= 0; i--) { -                    if (userId == mBuffer.get(i).first.getNormalizedUserId()) { -                        mBuffer.remove(i); +                synchronized (mBufferLock) { +                    for (int i = mBuffer.size() - 1; i >= 0; i--) { +                        if (userId == mBuffer.get(i).first.getNormalizedUserId()) { +                            mBuffer.remove(i); +                        }                      }                  }              } @@ -695,15 +703,18 @@ public class NotificationManagerService extends SystemService {          // Remove notifications with the specified user & channel ID.          public void removeChannelNotifications(String pkg, @UserIdInt int userId,                  String channelId) { -            Iterator<Pair<StatusBarNotification, Integer>> bufferIter = mBuffer.iterator(); -            while (bufferIter.hasNext()) { -                final Pair<StatusBarNotification, Integer> pair = bufferIter.next(); -                if (pair.first != null -                        && userId == pair.first.getNormalizedUserId() -                        && pkg != null && pkg.equals(pair.first.getPackageName()) -                        && pair.first.getNotification() != null -                        && Objects.equals(channelId, pair.first.getNotification().getChannelId())) { -                    bufferIter.remove(); +            synchronized (mBufferLock) { +                Iterator<Pair<StatusBarNotification, Integer>> bufferIter = descendingIterator(); +                while (bufferIter.hasNext()) { +                    final Pair<StatusBarNotification, Integer> pair = bufferIter.next(); +                    if (pair.first != null +                            && userId == pair.first.getNormalizedUserId() +                            && pkg != null && pkg.equals(pair.first.getPackageName()) +                            && pair.first.getNotification() != null +                            && Objects.equals(channelId, +                            pair.first.getNotification().getChannelId())) { +                        bufferIter.remove(); +                    }                  }              }          } @@ -2640,6 +2651,11 @@ public class NotificationManagerService extends SystemService {      @Override      public void onBootPhase(int phase) { +        onBootPhase(phase, Looper.getMainLooper()); +    } + +    @VisibleForTesting +    void onBootPhase(int phase, Looper mainLooper) {          if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {              // no beeping until we're basically done booting              mSystemReady = true; @@ -2649,9 +2665,11 @@ public class NotificationManagerService extends SystemService {              mAudioManagerInternal = getLocalService(AudioManagerInternal.class);              mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);              mZenModeHelper.onSystemReady(); -            mRoleObserver = new RoleObserver(getContext().getSystemService(RoleManager.class), -                    mPackageManager, getContext().getMainExecutor()); -            mRoleObserver.init(); +            RoleObserver roleObserver = new RoleObserver(getContext(), +                    getContext().getSystemService(RoleManager.class), +                    mPackageManager, mainLooper); +            roleObserver.init(); +            mRoleObserver = roleObserver;              LauncherApps launcherApps =                      (LauncherApps) getContext().getSystemService(Context.LAUNCHER_APPS_SERVICE);              mShortcutHelper = new ShortcutHelper(launcherApps, mShortcutListener, getLocalService( @@ -10677,26 +10695,40 @@ public class NotificationManagerService extends SystemService {          // Role name : user id : list of approved packages          private ArrayMap<String, ArrayMap<Integer, ArraySet<String>>> mNonBlockableDefaultApps; +        /** +         * Writes should be pretty rare (only when default browser changes) and reads are done +         * during activity start code-path, so we're optimizing for reads. This means this set is +         * immutable once written and we'll recreate the set every time there is a role change and +         * then assign that new set to the volatile below, so reads can be done without needing to +         * hold a lock. Every write is done on the main-thread, so write atomicity is guaranteed. +         * +         * Didn't use unmodifiable set to enforce immutability to avoid iterating via iterators. +         */ +        private volatile ArraySet<Integer> mTrampolineExemptUids = new ArraySet<>(); +          private final RoleManager mRm;          private final IPackageManager mPm;          private final Executor mExecutor; +        private final Looper mMainLooper; -        RoleObserver(@NonNull RoleManager roleManager, -                @NonNull IPackageManager pkgMgr, -                @NonNull @CallbackExecutor Executor executor) { +        RoleObserver(Context context, @NonNull RoleManager roleManager, +                @NonNull IPackageManager pkgMgr, @NonNull Looper mainLooper) {              mRm = roleManager;              mPm = pkgMgr; -            mExecutor = executor; +            mExecutor = context.getMainExecutor(); +            mMainLooper = mainLooper;          } +        /** Should be called from the main-thread. */ +        @MainThread          public void init() { -            List<UserInfo> users = mUm.getUsers(); +            List<UserHandle> users = mUm.getUserHandles(/* excludeDying */ true);              mNonBlockableDefaultApps = new ArrayMap<>();              for (int i = 0; i < NON_BLOCKABLE_DEFAULT_ROLES.length; i++) {                  final ArrayMap<Integer, ArraySet<String>> userToApprovedList = new ArrayMap<>();                  mNonBlockableDefaultApps.put(NON_BLOCKABLE_DEFAULT_ROLES[i], userToApprovedList);                  for (int j = 0; j < users.size(); j++) { -                    Integer userId = users.get(j).getUserHandle().getIdentifier(); +                    Integer userId = users.get(j).getIdentifier();                      ArraySet<String> approvedForUserId = new ArraySet<>(mRm.getRoleHoldersAsUser(                              NON_BLOCKABLE_DEFAULT_ROLES[i], UserHandle.of(userId)));                      ArraySet<Pair<String, Integer>> approvedAppUids = new ArraySet<>(); @@ -10707,7 +10739,7 @@ public class NotificationManagerService extends SystemService {                      mPreferencesHelper.updateDefaultApps(userId, null, approvedAppUids);                  }              } - +            updateTrampolineExemptUidsForUsers(users.toArray(new UserHandle[0]));              mRm.addOnRoleHoldersChangedListenerAsUser(mExecutor, this, UserHandle.ALL);          } @@ -10716,6 +10748,11 @@ public class NotificationManagerService extends SystemService {              return mNonBlockableDefaultApps.get(role).get(userId).contains(pkg);          } +        @VisibleForTesting +        public boolean isUidExemptFromTrampolineRestrictions(int uid) { +            return mTrampolineExemptUids.contains(uid); +        } +          /**           * Convert the assistant-role holder into settings. The rest of the system uses the           * settings. @@ -10725,6 +10762,12 @@ public class NotificationManagerService extends SystemService {           */          @Override          public void onRoleHoldersChanged(@NonNull String roleName, @NonNull UserHandle user) { +            onRoleHoldersChangedForNonBlockableDefaultApps(roleName, user); +            onRoleHoldersChangedForTrampolines(roleName, user); +        } + +        private void onRoleHoldersChangedForNonBlockableDefaultApps(@NonNull String roleName, +                @NonNull UserHandle user) {              // we only care about a couple of the roles they'll tell us about              boolean relevantChange = false;              for (int i = 0; i < NON_BLOCKABLE_DEFAULT_ROLES.length; i++) { @@ -10772,6 +10815,41 @@ public class NotificationManagerService extends SystemService {              // write of the notification policy xml for this change          } +        private void onRoleHoldersChangedForTrampolines(@NonNull String roleName, +                @NonNull UserHandle user) { +            if (!RoleManager.ROLE_BROWSER.equals(roleName)) { +                return; +            } +            updateTrampolineExemptUidsForUsers(user); +        } + +        private void updateTrampolineExemptUidsForUsers(UserHandle... users) { +            Preconditions.checkState(mMainLooper.isCurrentThread()); +            ArraySet<Integer> oldUids = mTrampolineExemptUids; +            ArraySet<Integer> newUids = new ArraySet<>(); +            // Add the uids from previous set for the users that we won't update. +            for (int i = 0, n = oldUids.size(); i < n; i++) { +                int uid = oldUids.valueAt(i); +                UserHandle user = UserHandle.of(UserHandle.getUserId(uid)); +                if (!ArrayUtils.contains(users, user)) { +                    newUids.add(uid); +                } +            } +            // Now lookup the new uids for the users that we want to update. +            for (int i = 0, n = users.length; i < n; i++) { +                UserHandle user = users[i]; +                for (String pkg : mRm.getRoleHoldersAsUser(RoleManager.ROLE_BROWSER, user)) { +                    int uid = getUidForPackage(pkg, user.getIdentifier()); +                    if (uid != -1) { +                        newUids.add(uid); +                    } else { +                        Slog.e(TAG, "Bad uid (-1) for browser package " + pkg); +                    } +                } +            } +            mTrampolineExemptUids = newUids; +        } +          private int getUidForPackage(String pkg, int userId) {              try {                  return mPm.getPackageUid(pkg, MATCH_ALL, userId); @@ -10936,7 +11014,7 @@ public class NotificationManagerService extends SystemService {              }              String logcatMessage =                      "Indirect notification activity start (trampoline) from " + packageName; -            if (CompatChanges.isChangeEnabled(NOTIFICATION_TRAMPOLINE_BLOCK, uid)) { +            if (blockTrampoline(uid)) {                  // Post toast() call to mHandler to offload PM lookup from the activity start path                  mHandler.post(() -> toast(packageName, uid));                  Slog.e(TAG, logcatMessage + " blocked"); @@ -10947,6 +11025,13 @@ public class NotificationManagerService extends SystemService {              }          } +        private boolean blockTrampoline(int uid) { +            if (mRoleObserver != null && mRoleObserver.isUidExemptFromTrampolineRestrictions(uid)) { +                return false; +            } +            return CompatChanges.isChangeEnabled(NOTIFICATION_TRAMPOLINE_BLOCK, uid); +        } +          @Override          public boolean canCloseSystemDialogs(Collection<IBinder> tokens, int uid) {              // If the start is allowed via notification, we allow the app to close system dialogs diff --git a/services/core/java/com/android/server/pm/ApkChecksums.java b/services/core/java/com/android/server/pm/ApkChecksums.java index afce23fe7647..28511070fc8e 100644 --- a/services/core/java/com/android/server/pm/ApkChecksums.java +++ b/services/core/java/com/android/server/pm/ApkChecksums.java @@ -303,8 +303,8 @@ public class ApkChecksums {       * @param onChecksumsReadyListener to receive the resulting checksums       */      public static void getChecksums(List<Pair<String, File>> filesToChecksum, -            @Checksum.Type int optional, -            @Checksum.Type int required, +            @Checksum.TypeMask int optional, +            @Checksum.TypeMask int required,              @Nullable String installerPackageName,              @Nullable Certificate[] trustedInstallers,              @NonNull IOnChecksumsReadyListener onChecksumsReadyListener, @@ -331,7 +331,7 @@ public class ApkChecksums {      private static void processRequiredChecksums(List<Pair<String, File>> filesToChecksum,              List<Map<Integer, ApkChecksum>> result, -            @Checksum.Type int required, +            @Checksum.TypeMask int required,              @NonNull IOnChecksumsReadyListener onChecksumsReadyListener,              @NonNull Injector injector,              long startTime) { @@ -382,7 +382,7 @@ public class ApkChecksums {       * @param checksums             resulting checksums       */      private static void getAvailableApkChecksums(String split, File file, -            @Checksum.Type int types, +            @Checksum.TypeMask int types,              @Nullable String installerPackageName,              @Nullable Certificate[] trustedInstallers,              Map<Integer, ApkChecksum> checksums, @@ -415,7 +415,7 @@ public class ApkChecksums {      }      private static void getInstallerChecksums(String split, File file, -            @Checksum.Type int types, +            @Checksum.TypeMask int types,              @Nullable String installerPackageName,              @Nullable Certificate[] trustedInstallers,              Map<Integer, ApkChecksum> checksums, @@ -523,7 +523,7 @@ public class ApkChecksums {       * Whether the file is available for checksumming or we need to wait.       */      private static boolean needToWait(File file, -            @Checksum.Type int types, +            @Checksum.TypeMask int types,              Map<Integer, ApkChecksum> checksums,              @NonNull Injector injector) throws IOException {          if (!isRequired(TYPE_WHOLE_MERKLE_ROOT_4K_SHA256, types, checksums) @@ -564,7 +564,7 @@ public class ApkChecksums {       * @param checksums resulting checksums       */      private static void getRequiredApkChecksums(String split, File file, -            @Checksum.Type int types, +            @Checksum.TypeMask int types,              Map<Integer, ApkChecksum> checksums) {          final String filePath = file.getAbsolutePath(); @@ -596,7 +596,7 @@ public class ApkChecksums {      }      private static boolean isRequired(@Checksum.Type int type, -            @Checksum.Type int types, Map<Integer, ApkChecksum> checksums) { +            @Checksum.TypeMask int types, Map<Integer, ApkChecksum> checksums) {          if ((types & type) == 0) {              return false;          } diff --git a/services/core/java/com/android/server/pm/ComponentResolver.java b/services/core/java/com/android/server/pm/ComponentResolver.java index 1d556fec31ea..dde9f822ac76 100644 --- a/services/core/java/com/android/server/pm/ComponentResolver.java +++ b/services/core/java/com/android/server/pm/ComponentResolver.java @@ -59,6 +59,9 @@ import com.android.server.IntentResolver;  import com.android.server.pm.parsing.PackageInfoUtils;  import com.android.server.pm.parsing.PackageInfoUtils.CachedApplicationInfoGenerator;  import com.android.server.pm.parsing.pkg.AndroidPackage; +import com.android.server.utils.Snappable; +import com.android.server.utils.SnapshotCache; +import com.android.server.utils.WatchableImpl;  import java.io.PrintWriter;  import java.util.ArrayList; @@ -72,12 +75,19 @@ import java.util.Set;  import java.util.function.Function;  /** Resolves all Android component types [activities, services, providers and receivers]. */ -public class ComponentResolver { +public class ComponentResolver +        extends WatchableImpl +        implements Snappable {      private static final boolean DEBUG = false;      private static final String TAG = "PackageManager";      private static final boolean DEBUG_FILTERS = false;      private static final boolean DEBUG_SHOW_INFO = false; +    // Convenience function to report that this object has changed. +    private void onChanged() { +        dispatchChange(this); +    } +      /**       * The set of all protected actions [i.e. those actions for which a high priority       * intent filter is disallowed]. @@ -158,27 +168,27 @@ public class ComponentResolver {       * would be able to hold its lock while checking the package setting state.</li>       * </ol>       */ -    private final Object mLock; +    private final PackageManagerTracedLock mLock;      /** All available activities, for your resolving pleasure. */      @GuardedBy("mLock") -    private final ActivityIntentResolver mActivities = new ActivityIntentResolver(); +    private final ActivityIntentResolver mActivities;      /** All available providers, for your resolving pleasure. */      @GuardedBy("mLock") -    private final ProviderIntentResolver mProviders = new ProviderIntentResolver(); +    private final ProviderIntentResolver mProviders;      /** All available receivers, for your resolving pleasure. */      @GuardedBy("mLock") -    private final ActivityIntentResolver mReceivers = new ReceiverIntentResolver(); +    private final ReceiverIntentResolver mReceivers;      /** All available services, for your resolving pleasure. */      @GuardedBy("mLock") -    private final ServiceIntentResolver mServices = new ServiceIntentResolver(); +    private final ServiceIntentResolver mServices;      /** Mapping from provider authority [first directory in content URI codePath) to provider. */      @GuardedBy("mLock") -    private final ArrayMap<String, ParsedProvider> mProvidersByAuthority = new ArrayMap<>(); +    private final ArrayMap<String, ParsedProvider> mProvidersByAuthority;      /** Whether or not processing protected filters should be deferred. */      private boolean mDeferProtectedFilters = true; @@ -200,12 +210,57 @@ public class ComponentResolver {      ComponentResolver(UserManagerService userManager,              PackageManagerInternal packageManagerInternal, -            Object lock) { +            PackageManagerTracedLock lock) {          sPackageManagerInternal = packageManagerInternal;          sUserManager = userManager;          mLock = lock; + +        mActivities = new ActivityIntentResolver(); +        mProviders = new ProviderIntentResolver(); +        mReceivers = new ReceiverIntentResolver(); +        mServices = new ServiceIntentResolver(); +        mProvidersByAuthority = new ArrayMap<>(); +        mDeferProtectedFilters = true; + +        mSnapshot = new SnapshotCache<ComponentResolver>(this, this) { +                @Override +                public ComponentResolver createSnapshot() { +                    return new ComponentResolver(mSource); +                }}; +    } + +    // Copy constructor used in creating snapshots. +    private ComponentResolver(ComponentResolver orig) { +        // Do not set the static variables that are set in the default constructor.   Do +        // create a new object for the lock.  The snapshot is read-only, so a lock is not +        // strictly required.  However, the current code is simpler if the lock exists, +        // but does not contend with any outside class. +        // TODO: make the snapshot lock-free +        mLock = new PackageManagerTracedLock(); + +        mActivities = new ActivityIntentResolver(orig.mActivities); +        mProviders = new ProviderIntentResolver(orig.mProviders); +        mReceivers = new ReceiverIntentResolver(orig.mReceivers); +        mServices = new ServiceIntentResolver(orig.mServices); +        mProvidersByAuthority = new ArrayMap<>(orig.mProvidersByAuthority); +        mDeferProtectedFilters = orig.mDeferProtectedFilters; +        mProtectedFilters = (mProtectedFilters == null) +                            ? null +                            : new ArrayList<>(orig.mProtectedFilters); + +        mSnapshot = null;      } +    final SnapshotCache<ComponentResolver> mSnapshot; + +    /** +     * Create a snapshot. +     */ +    public ComponentResolver snapshot() { +        return mSnapshot.snapshot(); +    } + +      /** Returns the given activity */      @Nullable      @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) @@ -474,6 +529,7 @@ public class ComponentResolver {              addReceiversLocked(pkg, chatty);              addProvidersLocked(pkg, chatty);              addServicesLocked(pkg, chatty); +            onChanged();          }          // expect single setupwizard package          final String setupWizardPackage = ArrayUtils.firstOrNull( @@ -489,6 +545,7 @@ public class ComponentResolver {              final List<ParsedActivity> systemActivities =                      disabledPkg != null ? disabledPkg.getActivities() : null;              adjustPriority(systemActivities, pair.first, pair.second, setupWizardPackage); +            onChanged();          }      } @@ -496,6 +553,7 @@ public class ComponentResolver {      void removeAllComponents(AndroidPackage pkg, boolean chatty) {          synchronized (mLock) {              removeAllComponentsLocked(pkg, chatty); +            onChanged();          }      } @@ -504,51 +562,54 @@ public class ComponentResolver {       * all of the filters defined on the /system partition and know the special components.       */      void fixProtectedFilterPriorities() { -        if (!mDeferProtectedFilters) { -            return; -        } -        mDeferProtectedFilters = false; +        synchronized (mLock) { +            if (!mDeferProtectedFilters) { +                return; +            } +            mDeferProtectedFilters = false; -        if (mProtectedFilters == null || mProtectedFilters.size() == 0) { -            return; -        } -        final List<Pair<ParsedMainComponent, ParsedIntentInfo>> protectedFilters = -                mProtectedFilters; -        mProtectedFilters = null; +            if (mProtectedFilters == null || mProtectedFilters.size() == 0) { +                return; +            } +            final List<Pair<ParsedMainComponent, ParsedIntentInfo>> protectedFilters = +                    mProtectedFilters; +            mProtectedFilters = null; -        // expect single setupwizard package -        final String setupWizardPackage = ArrayUtils.firstOrNull( +            // expect single setupwizard package +            final String setupWizardPackage = ArrayUtils.firstOrNull(                  sPackageManagerInternal.getKnownPackageNames( -                        PACKAGE_SETUP_WIZARD, UserHandle.USER_SYSTEM)); - -        if (DEBUG_FILTERS && setupWizardPackage == null) { -            Slog.i(TAG, "No setup wizard;" -                    + " All protected intents capped to priority 0"); -        } -        for (int i = protectedFilters.size() - 1; i >= 0; --i) { -            final Pair<ParsedMainComponent, ParsedIntentInfo> pair = protectedFilters.get(i); -            ParsedMainComponent component = pair.first; -            ParsedIntentInfo filter = pair.second; -            String packageName = component.getPackageName(); -            String className = component.getClassName(); -            if (packageName.equals(setupWizardPackage)) { +                    PACKAGE_SETUP_WIZARD, UserHandle.USER_SYSTEM)); + +            if (DEBUG_FILTERS && setupWizardPackage == null) { +                Slog.i(TAG, "No setup wizard;" +                        + " All protected intents capped to priority 0"); +            } +            for (int i = protectedFilters.size() - 1; i >= 0; --i) { +                final Pair<ParsedMainComponent, ParsedIntentInfo> pair = protectedFilters.get(i); +                ParsedMainComponent component = pair.first; +                ParsedIntentInfo filter = pair.second; +                String packageName = component.getPackageName(); +                String className = component.getClassName(); +                if (packageName.equals(setupWizardPackage)) { +                    if (DEBUG_FILTERS) { +                        Slog.i(TAG, "Found setup wizard;" +                                + " allow priority " + filter.getPriority() + ";" +                                + " package: " + packageName +                                + " activity: " + className +                                + " priority: " + filter.getPriority()); +                    } +                    // skip setup wizard; allow it to keep the high priority filter +                    continue; +                }                  if (DEBUG_FILTERS) { -                    Slog.i(TAG, "Found setup wizard;" -                            + " allow priority " + filter.getPriority() + ";" +                    Slog.i(TAG, "Protected action; cap priority to 0;"                              + " package: " + packageName                              + " activity: " + className -                            + " priority: " + filter.getPriority()); +                            + " origPrio: " + filter.getPriority());                  } -                // skip setup wizard; allow it to keep the high priority filter -                continue; -            } -            if (DEBUG_FILTERS) { -                Slog.i(TAG, "Protected action; cap priority to 0;" -                        + " package: " + packageName -                        + " activity: " + className -                        + " origPrio: " + filter.getPriority()); +                filter.setPriority(0);              } -            filter.setPriority(0); +            onChanged();          }      } @@ -1181,9 +1242,20 @@ public class ComponentResolver {      private abstract static class MimeGroupsAwareIntentResolver<F extends Pair<?              extends ParsedComponent, ParsedIntentInfo>, R>              extends IntentResolver<F, R> { -        private ArrayMap<String, F[]> mMimeGroupToFilter = new ArrayMap<>(); +        private final ArrayMap<String, F[]> mMimeGroupToFilter = new ArrayMap<>();          private boolean mIsUpdatingMimeGroup = false; +        // Default constructor +        MimeGroupsAwareIntentResolver() { +        } + +        // Copy constructor used in creating snapshots +        MimeGroupsAwareIntentResolver(MimeGroupsAwareIntentResolver<F, R> orig) { +            copyFrom(orig); +            copyInto(mMimeGroupToFilter, orig.mMimeGroupToFilter); +            mIsUpdatingMimeGroup = orig.mIsUpdatingMimeGroup; +        } +          @Override          public void addFilter(F f) {              IntentFilter intentFilter = getIntentFilter(f); @@ -1282,6 +1354,17 @@ public class ComponentResolver {      private static class ActivityIntentResolver              extends MimeGroupsAwareIntentResolver<Pair<ParsedActivity, ParsedIntentInfo>, ResolveInfo> { +        // Default constructor +        ActivityIntentResolver() { +        } + +        // Copy constructor used in creating snapshots +        ActivityIntentResolver(ActivityIntentResolver orig) { +            super(orig); +            mActivities.putAll(orig.mActivities); +            mFlags = orig.mFlags; +        } +          @Override          public List<ResolveInfo> queryIntent(Intent intent, String resolvedType,                  boolean defaultOnly, int userId) { @@ -1330,7 +1413,7 @@ public class ComponentResolver {              return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId);          } -        private void addActivity(ParsedActivity a, String type, +        protected void addActivity(ParsedActivity a, String type,                  List<Pair<ParsedActivity, ParsedIntentInfo>> newIntents) {              mActivities.put(a.getComponentName(), a);              if (DEBUG_SHOW_INFO) { @@ -1354,7 +1437,7 @@ public class ComponentResolver {              }          } -        private void removeActivity(ParsedActivity a, String type) { +        protected void removeActivity(ParsedActivity a, String type) {              mActivities.remove(a.getComponentName());              if (DEBUG_SHOW_INFO) {                  Log.v(TAG, "  " + type + ":"); @@ -1567,8 +1650,11 @@ public class ComponentResolver {              return pkg.getActivities();          } -        // Keys are String (activity class name), values are Activity. -        private final ArrayMap<ComponentName, ParsedActivity> mActivities = +        // Keys are String (activity class name), values are Activity.  This attribute is +        // protected because it is accessed directly from ComponentResolver.  That works +        // even if the attribute is private, but fails for subclasses of +        // ActivityIntentResolver. +        protected final ArrayMap<ComponentName, ParsedActivity> mActivities =                  new ArrayMap<>();          private int mFlags;      } @@ -1576,6 +1662,15 @@ public class ComponentResolver {      // Both receivers and activities share a class, but point to different get methods      private static final class ReceiverIntentResolver extends ActivityIntentResolver { +        // Default constructor +        ReceiverIntentResolver() { +        } + +        // Copy constructor used in creating snapshots +        ReceiverIntentResolver(ReceiverIntentResolver orig) { +            super(orig); +        } +          @Override          protected List<ParsedActivity> getResolveList(AndroidPackage pkg) {              return pkg.getReceivers(); @@ -1584,6 +1679,17 @@ public class ComponentResolver {      private static final class ProviderIntentResolver              extends MimeGroupsAwareIntentResolver<Pair<ParsedProvider, ParsedIntentInfo>, ResolveInfo> { +        // Default constructor +        ProviderIntentResolver() { +        } + +        // Copy constructor used in creating snapshots +        ProviderIntentResolver(ProviderIntentResolver orig) { +            super(orig); +            mProviders.putAll(orig.mProviders); +            mFlags = orig.mFlags; +        } +          @Override          public List<ResolveInfo> queryIntent(Intent intent, String resolvedType,                  boolean defaultOnly, int userId) { @@ -1829,6 +1935,17 @@ public class ComponentResolver {      private static final class ServiceIntentResolver              extends MimeGroupsAwareIntentResolver<Pair<ParsedService, ParsedIntentInfo>, ResolveInfo> { +        // Default constructor +        ServiceIntentResolver() { +        } + +        // Copy constructor used in creating snapshots +        ServiceIntentResolver(ServiceIntentResolver orig) { +            copyFrom(orig); +            mServices.putAll(orig.mServices); +            mFlags = orig.mFlags; +        } +          @Override          public List<ResolveInfo> queryIntent(Intent intent, String resolvedType,                  boolean defaultOnly, int userId) { @@ -2213,11 +2330,16 @@ public class ComponentResolver {       * @return true if any intent filters were changed due to this update       */      boolean updateMimeGroup(String packageName, String group) { -        boolean hasChanges = mActivities.updateMimeGroup(packageName, group); -        hasChanges |= mProviders.updateMimeGroup(packageName, group); -        hasChanges |= mReceivers.updateMimeGroup(packageName, group); -        hasChanges |= mServices.updateMimeGroup(packageName, group); - +        boolean hasChanges = false; +        synchronized (mLock) { +            hasChanges |= mActivities.updateMimeGroup(packageName, group); +            hasChanges |= mProviders.updateMimeGroup(packageName, group); +            hasChanges |= mReceivers.updateMimeGroup(packageName, group); +            hasChanges |= mServices.updateMimeGroup(packageName, group); +            if (hasChanges) { +                onChanged(); +            } +        }          return hasChanges;      }  } diff --git a/services/core/java/com/android/server/pm/CrossProfileIntentFilter.java b/services/core/java/com/android/server/pm/CrossProfileIntentFilter.java index 7c19d90e4ede..f5910fa3143c 100644 --- a/services/core/java/com/android/server/pm/CrossProfileIntentFilter.java +++ b/services/core/java/com/android/server/pm/CrossProfileIntentFilter.java @@ -24,6 +24,7 @@ import android.util.TypedXmlPullParser;  import android.util.TypedXmlSerializer;  import com.android.internal.util.XmlUtils; +import com.android.server.utils.SnapshotCache;  import org.xmlpull.v1.XmlPullParser;  import org.xmlpull.v1.XmlPullParserException; @@ -35,7 +36,7 @@ import java.io.IOException;   * If an {@link Intent} matches the {@link CrossProfileIntentFilter}, then activities in the user   * {@link #mTargetUserId} can access it.   */ -class CrossProfileIntentFilter extends IntentFilter { +class CrossProfileIntentFilter extends WatchedIntentFilter {      private static final String ATTR_TARGET_USER_ID = "targetUserId";      private static final String ATTR_FLAGS = "flags";      private static final String ATTR_OWNER_PACKAGE = "ownerPackage"; @@ -48,12 +49,41 @@ class CrossProfileIntentFilter extends IntentFilter {      final String mOwnerPackage; // packageName of the app.      final int mFlags; +    // The cache for snapshots, so they are not rebuilt if the base object has not +    // changed. +    final SnapshotCache<CrossProfileIntentFilter> mSnapshot; + +    private SnapshotCache makeCache() { +        return new SnapshotCache<CrossProfileIntentFilter>(this, this) { +            @Override +            public CrossProfileIntentFilter createSnapshot() { +                CrossProfileIntentFilter s = new CrossProfileIntentFilter(mSource); +                s.seal(); +                return s; +            }}; +    } +      CrossProfileIntentFilter(IntentFilter filter, String ownerPackage, int targetUserId,              int flags) {          super(filter);          mTargetUserId = targetUserId;          mOwnerPackage = ownerPackage;          mFlags = flags; +        mSnapshot = makeCache(); +    } + +    CrossProfileIntentFilter(WatchedIntentFilter filter, String ownerPackage, int targetUserId, +            int flags) { +        this(filter.mFilter, ownerPackage, targetUserId, flags); +    } + +    // Copy constructor used only to create a snapshot. +    private CrossProfileIntentFilter(CrossProfileIntentFilter f) { +        super(f); +        mTargetUserId = f.mTargetUserId; +        mOwnerPackage = f.mOwnerPackage; +        mFlags = f.mFlags; +        mSnapshot = new SnapshotCache.Sealed();      }      public int getTargetUserId() { @@ -72,6 +102,7 @@ class CrossProfileIntentFilter extends IntentFilter {          mTargetUserId = parser.getAttributeInt(null, ATTR_TARGET_USER_ID, UserHandle.USER_NULL);          mOwnerPackage = getStringFromXml(parser, ATTR_OWNER_PACKAGE, "");          mFlags = parser.getAttributeInt(null, ATTR_FLAGS, 0); +        mSnapshot = makeCache();          int outerDepth = parser.getDepth();          String tagName = parser.getName(); @@ -94,7 +125,7 @@ class CrossProfileIntentFilter extends IntentFilter {              }          }          if (tagName.equals(ATTR_FILTER)) { -            readFromXml(parser); +            mFilter.readFromXml(parser);          } else {              String msg = "Missing element under " + TAG + ": " + ATTR_FILTER +                      " at " + parser.getPositionDescription(); @@ -103,7 +134,8 @@ class CrossProfileIntentFilter extends IntentFilter {          }      } -    String getStringFromXml(TypedXmlPullParser parser, String attribute, String defaultValue) { +    private String getStringFromXml(TypedXmlPullParser parser, String attribute, +            String defaultValue) {          String value = parser.getAttributeValue(null, attribute);          if (value == null) {              String msg = "Missing element under " + TAG +": " + attribute + " at " + @@ -120,7 +152,7 @@ class CrossProfileIntentFilter extends IntentFilter {          serializer.attributeInt(null, ATTR_FLAGS, mFlags);          serializer.attribute(null, ATTR_OWNER_PACKAGE, mOwnerPackage);          serializer.startTag(null, ATTR_FILTER); -            super.writeToXml(serializer); +        mFilter.writeToXml(serializer);          serializer.endTag(null, ATTR_FILTER);      } @@ -135,4 +167,8 @@ class CrossProfileIntentFilter extends IntentFilter {                  && mOwnerPackage.equals(other.mOwnerPackage)                  && mFlags == other.mFlags;      } + +    public CrossProfileIntentFilter snapshot() { +        return mSnapshot.snapshot(); +    }  } diff --git a/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java b/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java index 791a1057d112..792753860358 100644 --- a/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java +++ b/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java @@ -21,6 +21,7 @@ import android.content.IntentFilter;  import com.android.server.WatchedIntentResolver;  import com.android.server.utils.Snappable; +import com.android.server.utils.SnapshotCache;  import java.util.List; @@ -47,7 +48,34 @@ class CrossProfileIntentResolver      @Override      protected IntentFilter getIntentFilter(@NonNull CrossProfileIntentFilter input) { -        return input; +        return input.getIntentFilter(); +    } + +    CrossProfileIntentResolver() { +        mSnapshot = makeCache(); +    } + +    // Take the snapshot of F +    protected CrossProfileIntentFilter snapshot(CrossProfileIntentFilter f) { +        return (f == null) ? null : f.snapshot(); +    } + +    // Copy constructor used only to create a snapshot. +    private CrossProfileIntentResolver(CrossProfileIntentResolver f) { +        copyFrom(f); +        mSnapshot = new SnapshotCache.Sealed(); +    } + +    // The cache for snapshots, so they are not rebuilt if the base object has not +    // changed. +    final SnapshotCache<CrossProfileIntentResolver> mSnapshot; + +    private SnapshotCache makeCache() { +        return new SnapshotCache<CrossProfileIntentResolver>(this, this) { +            @Override +            public CrossProfileIntentResolver createSnapshot() { +                return new CrossProfileIntentResolver(mSource); +            }};      }      /** @@ -56,8 +84,6 @@ class CrossProfileIntentResolver       * @return A snapshot of the current object.       */      public CrossProfileIntentResolver snapshot() { -        CrossProfileIntentResolver result = new CrossProfileIntentResolver(); -        result.copyFrom(this); -        return result; +        return mSnapshot.snapshot();      }  } diff --git a/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFilter.java b/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFilter.java index a32e107d9e73..c58128a3c9b1 100644 --- a/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFilter.java +++ b/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFilter.java @@ -43,7 +43,7 @@ final class DefaultCrossProfileIntentFilter {      }      /** The intent filter that's used */ -    public final IntentFilter filter; +    public final WatchedIntentFilter filter;      /**       * The flags related to the forwarding, e.g. @@ -66,7 +66,7 @@ final class DefaultCrossProfileIntentFilter {       */      public final boolean letsPersonalDataIntoProfile; -    private DefaultCrossProfileIntentFilter(IntentFilter filter, int flags, +    private DefaultCrossProfileIntentFilter(WatchedIntentFilter filter, int flags,              @Direction int direction, boolean letsPersonalDataIntoProfile) {          this.filter = requireNonNull(filter);          this.flags = flags; @@ -75,7 +75,7 @@ final class DefaultCrossProfileIntentFilter {      }      static final class Builder { -        private IntentFilter mFilter = new IntentFilter(); +        private WatchedIntentFilter mFilter = new WatchedIntentFilter();          private int mFlags;          private @Direction int mDirection;          private boolean mLetsPersonalDataIntoProfile; diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 656f3474e797..b6f5e999be27 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -20,6 +20,7 @@ import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;  import static org.xmlpull.v1.XmlPullParser.START_TAG;  import android.Manifest; +import android.annotation.NonNull;  import android.app.ActivityManager;  import android.app.AppGlobals;  import android.app.AppOpsManager; @@ -88,6 +89,7 @@ import com.android.server.SystemConfig;  import com.android.server.SystemService;  import com.android.server.SystemServiceManager;  import com.android.server.pm.parsing.PackageParser2; +import com.android.server.pm.utils.RequestThrottle;  import libcore.io.IoUtils; @@ -220,6 +222,14 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements          }      } +    @NonNull +    private final RequestThrottle mSettingsWriteRequest = new RequestThrottle(IoThread.getHandler(), +            () -> { +                synchronized (mSessions) { +                    return writeSessionsLocked(); +                } +            }); +      public PackageInstallerService(Context context, PackageManagerService pm,              Supplier<PackageParser2> apexParserSupplier) {          mContext = context; @@ -275,7 +285,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements              // Invalid sessions might have been marked while parsing. Re-write the database with              // the updated information. -            writeSessionsLocked(); +            mSettingsWriteRequest.runNow();          }      } @@ -464,7 +474,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements      }      @GuardedBy("mSessions") -    private void writeSessionsLocked() { +    private boolean writeSessionsLocked() {          if (LOGD) Slog.v(TAG, "writeSessionsLocked()");          FileOutputStream fos = null; @@ -483,28 +493,20 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements              out.endDocument();              mSessionsFile.finishWrite(fos); +            return true;          } catch (IOException e) {              if (fos != null) {                  mSessionsFile.failWrite(fos);              }          } + +        return false;      }      private File buildAppIconFile(int sessionId) {          return new File(mSessionsDir, "app_icon." + sessionId + ".png");      } -    private void writeSessionsAsync() { -        IoThread.getHandler().post(new Runnable() { -            @Override -            public void run() { -                synchronized (mSessions) { -                    writeSessionsLocked(); -                } -            } -        }); -    } -      @Override      public int createSession(SessionParams params, String installerPackageName,              String callingAttributionTag, int userId) { @@ -764,7 +766,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements          mCallbacks.notifySessionCreated(session.sessionId, session.userId); -        writeSessionsAsync(); +        mSettingsWriteRequest.schedule();          return sessionId;      } @@ -1374,7 +1376,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements      class InternalCallback {          public void onSessionBadgingChanged(PackageInstallerSession session) {              mCallbacks.notifySessionBadgingChanged(session.sessionId, session.userId); -            writeSessionsAsync(); +            mSettingsWriteRequest.schedule();          }          public void onSessionActiveChanged(PackageInstallerSession session, boolean active) { @@ -1389,7 +1391,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements          public void onStagedSessionChanged(PackageInstallerSession session) {              session.markUpdated(); -            writeSessionsAsync(); +            mSettingsWriteRequest.schedule();              if (mOkToSendBroadcasts && !session.isDestroyed()) {                  // we don't scrub the data here as this is sent only to the installer several                  // privileged system packages @@ -1419,7 +1421,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements                              appIconFile.delete();                          } -                        writeSessionsLocked(); +                        mSettingsWriteRequest.runNow();                      }                  }              }); @@ -1428,16 +1430,14 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements          public void onSessionPrepared(PackageInstallerSession session) {              // We prepared the destination to write into; we want to persist              // this, but it's not critical enough to block for. -            writeSessionsAsync(); +            mSettingsWriteRequest.schedule();          }          public void onSessionSealedBlocking(PackageInstallerSession session) {              // It's very important that we block until we've recorded the              // session as being sealed, since we never want to allow mutation              // after sealing. -            synchronized (mSessions) { -                writeSessionsLocked(); -            } +            mSettingsWriteRequest.runNow();          }      }  } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index dad37f40babb..db2b166aac63 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -134,6 +134,7 @@ import static com.android.server.pm.PackageManagerServiceUtils.getLastModifiedTi  import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;  import static com.android.server.pm.PackageManagerServiceUtils.makeDirRecursive;  import static com.android.server.pm.PackageManagerServiceUtils.verifySignatures; +import static com.android.server.pm.parsing.PackageInfoUtils.checkUseInstalledOrHidden;  import android.Manifest;  import android.annotation.AppIdInt; @@ -1481,7 +1482,9 @@ public class PackageManagerService extends IPackageManager.Stub      // Internal interface for permission manager      private final PermissionManagerServiceInternal mPermissionManager; +    @Watched      private final ComponentResolver mComponentResolver; +      // List of packages names to keep cached, even if they are uninstalled for all users      private List<String> mKeepUninstalledPackages; @@ -1825,6 +1828,7 @@ public class PackageManagerService extends IPackageManager.Stub          public final ApplicationInfo androidApplication;          public final String appPredictionServicePackage;          public final AppsFilter appsFilter; +        public final ComponentResolver componentResolver;          public final PackageManagerService service;          Snapshot(int type) { @@ -1850,6 +1854,7 @@ public class PackageManagerService extends IPackageManager.Stub                          : new ApplicationInfo(mAndroidApplication);                  appPredictionServicePackage = mAppPredictionServicePackage;                  appsFilter = mAppsFilter.snapshot(); +                componentResolver = mComponentResolver.snapshot();              } else if (type == Snapshot.LIVE) {                  settings = mSettings;                  isolatedOwners = mIsolatedOwners; @@ -1866,6 +1871,7 @@ public class PackageManagerService extends IPackageManager.Stub                  androidApplication = mAndroidApplication;                  appPredictionServicePackage = mAppPredictionServicePackage;                  appsFilter = mAppsFilter; +                componentResolver = mComponentResolver;              } else {                  throw new IllegalArgumentException();              } @@ -1955,8 +1961,8 @@ public class PackageManagerService extends IPackageManager.Stub                  int callingUid);          ResolveInfo createForwardingResolveInfo(CrossProfileIntentFilter filter, Intent intent,                  String resolvedType, int flags, int sourceUserId); -        ResolveInfo createForwardingResolveInfoUnchecked(IntentFilter filter, int sourceUserId, -                int targetUserId); +        ResolveInfo createForwardingResolveInfoUnchecked(WatchedIntentFilter filter, +                int sourceUserId, int targetUserId);          ResolveInfo queryCrossProfileIntents(List<CrossProfileIntentFilter> matchingFilters,                  Intent intent, String resolvedType, int flags, int sourceUserId,                  boolean matchInCurrentProfile); @@ -2113,6 +2119,7 @@ public class PackageManagerService extends IPackageManager.Stub              mInstantAppRegistry = args.instantAppRegistry;              mLocalAndroidApplication = args.androidApplication;              mAppsFilter = args.appsFilter; +            mComponentResolver = args.componentResolver;              mAppPredictionServicePackage = args.appPredictionServicePackage; @@ -2123,7 +2130,6 @@ public class PackageManagerService extends IPackageManager.Stub              mContext = args.service.mContext;              mInjector = args.service.mInjector;              mApexManager = args.service.mApexManager; -            mComponentResolver = args.service.mComponentResolver;              mInstantAppResolverConnection = args.service.mInstantAppResolverConnection;              mDefaultAppProvider = args.service.mDefaultAppProvider;              mDomainVerificationManager = args.service.mDomainVerificationManager; @@ -2510,8 +2516,8 @@ public class PackageManagerService extends IPackageManager.Stub              if (DEBUG_PACKAGE_INFO) Log.v(TAG, "getActivityInfo " + component + ": " + a);              AndroidPackage pkg = a == null ? null : mPackages.get(a.getPackageName()); +            PackageSetting ps = a == null ? null : mSettings.getPackageLPr(a.getPackageName());              if (pkg != null && mSettings.isEnabledAndMatchLPr(pkg, a, flags, userId)) { -                PackageSetting ps = mSettings.getPackageLPr(component.getPackageName());                  if (ps == null) return null;                  if (shouldFilterApplicationLocked(                          ps, filterCallingUid, component, TYPE_ACTIVITY, userId)) { @@ -2521,8 +2527,8 @@ public class PackageManagerService extends IPackageManager.Stub                          a, flags, ps.readUserState(userId), userId, ps);              }              if (resolveComponentName().equals(component)) { -                return PackageParser.generateActivityInfo( -                        mResolveActivity, flags, new PackageUserState(), userId); +                return generateDelegateActivityInfo(pkg, ps, new PackageUserState(), +                        mResolveActivity, flags, userId);              }              return null;          } @@ -2859,8 +2865,8 @@ public class PackageManagerService extends IPackageManager.Stub                  }                  if (result == null) {                      result = new CrossProfileDomainInfo(); -                    result.resolveInfo = createForwardingResolveInfoUnchecked(new IntentFilter(), -                            sourceUserId, parentUserId); +                    result.resolveInfo = createForwardingResolveInfoUnchecked( +                            new WatchedIntentFilter(), sourceUserId, parentUserId);                  }                  result.highestApprovalLevel = Math.max(mDomainVerificationManager @@ -3168,8 +3174,8 @@ public class PackageManagerService extends IPackageManager.Stub                  return result;              }              final ResolveInfo ephemeralInstaller = new ResolveInfo(mInstantAppInstallerInfo); -            ephemeralInstaller.activityInfo = PackageParser.generateActivityInfo( -                    instantAppInstallerActivity(), 0, ps.readUserState(userId), userId); +            ephemeralInstaller.activityInfo = generateDelegateActivityInfo(ps.getPkg(), ps, +                    ps.readUserState(userId), instantAppInstallerActivity(), 0 /*flags*/, userId);              ephemeralInstaller.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART                      | IntentFilter.MATCH_ADJUSTMENT_NORMAL;              // add a non-generic filter @@ -3253,7 +3259,7 @@ public class PackageManagerService extends IPackageManager.Stub                  ai.flags = ps.pkgFlags;                  ai.privateFlags = ps.pkgPrivateFlags;                  pi.applicationInfo = -                        PackageParser.generateApplicationInfo(ai, flags, state, userId); +                        PackageInfoUtils.generateApplicationInfo(p, flags, state, userId, ps);                  if (DEBUG_PACKAGE_INFO) Log.v(TAG, "ps.pkg is n/a for ["                          + ps.name + "]. Provides a minimum info."); @@ -3369,6 +3375,19 @@ public class PackageManagerService extends IPackageManager.Stub              return getInstalledPackagesBody(flags, userId, callingUid);          } +        private static ActivityInfo generateDelegateActivityInfo(@Nullable AndroidPackage pkg, +                @Nullable PackageSetting ps, @NonNull PackageUserState state, +                @Nullable ActivityInfo activity, int flags, int userId) { +            if (activity == null || pkg == null +                    || !checkUseInstalledOrHidden(pkg, ps, state, flags)) { +                return null; +            } +            final ActivityInfo info = new ActivityInfo(activity); +            info.applicationInfo = +                    PackageInfoUtils.generateApplicationInfo(pkg, flags, state, userId, ps); +            return info; +        } +          public ParceledListSlice<PackageInfo> getInstalledPackagesBody(int flags, int userId,                                                                            int callingUid) {              // writer @@ -3455,15 +3474,15 @@ public class PackageManagerService extends IPackageManager.Stub                  for (int i = resultTargetUser.size() - 1; i >= 0; i--) {                      if ((resultTargetUser.get(i).activityInfo.applicationInfo.flags                              & ApplicationInfo.FLAG_SUSPENDED) == 0) { -                        return createForwardingResolveInfoUnchecked(filter, sourceUserId, -                                targetUserId); +                        return createForwardingResolveInfoUnchecked(filter, +                              sourceUserId, targetUserId);                      }                  }              }              return null;          } -        public ResolveInfo createForwardingResolveInfoUnchecked(IntentFilter filter, +        public ResolveInfo createForwardingResolveInfoUnchecked(WatchedIntentFilter filter,                  int sourceUserId, int targetUserId) {              ResolveInfo forwardingResolveInfo = new ResolveInfo();              final long ident = Binder.clearCallingIdentity(); @@ -3493,7 +3512,7 @@ public class PackageManagerService extends IPackageManager.Stub              forwardingResolveInfo.preferredOrder = 0;              forwardingResolveInfo.match = 0;              forwardingResolveInfo.isDefault = true; -            forwardingResolveInfo.filter = filter; +            forwardingResolveInfo.filter = new IntentFilter(filter.getIntentFilter());              forwardingResolveInfo.targetUserId = targetUserId;              return forwardingResolveInfo;          } @@ -5693,8 +5712,8 @@ public class PackageManagerService extends IPackageManager.Stub      @Override      public void requestChecksums(@NonNull String packageName, boolean includeSplits, -            @Checksum.Type int optional, -            @Checksum.Type int required, @Nullable List trustedInstallers, +            @Checksum.TypeMask int optional, +            @Checksum.TypeMask int required, @Nullable List trustedInstallers,              @NonNull IOnChecksumsReadyListener onChecksumsReadyListener, int userId) {          requestChecksumsInternal(packageName, includeSplits, optional, required, trustedInstallers,                  onChecksumsReadyListener, userId, mInjector.getBackgroundExecutor(), @@ -5702,7 +5721,7 @@ public class PackageManagerService extends IPackageManager.Stub      }      private void requestChecksumsInternal(@NonNull String packageName, boolean includeSplits, -            @Checksum.Type int optional, @Checksum.Type int required, +            @Checksum.TypeMask int optional, @Checksum.TypeMask int required,              @Nullable List trustedInstallers,              @NonNull IOnChecksumsReadyListener onChecksumsReadyListener, int userId,              @NonNull Executor executor, @NonNull Handler handler) { @@ -6130,6 +6149,7 @@ public class PackageManagerService extends IPackageManager.Stub          mInstantAppRegistry.registerObserver(mWatcher);          mSettings.registerObserver(mWatcher);          mIsolatedOwners.registerObserver(mWatcher); +        mComponentResolver.registerObserver(mWatcher);          // If neither "build" attribute is true then this may be a mockito test, and verification          // can fail as a false positive.          Watchable.verifyWatchedAttributes(this, mWatcher, !(mIsEngBuild || mIsUserDebugBuild)); @@ -9443,6 +9463,15 @@ public class PackageManagerService extends IPackageManager.Stub      @Override      public void setLastChosenActivity(Intent intent, String resolvedType, int flags,              IntentFilter filter, int match, ComponentName activity) { +        setLastChosenActivity(intent, resolvedType, flags, +                              new WatchedIntentFilter(filter), match, activity); +    } + +    /** +     * Variant that takes a {@link WatchedIntentFilter} +     */ +    public void setLastChosenActivity(Intent intent, String resolvedType, int flags, +            WatchedIntentFilter filter, int match, ComponentName activity) {          if (getInstantAppPackageName(Binder.getCallingUid()) != null) {              return;          } @@ -9463,7 +9492,7 @@ public class PackageManagerService extends IPackageManager.Stub          findPreferredActivityNotLocked(                  intent, resolvedType, flags, query, 0, false, true, false, userId);          // Add the new activity as the last chosen for this filter -        addPreferredActivityInternal(filter, match, null, activity, false, userId, +        addPreferredActivity(filter, match, null, activity, false, userId,                  "Setting last chosen", false);      } @@ -10181,12 +10210,6 @@ public class PackageManagerService extends IPackageManager.Stub                  resolvedType, flags, sourceUserId);      } -    private ResolveInfo createForwardingResolveInfoUnchecked(IntentFilter filter, -            int sourceUserId, int targetUserId) { -        return liveComputer().createForwardingResolveInfoUnchecked(filter, -                sourceUserId, targetUserId); -    } -      @Override      public @NonNull ParceledListSlice<ResolveInfo> queryIntentActivityOptions(ComponentName caller,              Intent[] specifics, String[] specificTypes, Intent intent, @@ -16463,7 +16486,7 @@ public class PackageManagerService extends IPackageManager.Stub              return new ParceledListSlice<IntentFilter>(result) {                  @Override                  protected void writeElement(IntentFilter parcelable, Parcel dest, int callFlags) { -                    // IntentFilter has final Parcelable methods, so redirect to the subclass +                    // WatchedIntentFilter has final Parcelable methods, so redirect to the subclass                      ((ParsedIntentInfo) parcelable).writeIntentInfoToParcel(dest,                              callFlags);                  } @@ -21950,11 +21973,14 @@ public class PackageManagerService extends IPackageManager.Stub      @Override      public void addPreferredActivity(IntentFilter filter, int match,              ComponentName[] set, ComponentName activity, int userId, boolean removeExisting) { -        addPreferredActivityInternal(filter, match, set, activity, true, userId, +        addPreferredActivity(new WatchedIntentFilter(filter), match, set, activity, true, userId,                  "Adding preferred", removeExisting);      } -    private void addPreferredActivityInternal(IntentFilter filter, int match, +    /** +     * Variant that takes a {@link WatchedIntentFilter} +     */ +    public void addPreferredActivity(WatchedIntentFilter filter, int match,              ComponentName[] set, ComponentName activity, boolean always, int userId,              String opname, boolean removeExisting) {          // writer @@ -22020,6 +22046,15 @@ public class PackageManagerService extends IPackageManager.Stub      @Override      public void replacePreferredActivity(IntentFilter filter, int match,              ComponentName[] set, ComponentName activity, int userId) { +        replacePreferredActivity(new WatchedIntentFilter(filter), match, +                                 set, activity, userId); +    } + +    /** +     * Variant that takes a {@link WatchedIntentFilter} +     */ +    public void replacePreferredActivity(WatchedIntentFilter filter, int match, +            ComponentName[] set, ComponentName activity, int userId) {          if (filter.countActions() != 1) {              throw new IllegalArgumentException(                      "replacePreferredActivity expects filter to have only 1 action."); @@ -22092,7 +22127,7 @@ public class PackageManagerService extends IPackageManager.Stub                  }              }          } -        addPreferredActivityInternal(filter, match, set, activity, true, userId, +        addPreferredActivity(filter, match, set, activity, true, userId,                  "Replacing preferred", false);      } @@ -22199,6 +22234,22 @@ public class PackageManagerService extends IPackageManager.Stub      @Override      public int getPreferredActivities(List<IntentFilter> outFilters,              List<ComponentName> outActivities, String packageName) { +        List<WatchedIntentFilter> temp = +                WatchedIntentFilter.toWatchedIntentFilterList(outFilters); +        final int result = getPreferredActivitiesInternal( +                temp, outActivities, packageName); +        outFilters.clear(); +        for (int i = 0; i < temp.size(); i++) { +            outFilters.add(temp.get(i).getIntentFilter()); +        } +        return result; +    } + +    /** +     * Variant that takes a {@link WatchedIntentFilter} +     */ +    public int getPreferredActivitiesInternal(List<WatchedIntentFilter> outFilters, +            List<ComponentName> outActivities, String packageName) {          if (getInstantAppPackageName(Binder.getCallingUid()) != null) {              return 0;          } @@ -22215,7 +22266,7 @@ public class PackageManagerService extends IPackageManager.Stub                              || (pa.mPref.mComponent.getPackageName().equals(packageName)                                      && pa.mPref.mAlways)) {                          if (outFilters != null) { -                            outFilters.add(new IntentFilter(pa)); +                            outFilters.add(new WatchedIntentFilter(pa.getIntentFilter()));                          }                          if (outActivities != null) {                              outActivities.add(pa.mPref.mComponent); @@ -22231,6 +22282,14 @@ public class PackageManagerService extends IPackageManager.Stub      @Override      public void addPersistentPreferredActivity(IntentFilter filter, ComponentName activity,              int userId) { +        addPersistentPreferredActivity(new WatchedIntentFilter(filter), activity, userId); +    } + +    /** +     * Variant that takes a {@link WatchedIntentFilter} +     */ +    public void addPersistentPreferredActivity(WatchedIntentFilter filter, ComponentName activity, +            int userId) {          int callingUid = Binder.getCallingUid();          if (callingUid != Process.SYSTEM_UID) {              throw new SecurityException( @@ -22474,6 +22533,15 @@ public class PackageManagerService extends IPackageManager.Stub      @Override      public void addCrossProfileIntentFilter(IntentFilter intentFilter, String ownerPackage,              int sourceUserId, int targetUserId, int flags) { +        addCrossProfileIntentFilter(new WatchedIntentFilter(intentFilter), ownerPackage, +                                    sourceUserId, targetUserId, flags); +    } + +    /** +     * Variant that takes a {@link WatchedIntentFilter} +     */ +    public void addCrossProfileIntentFilter(WatchedIntentFilter intentFilter, String ownerPackage, +            int sourceUserId, int targetUserId, int flags) {          mContext.enforceCallingOrSelfPermission(                          android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);          int callingUid = Binder.getCallingUid(); @@ -22603,8 +22671,8 @@ public class PackageManagerService extends IPackageManager.Stub          return liveComputer().getHomeIntent();      } -    private IntentFilter getHomeFilter() { -        IntentFilter filter = new IntentFilter(Intent.ACTION_MAIN); +    private WatchedIntentFilter getHomeFilter() { +        WatchedIntentFilter filter = new WatchedIntentFilter(Intent.ACTION_MAIN);          filter.addCategory(Intent.CATEGORY_HOME);          filter.addCategory(Intent.CATEGORY_DEFAULT);          return filter; @@ -23604,7 +23672,7 @@ public class PackageManagerService extends IPackageManager.Stub          boolean compatibilityModeEnabled = android.provider.Settings.Global.getInt(                  mContext.getContentResolver(),                  android.provider.Settings.Global.COMPATIBILITY_MODE, 1) == 1; -        PackageParser.setCompatibilityModeEnabled(compatibilityModeEnabled); +        ParsingPackageUtils.setCompatibilityModeEnabled(compatibilityModeEnabled);          if (DEBUG_SETTINGS) {              Log.d(TAG, "compatibility mode:" + compatibilityModeEnabled); @@ -26019,18 +26087,29 @@ public class PackageManagerService extends IPackageManager.Stub          @Override          public String[] getNamesForUids(int[] uids) throws RemoteException { -            if (uids == null || uids.length == 0) { -                return null; -            } -            final String[] names = PackageManagerService.this.getNamesForUids(uids); -            final String[] results = (names != null) ? names : new String[uids.length]; -            // massage results so they can be parsed by the native binder -            for (int i = results.length - 1; i >= 0; --i) { -                if (results[i] == null) { -                    results[i] = ""; +            String[] names = null; +            String[] results = null; +            try { +                if (uids == null || uids.length == 0) { +                    return null;                  } +                names = PackageManagerService.this.getNamesForUids(uids); +                results = (names != null) ? names : new String[uids.length]; +                // massage results so they can be parsed by the native binder +                for (int i = results.length - 1; i >= 0; --i) { +                    if (results[i] == null) { +                        results[i] = ""; +                    } +                } +                return results; +            } catch (Throwable t) { +                // STOPSHIP(186558987): revert addition of try/catch/log +                Slog.e(TAG, "uids: " + Arrays.toString(uids)); +                Slog.e(TAG, "names: " + Arrays.toString(names)); +                Slog.e(TAG, "results: " + Arrays.toString(results)); +                Slog.e(TAG, "throwing exception", t); +                throw t;              } -            return results;          }          // NB: this differentiates between preloads and sideloads @@ -27225,7 +27304,7 @@ public class PackageManagerService extends IPackageManager.Stub          @Override          public void requestChecksums(@NonNull String packageName, boolean includeSplits, -                @Checksum.Type int optional, @Checksum.Type int required, +                @Checksum.TypeMask int optional, @Checksum.TypeMask int required,                  @Nullable List trustedInstallers,                  @NonNull IOnChecksumsReadyListener onChecksumsReadyListener, int userId,                  @NonNull Executor executor, @NonNull Handler handler) { diff --git a/services/core/java/com/android/server/pm/PersistentPreferredActivity.java b/services/core/java/com/android/server/pm/PersistentPreferredActivity.java index a015456f1485..ad3950c906ef 100644 --- a/services/core/java/com/android/server/pm/PersistentPreferredActivity.java +++ b/services/core/java/com/android/server/pm/PersistentPreferredActivity.java @@ -23,13 +23,14 @@ import android.util.TypedXmlPullParser;  import android.util.TypedXmlSerializer;  import com.android.internal.util.XmlUtils; +import com.android.server.utils.SnapshotCache;  import org.xmlpull.v1.XmlPullParser;  import org.xmlpull.v1.XmlPullParserException;  import java.io.IOException; -class PersistentPreferredActivity extends IntentFilter { +class PersistentPreferredActivity extends WatchedIntentFilter {      private static final String ATTR_NAME = "name"; // component name      private static final String ATTR_FILTER = "filter"; // filter      private static final String ATTR_SET_BY_DPM = "set-by-dpm"; // set by DPM @@ -41,10 +42,38 @@ class PersistentPreferredActivity extends IntentFilter {      final ComponentName mComponent;      final boolean mIsSetByDpm; +    // The cache for snapshots, so they are not rebuilt if the base object has not +    // changed. +    final SnapshotCache<PersistentPreferredActivity> mSnapshot; + +    private SnapshotCache makeCache() { +        return new SnapshotCache<PersistentPreferredActivity>(this, this) { +            @Override +            public PersistentPreferredActivity createSnapshot() { +                PersistentPreferredActivity s = new PersistentPreferredActivity(mSource); +                s.seal(); +                return s; +            }}; +    } +      PersistentPreferredActivity(IntentFilter filter, ComponentName activity, boolean isSetByDpm) {          super(filter);          mComponent = activity;          mIsSetByDpm = isSetByDpm; +        mSnapshot = makeCache(); +    } + +    PersistentPreferredActivity(WatchedIntentFilter filter, ComponentName activity, +            boolean isSetByDpm) { +        this(filter.mFilter, activity, isSetByDpm); +    } + +    // Copy constructor used only to create a snapshot +    private PersistentPreferredActivity(PersistentPreferredActivity f) { +        super(f); +        mComponent = f.mComponent; +        mIsSetByDpm = f.mIsSetByDpm; +        mSnapshot = new SnapshotCache.Sealed();      }      PersistentPreferredActivity(TypedXmlPullParser parser) @@ -79,27 +108,36 @@ class PersistentPreferredActivity extends IntentFilter {              }          }          if (tagName.equals(ATTR_FILTER)) { -            readFromXml(parser); +            mFilter.readFromXml(parser);          } else {              PackageManagerService.reportSettingsProblem(Log.WARN,                      "Missing element filter at " +                      parser.getPositionDescription());              XmlUtils.skipCurrentTag(parser);          } +        mSnapshot = makeCache();      }      public void writeToXml(TypedXmlSerializer serializer) throws IOException {          serializer.attribute(null, ATTR_NAME, mComponent.flattenToShortString());          serializer.attributeBoolean(null, ATTR_SET_BY_DPM, mIsSetByDpm);          serializer.startTag(null, ATTR_FILTER); -            super.writeToXml(serializer); +        mFilter.writeToXml(serializer);          serializer.endTag(null, ATTR_FILTER);      } +    public IntentFilter getIntentFilter() { +        return mFilter; +    } +      @Override      public String toString() {          return "PersistentPreferredActivity{0x" + Integer.toHexString(System.identityHashCode(this))                  + " " + mComponent.flattenToShortString()                  + ", mIsSetByDpm=" + mIsSetByDpm + "}";      } + +    public PersistentPreferredActivity snapshot() { +        return mSnapshot.snapshot(); +    }  } diff --git a/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java b/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java index 2b11a4297835..bfddaea0dd75 100644 --- a/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java +++ b/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java @@ -21,6 +21,7 @@ import android.content.IntentFilter;  import com.android.server.WatchedIntentResolver;  import com.android.server.utils.Snappable; +import com.android.server.utils.SnapshotCache;  public class PersistentPreferredIntentResolver          extends WatchedIntentResolver<PersistentPreferredActivity, PersistentPreferredActivity> @@ -32,7 +33,7 @@ public class PersistentPreferredIntentResolver      @Override      protected IntentFilter getIntentFilter(@NonNull PersistentPreferredActivity input) { -        return input; +        return input.getIntentFilter();      }      @Override @@ -40,14 +41,40 @@ public class PersistentPreferredIntentResolver          return packageName.equals(filter.mComponent.getPackageName());      } +    public PersistentPreferredIntentResolver() { +        super(); +        mSnapshot = makeCache(); +    } + +    // Take the snapshot of F +    protected PersistentPreferredActivity snapshot(PersistentPreferredActivity f) { +        return (f == null) ? null : f.snapshot(); +    } + +    // Copy constructor used only to create a snapshot. +    private PersistentPreferredIntentResolver(PersistentPreferredIntentResolver f) { +        copyFrom(f); +        mSnapshot = new SnapshotCache.Sealed(); +    } + +    // The cache for snapshots, so they are not rebuilt if the base object has not +    // changed. +    final SnapshotCache<PersistentPreferredIntentResolver> mSnapshot; + +    private SnapshotCache makeCache() { +        return new SnapshotCache<PersistentPreferredIntentResolver>(this, this) { +            @Override +            public PersistentPreferredIntentResolver createSnapshot() { +                return new PersistentPreferredIntentResolver(mSource); +            }}; +    } +      /**       * Return a snapshot of the current object.  The snapshot is a read-only copy suitable       * for read-only methods.       * @return A snapshot of the current object.       */      public PersistentPreferredIntentResolver snapshot() { -        PersistentPreferredIntentResolver result = new PersistentPreferredIntentResolver(); -        result.copyFrom(this); -        return result; +        return mSnapshot.snapshot();      }  } diff --git a/services/core/java/com/android/server/pm/PreferredActivity.java b/services/core/java/com/android/server/pm/PreferredActivity.java index 4e1dcb27111d..5bc915f2c1c4 100644 --- a/services/core/java/com/android/server/pm/PreferredActivity.java +++ b/services/core/java/com/android/server/pm/PreferredActivity.java @@ -23,32 +23,62 @@ import android.util.TypedXmlPullParser;  import android.util.TypedXmlSerializer;  import com.android.internal.util.XmlUtils; +import com.android.server.utils.SnapshotCache;  import org.xmlpull.v1.XmlPullParserException;  import java.io.IOException; +import java.io.PrintWriter; -class PreferredActivity extends IntentFilter implements PreferredComponent.Callbacks { +class PreferredActivity extends WatchedIntentFilter implements PreferredComponent.Callbacks {      private static final String TAG = "PreferredActivity";      private static final boolean DEBUG_FILTERS = false;      final PreferredComponent mPref; +    // The cache for snapshots, so they are not rebuilt if the base object has not +    // changed. +    final SnapshotCache<PreferredActivity> mSnapshot; + +    private SnapshotCache makeCache() { +        return new SnapshotCache<PreferredActivity>(this, this) { +            @Override +            public PreferredActivity createSnapshot() { +                PreferredActivity s = new PreferredActivity(mSource); +                s.seal(); +                return s; +            }}; +    } +      PreferredActivity(IntentFilter filter, int match, ComponentName[] set, ComponentName activity,              boolean always) {          super(filter);          mPref = new PreferredComponent(this, match, set, activity, always); +        mSnapshot = makeCache(); +    } + +    PreferredActivity(WatchedIntentFilter filter, int match, ComponentName[] set, +            ComponentName activity, boolean always) { +        this(filter.mFilter, match, set, activity, always); +    } + +    // Copy constructor used only to create a snapshot +    private PreferredActivity(PreferredActivity f) { +        super(f); +        mPref = f.mPref; +        mSnapshot = new SnapshotCache.Sealed();      }      PreferredActivity(TypedXmlPullParser parser) throws XmlPullParserException, IOException {          mPref = new PreferredComponent(this, parser); +        mSnapshot = makeCache();      }      public void writeToXml(TypedXmlSerializer serializer, boolean full) throws IOException {          mPref.writeToXml(serializer, full);          serializer.startTag(null, "filter"); -            super.writeToXml(serializer); +        mFilter.writeToXml(serializer);          serializer.endTag(null, "filter");      } @@ -58,7 +88,7 @@ class PreferredActivity extends IntentFilter implements PreferredComponent.Callb              if (DEBUG_FILTERS) {                  Log.i(TAG, "Starting to parse filter...");              } -            readFromXml(parser); +            mFilter.readFromXml(parser);              if (DEBUG_FILTERS) {                  Log.i(TAG, "Finished filter: depth=" + parser.getDepth() + " tag="                          + parser.getName()); @@ -71,9 +101,17 @@ class PreferredActivity extends IntentFilter implements PreferredComponent.Callb          return true;      } +    public void dumpPref(PrintWriter out, String prefix, PreferredActivity filter) { +        mPref.dump(out, prefix, filter); +    } +      @Override      public String toString() {          return "PreferredActivity{0x" + Integer.toHexString(System.identityHashCode(this))                  + " " + mPref.mComponent.flattenToShortString() + "}";      } + +    public PreferredActivity snapshot() { +        return mSnapshot.snapshot(); +    }  } diff --git a/services/core/java/com/android/server/pm/PreferredIntentResolver.java b/services/core/java/com/android/server/pm/PreferredIntentResolver.java index 10a6b3f69fde..0aca6eec25fc 100644 --- a/services/core/java/com/android/server/pm/PreferredIntentResolver.java +++ b/services/core/java/com/android/server/pm/PreferredIntentResolver.java @@ -21,6 +21,7 @@ import android.content.IntentFilter;  import com.android.server.WatchedIntentResolver;  import com.android.server.utils.Snappable; +import com.android.server.utils.SnapshotCache;  import java.io.PrintWriter;  import java.util.ArrayList; @@ -46,7 +47,7 @@ public class PreferredIntentResolver      @Override      protected IntentFilter getIntentFilter(@NonNull PreferredActivity input) { -        return input; +        return input.getIntentFilter();      }      public boolean shouldAddPreferredActivity(PreferredActivity pa) { @@ -69,14 +70,40 @@ public class PreferredIntentResolver          return true;      } +    public PreferredIntentResolver() { +        super(); +        mSnapshot = makeCache(); +    } + +    // Take the snapshot of F +    protected PreferredActivity snapshot(PreferredActivity f) { +        return (f == null) ? null : f.snapshot(); +    } + +    // Copy constructor used only to create a snapshot. +    private PreferredIntentResolver(PreferredIntentResolver f) { +        copyFrom(f); +        mSnapshot = new SnapshotCache.Sealed(); +    } + +    // The cache for snapshots, so they are not rebuilt if the base object has not +    // changed. +    final SnapshotCache<PreferredIntentResolver> mSnapshot; + +    private SnapshotCache makeCache() { +        return new SnapshotCache<PreferredIntentResolver>(this, this) { +            @Override +            public PreferredIntentResolver createSnapshot() { +                return new PreferredIntentResolver(mSource); +            }}; +    } +      /**       * Return a snapshot of the current object.  The snapshot is a read-only copy suitable       * for read-only methods.       * @return A snapshot of the current object.       */      public PreferredIntentResolver snapshot() { -        PreferredIntentResolver result = new PreferredIntentResolver(); -        result.copyFrom(this); -        return result; +        return mSnapshot.snapshot();      }  } diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index b985229d3116..1b8eee3925a5 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -3026,8 +3026,9 @@ public final class Settings implements Watchable, Snappable {                          = ps.pkg.getPreferredActivityFilters();                  for (int i=0; i<intents.size(); i++) {                      Pair<String, ParsedIntentInfo> pair = intents.get(i); -                    applyDefaultPreferredActivityLPw(pmInternal, pair.second, new ComponentName( -                            ps.name, pair.first), userId); +                    applyDefaultPreferredActivityLPw(pmInternal, +                            new WatchedIntentFilter(pair.second), +                            new ComponentName(ps.name, pair.first), userId);                  }              }          } @@ -3097,7 +3098,7 @@ public final class Settings implements Watchable, Snappable {      }      static void removeFilters(@NonNull PreferredIntentResolver pir, -            @NonNull IntentFilter filter, @NonNull List<PreferredActivity> existing) { +            @NonNull WatchedIntentFilter filter, @NonNull List<PreferredActivity> existing) {          if (PackageManagerService.DEBUG_PREFERRED) {              Slog.i(TAG, existing.size() + " preferred matches for:");              filter.dump(new LogPrinter(Log.INFO, TAG), "  "); @@ -3112,8 +3113,8 @@ public final class Settings implements Watchable, Snappable {          }      } -    private void applyDefaultPreferredActivityLPw( -            PackageManagerInternal pmInternal, IntentFilter tmpPa, ComponentName cn, int userId) { +    private void applyDefaultPreferredActivityLPw(PackageManagerInternal pmInternal, +            WatchedIntentFilter tmpPa, ComponentName cn, int userId) {          // The initial preferences only specify the target activity          // component and intent-filter, not the set of matches.  So we          // now need to query for the matches to build the correct @@ -3284,7 +3285,7 @@ public final class Settings implements Watchable, Snappable {              haveNonSys = null;          }          if (haveAct && haveNonSys == null) { -            IntentFilter filter = new IntentFilter(); +            WatchedIntentFilter filter = new WatchedIntentFilter();              if (intent.getAction() != null) {                  filter.addAction(intent.getAction());              } diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java index 3dfb835eeb45..1bd9e5eedb84 100644 --- a/services/core/java/com/android/server/pm/ShortcutPackage.java +++ b/services/core/java/com/android/server/pm/ShortcutPackage.java @@ -319,7 +319,7 @@ class ShortcutPackage extends ShortcutPackageItem {              }              final Icon icon = si.getIcon();              if (icon != null && icon.getType() != Icon.TYPE_BITMAP -                    && icon.getType() == Icon.TYPE_ADAPTIVE_BITMAP) { +                    && icon.getType() != Icon.TYPE_ADAPTIVE_BITMAP) {                  continue;              }              if (icon == null && !si.hasIconFile()) { diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java index 61f51e36202c..b89dbdc863e0 100644 --- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java +++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java @@ -417,7 +417,7 @@ public class PackageInfoUtils {       * Returns true if the package is installed and not hidden, or if the caller       * explicitly wanted all uninstalled and hidden packages as well.       */ -    private static boolean checkUseInstalledOrHidden(AndroidPackage pkg, +    public static boolean checkUseInstalledOrHidden(AndroidPackage pkg,              PackageSetting pkgSetting, PackageUserState state,              @PackageManager.PackageInfoFlags int flags) {          // Returns false if the package is hidden system app until installed. diff --git a/services/core/java/com/android/server/pm/utils/RequestThrottle.java b/services/core/java/com/android/server/pm/utils/RequestThrottle.java new file mode 100644 index 000000000000..f1dd402d48f5 --- /dev/null +++ b/services/core/java/com/android/server/pm/utils/RequestThrottle.java @@ -0,0 +1,154 @@ +/* + * 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.pm.utils; + +import android.annotation.NonNull; +import android.os.Handler; + +import com.android.server.IoThread; + +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Supplier; + +/** + * Loose throttle latest behavior for success/fail requests, with options to schedule or force a + * request through. Throttling is implicit and not configurable. This means requests are dispatched + * to the {@link Handler} immediately when received, and only batched while waiting on the next + * message execution or running request. + * + * This also means there is no explicit debouncing. Implicit debouncing is available through the + * same runtime delays in the {@link Handler} instance and the request execution, where multiple + * requests prior to the execution point are collapsed. + * + * Callers provide a {@link Handler} with which to schedule tasks on. This may be a highly + * contentious thread like {@link IoThread#getHandler()}, but note that there are no guarantees + * that the request will be handled before the system server dies. Ideally callers should handle + * re-initialization from stale state with no consequences to the user. + * + * This class will retry requests if they don't succeed, as provided by a true/false response from + * the block provided to run the request. This uses an exponential backoff mechanism, assuming that + * state write should be attempted immediately, but not retried so heavily as to potentially block + * other system server callers. Exceptions are not considered and will not result in a retry if + * thrown from inside the block. Caller should wrap with try-catch and rollback and transaction + * state before returning false to signal a retry. + * + * The caller is strictly responsible for data synchronization, as this class will not synchronize + * the request block, potentially running it multiple times or on multiple threads simultaneously + * if requests come in asynchronously. + */ +public class RequestThrottle { + +    private static final int DEFAULT_RETRY_MAX_ATTEMPTS = 5; +    private static final int DEFAULT_DELAY_MS = 1000; +    private static final int DEFAULT_BACKOFF_BASE = 2; + +    private final AtomicInteger mLastRequest = new AtomicInteger(0); +    private final AtomicInteger mLastCommitted = new AtomicInteger(-1); + +    private final int mMaxAttempts; +    private final int mFirstDelay; +    private final int mBackoffBase; + +    private final AtomicInteger mCurrentRetry = new AtomicInteger(0); + +    @NonNull +    private final Handler mHandler; + +    @NonNull +    private final Supplier<Boolean> mBlock; + +    @NonNull +    private final Runnable mRunnable; + +    /** +     * @see #RequestThrottle(Handler, int, int, int, Supplier) +     */ +    public RequestThrottle(@NonNull Handler handler, @NonNull Supplier<Boolean> block) { +        this(handler, DEFAULT_RETRY_MAX_ATTEMPTS, DEFAULT_DELAY_MS, DEFAULT_BACKOFF_BASE, +                block); +    } + +    /** +     * Backoff timing is calculated as firstDelay * (backoffBase ^ retryAttempt). +     * +     * @param handler     Representing the thread to run the provided block. +     * @param block       The action to run when scheduled, returning whether or not the request was +     *                    successful. Note that any thrown exceptions will be ignored and not +     *                    retried, since it's not easy to tell how destructive or retry-able an +     *                    exception is. +     * @param maxAttempts Number of times to re-attempt any single request. +     * @param firstDelay  The first delay used after the initial attempt. +     * @param backoffBase The base of the backoff calculation, where retry attempt count is the +     *                    exponent. +     */ +    public RequestThrottle(@NonNull Handler handler, int maxAttempts, int firstDelay, +            int backoffBase, @NonNull Supplier<Boolean> block) { +        mHandler = handler; +        mBlock = block; +        mMaxAttempts = maxAttempts; +        mFirstDelay = firstDelay; +        mBackoffBase = backoffBase; +        mRunnable = this::runInternal; +    } + +    /** +     * Schedule the intended action on the provided {@link Handler}. +     */ +    public void schedule() { +        // To avoid locking the Handler twice by pre-checking hasCallbacks, instead just queue +        // the Runnable again. It will no-op if the request has already been written to disk. +        mLastRequest.incrementAndGet(); +        mHandler.post(mRunnable); +    } + +    /** +     * Run the intended action immediately on the calling thread. Note that synchronization and +     * deadlock between threads is not handled. This will immediately call the request block, and +     * also potentially schedule a retry. The caller must not block itself. +     * +     * @return true if the write succeeded or the last request was already written +     */ +    public boolean runNow() { +        mLastRequest.incrementAndGet(); +        return runInternal(); +    } + +    private boolean runInternal() { +        int lastRequest = mLastRequest.get(); +        int lastCommitted = mLastCommitted.get(); +        if (lastRequest == lastCommitted) { +            return true; +        } + +        if (mBlock.get()) { +            mCurrentRetry.set(0); +            mLastCommitted.set(lastRequest); +            return true; +        } else { +            int currentRetry = mCurrentRetry.getAndIncrement(); +            if (currentRetry < mMaxAttempts) { +                long nextDelay = +                        (long) (mFirstDelay * Math.pow(mBackoffBase, currentRetry)); +                mHandler.postDelayed(mRunnable, nextDelay); +            } else { +                mCurrentRetry.set(0); +            } + +            return false; +        } +    } +} diff --git a/services/core/java/com/android/server/policy/DisplayFoldController.java b/services/core/java/com/android/server/policy/DisplayFoldController.java index 0e12584f80a1..3c9b1063ba93 100644 --- a/services/core/java/com/android/server/policy/DisplayFoldController.java +++ b/services/core/java/com/android/server/policy/DisplayFoldController.java @@ -21,6 +21,7 @@ import android.content.Context;  import android.graphics.Rect;  import android.hardware.ICameraService;  import android.hardware.devicestate.DeviceStateManager; +import android.hardware.devicestate.DeviceStateManager.FoldStateListener;  import android.hardware.display.DisplayManagerInternal;  import android.os.Handler;  import android.os.HandlerExecutor; @@ -75,7 +76,7 @@ class DisplayFoldController {          DeviceStateManager deviceStateManager = context.getSystemService(DeviceStateManager.class);          deviceStateManager.registerCallback(new HandlerExecutor(handler), -                new DeviceStateListener(context)); +                new FoldStateListener(context, folded -> setDeviceFolded(folded)));      }      void finishedGoingToSleep() { @@ -202,30 +203,4 @@ class DisplayFoldController {          return new DisplayFoldController(context, windowManagerService, displayService,                  cameraServiceProxy, displayId, foldedArea, DisplayThread.getHandler());      } - -    /** -     * Listens to changes in device state and reports the state as folded if the device state -     * matches the value in the {@link com.android.internal.R.integer.config_foldedDeviceState} -     * resource. -     */ -    private class DeviceStateListener implements DeviceStateManager.DeviceStateCallback { -        private final int[] mFoldedDeviceStates; - -        DeviceStateListener(Context context) { -            mFoldedDeviceStates = context.getResources().getIntArray( -                    com.android.internal.R.array.config_foldedDeviceStates); -        } - -        @Override -        public void onStateChanged(int deviceState) { -            boolean folded = false; -            for (int i = 0; i < mFoldedDeviceStates.length; i++) { -                if (deviceState == mFoldedDeviceStates[i]) { -                    folded = true; -                    break; -                } -            } -            setDeviceFolded(folded); -        } -    }  } diff --git a/services/core/java/com/android/server/telecom/TelecomLoaderService.java b/services/core/java/com/android/server/telecom/TelecomLoaderService.java index f0c96e18930a..32ad702ceff5 100644 --- a/services/core/java/com/android/server/telecom/TelecomLoaderService.java +++ b/services/core/java/com/android/server/telecom/TelecomLoaderService.java @@ -31,6 +31,7 @@ import android.telecom.DefaultDialerManager;  import android.telecom.PhoneAccountHandle;  import android.telecom.TelecomManager;  import android.telephony.CarrierConfigManager; +import android.telephony.SubscriptionManager;  import android.util.IntArray;  import android.util.Slog; @@ -44,6 +45,9 @@ import com.android.server.SystemService;  import com.android.server.pm.UserManagerService;  import com.android.server.pm.permission.LegacyPermissionManagerInternal; +import java.util.ArrayList; +import java.util.List; +  /**   * Starts the telecom component by binding to its ITelecomService implementation. Telecom is setup   * to run in the system-server process so once it is loaded into memory it will stay running. @@ -208,13 +212,23 @@ public class TelecomLoaderService extends SystemService {                      return null;                  }              } +            SubscriptionManager subscriptionManager = +                    mContext.getSystemService(SubscriptionManager.class); +            if (subscriptionManager == null) { +                return null; +            }              TelecomManager telecomManager =                      (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE); -            PhoneAccountHandle phoneAccount = telecomManager.getSimCallManager(userId); -            if (phoneAccount != null) { -                return new String[]{phoneAccount.getComponentName().getPackageName()}; +            List<String> packages = new ArrayList<>(); +            int[] subIds = subscriptionManager.getActiveSubscriptionIdList(); +            for (int subId : subIds) { +                PhoneAccountHandle phoneAccount = +                        telecomManager.getSimCallManagerForSubscription(subId); +                if (phoneAccount != null) { +                    packages.add(phoneAccount.getComponentName().getPackageName()); +                }              } -            return null; +            return packages.toArray(new String[] {});          });      } diff --git a/services/core/java/com/android/server/timezonedetector/MetricsTimeZoneDetectorState.java b/services/core/java/com/android/server/timezonedetector/MetricsTimeZoneDetectorState.java index c8c828f10ad3..27b50d892144 100644 --- a/services/core/java/com/android/server/timezonedetector/MetricsTimeZoneDetectorState.java +++ b/services/core/java/com/android/server/timezonedetector/MetricsTimeZoneDetectorState.java @@ -89,8 +89,6 @@ public final class MetricsTimeZoneDetectorState {              @Nullable TelephonyTimeZoneSuggestion latestTelephonySuggestion,              @Nullable GeolocationTimeZoneSuggestion latestGeolocationSuggestion) { -        // TODO(b/172934905) Add logic to canonicalize the time zone IDs to Android's preferred IDs -        //  so that the ordinals will match even when the ID is not identical, just equivalent.          int deviceTimeZoneIdOrdinal =                  tzIdOrdinalGenerator.ordinal(Objects.requireNonNull(deviceTimeZoneId));          MetricsTimeZoneSuggestion latestObfuscatedManualSuggestion = diff --git a/services/core/java/com/android/server/timezonedetector/OrdinalGenerator.java b/services/core/java/com/android/server/timezonedetector/OrdinalGenerator.java index a448773c40d5..50875308db7d 100644 --- a/services/core/java/com/android/server/timezonedetector/OrdinalGenerator.java +++ b/services/core/java/com/android/server/timezonedetector/OrdinalGenerator.java @@ -15,9 +15,12 @@   */  package com.android.server.timezonedetector; +import android.annotation.NonNull;  import android.util.ArraySet;  import java.util.List; +import java.util.Objects; +import java.util.function.Function;  /**   * A helper class that turns a set of objects into ordinal values, i.e. each object is offered @@ -30,11 +33,19 @@ import java.util.List;  class OrdinalGenerator<T> {      private final ArraySet<T> mKnownIds = new ArraySet<>(); +    private final @NonNull Function<T, T> mCanonicalizationFunction; + +    OrdinalGenerator(@NonNull Function<T, T> canonicalizationFunction) { +        mCanonicalizationFunction = Objects.requireNonNull(canonicalizationFunction); +    } +      int ordinal(T object) { -        int ordinal = mKnownIds.indexOf(object); +        T canonical = mCanonicalizationFunction.apply(object); + +        int ordinal = mKnownIds.indexOf(canonical);          if (ordinal < 0) {              ordinal = mKnownIds.size(); -            mKnownIds.add(object); +            mKnownIds.add(canonical);          }          return ordinal;      } diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneCanonicalizer.java b/services/core/java/com/android/server/timezonedetector/TimeZoneCanonicalizer.java new file mode 100644 index 000000000000..bdbf60712008 --- /dev/null +++ b/services/core/java/com/android/server/timezonedetector/TimeZoneCanonicalizer.java @@ -0,0 +1,35 @@ +/* + * 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.timezonedetector; + +import com.android.i18n.timezone.TimeZoneFinder; + +import java.util.function.Function; + +/** + * Returns preferred time zone ID if {@code timeZoneId} was deprecated. For example, returns + * America/Nuuk for America/Godthab. + */ +final class TimeZoneCanonicalizer implements Function<String, String> { +    @Override +    public String apply(String timeZoneId) { +        String canonicialZoneId = TimeZoneFinder.getInstance().getCountryZonesFinder() +                .findCanonicalTimeZoneId(timeZoneId); + +        return canonicialZoneId == null ? timeZoneId : canonicialZoneId; +    } +} diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java index c34a7d37ba24..ab2a88b44a87 100644 --- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java +++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java @@ -383,7 +383,8 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat                  bestQualifiedTelephonySuggestion == null                          ? null : bestQualifiedTelephonySuggestion.suggestion;          // A new generator is created each time: we don't want / require consistency. -        OrdinalGenerator<String> tzIdOrdinalGenerator = new OrdinalGenerator<>(); +        OrdinalGenerator<String> tzIdOrdinalGenerator = +                new OrdinalGenerator<>(new TimeZoneCanonicalizer());          return MetricsTimeZoneDetectorState.create(                  tzIdOrdinalGenerator,                  getConfigurationInternal(currentUserId), diff --git a/services/core/java/com/android/server/utils/SnapshotCache.java b/services/core/java/com/android/server/utils/SnapshotCache.java index f0fb8b25b402..b4b8835ac026 100644 --- a/services/core/java/com/android/server/utils/SnapshotCache.java +++ b/services/core/java/com/android/server/utils/SnapshotCache.java @@ -57,6 +57,15 @@ public abstract class SnapshotCache<T> extends Watcher{      }      /** +     * A private constructor that sets fields to null and mSealed to true.  This supports +     * the Sealed subclass. +     */ +    public SnapshotCache() { +        mSource = null; +        mSealed = true; +    } + +    /**       * Notify the object that the source object has changed.  If the local object is sealed then       * IllegalStateException is thrown.  Otherwise, the cache is cleared.       */ @@ -93,4 +102,25 @@ public abstract class SnapshotCache<T> extends Watcher{       * @return A snapshot       */      public abstract T createSnapshot(); + +    /** +     * A snapshot cache suitable for sealed snapshots.  Attempting to retrieve the +     * snapshot will throw an UnsupportedOperationException. +     * @param <T> the type of object being cached.  This is needed for compilation only.  It +     * has no effect on execution. +     */ +    public static class Sealed<T> extends SnapshotCache<T> { +        /** +         * Create a sealed SnapshotCache that cannot be used to create new snapshots. +         */ +        public Sealed() { +        } +        /** +         * Provide a concrete implementation of createSnapshot() that throws +         * UnsupportedOperationException. +         */ +        public T createSnapshot() { +            throw new UnsupportedOperationException("cannot snapshot a sealed snaphot"); +        } +    }  } diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 6a1b1069f57c..8f3702ac1a5e 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -91,6 +91,7 @@ import static android.content.pm.ActivityInfo.SIZE_CHANGES_UNSUPPORTED_OVERRIDE;  import static android.content.pm.ActivityInfo.isFixedOrientationLandscape;  import static android.content.pm.ActivityInfo.isFixedOrientationPortrait;  import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.content.res.Configuration.ASSETS_SEQ_UNDEFINED;  import static android.content.res.Configuration.EMPTY;  import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;  import static android.content.res.Configuration.ORIENTATION_PORTRAIT; @@ -6618,9 +6619,15 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A      @Override      void onCancelFixedRotationTransform(int originalDisplayRotation) { -        if (this != mDisplayContent.getLastOrientationSource() -                || getRequestedConfigurationOrientation() != ORIENTATION_UNDEFINED) { -            // Only need to handle the activity that should be rotated with display. +        if (this != mDisplayContent.getLastOrientationSource()) { +            // This activity doesn't affect display rotation. +            return; +        } +        final int requestedOrientation = getRequestedConfigurationOrientation(); +        if (requestedOrientation != ORIENTATION_UNDEFINED +                && requestedOrientation != mDisplayContent.getConfiguration().orientation) { +            // Only need to handle the activity that can be rotated with display or the activity +            // has requested the same orientation.              return;          } @@ -6858,6 +6865,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A      @Override      void resolveOverrideConfiguration(Configuration newParentConfiguration) { +        final Configuration requestedOverrideConfig = getRequestedOverrideConfiguration(); +        if (requestedOverrideConfig.assetsSeq != ASSETS_SEQ_UNDEFINED +                && newParentConfiguration.assetsSeq > requestedOverrideConfig.assetsSeq) { +            requestedOverrideConfig.assetsSeq = ASSETS_SEQ_UNDEFINED; +        }          super.resolveOverrideConfiguration(newParentConfiguration);          final Configuration resolvedConfig = getResolvedOverrideConfiguration();          if (isFixedRotationTransforming()) { diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index e249e674a174..c6a66c573ada 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -472,6 +472,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {      /** Current sequencing integer of the configuration, for skipping old configurations. */      private int mConfigurationSeq; + +    /** Current sequencing integer of the asset changes, for skipping old resources overlays. */ +    private int mGlobalAssetsSeq; +      // To cache the list of supported system locales      private String[] mSupportedSystemLocales = null; @@ -4129,6 +4133,35 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {          return changes;      } +    private int increaseAssetConfigurationSeq() { +        mGlobalAssetsSeq = Math.max(++mGlobalAssetsSeq, 1); +        return mGlobalAssetsSeq; +    } + +    /** +     * Update the asset configuration and increase the assets sequence number. +     * @param processes the processes that needs to update the asset configuration, if none +     *                  updates the global configuration for all processes. +     */ +    public void updateAssetConfiguration(List<WindowProcessController> processes) { +        synchronized (mGlobalLock) { +            final int assetSeq = increaseAssetConfigurationSeq(); + +            // Update the global configuration if the no target processes +            if (processes == null) { +                Configuration newConfig = new Configuration(); +                newConfig.assetsSeq = assetSeq; +                updateConfiguration(newConfig); +                return; +            } + +            for (int i = processes.size() - 1; i >= 0; i--) { +                final WindowProcessController wpc = processes.get(i); +                wpc.updateAssetConfiguration(assetSeq); +            } +        } +    } +      void startLaunchPowerMode(@PowerModeReason int reason) {          if (mPowerManagerInternal == null) return;          mPowerManagerInternal.setPowerMode(Mode.LAUNCH, true); diff --git a/services/core/java/com/android/server/wm/DragAndDropPermissionsHandler.java b/services/core/java/com/android/server/wm/DragAndDropPermissionsHandler.java index 62e4a8547600..87670d23573e 100644 --- a/services/core/java/com/android/server/wm/DragAndDropPermissionsHandler.java +++ b/services/core/java/com/android/server/wm/DragAndDropPermissionsHandler.java @@ -32,8 +32,7 @@ import com.android.server.uri.UriGrantsManagerInternal;  import java.util.ArrayList; -class DragAndDropPermissionsHandler extends IDragAndDropPermissions.Stub -        implements IBinder.DeathRecipient { +class DragAndDropPermissionsHandler extends IDragAndDropPermissions.Stub {      private static final String TAG = "DragAndDrop";      private static final boolean DEBUG = false; @@ -49,7 +48,6 @@ class DragAndDropPermissionsHandler extends IDragAndDropPermissions.Stub      private IBinder mActivityToken = null;      private IBinder mPermissionOwnerToken = null; -    private IBinder mAppToken = null;      DragAndDropPermissionsHandler(WindowManagerGlobalLock lock, ClipData clipData, int sourceUid,              String targetPackage, int mode, int sourceUserId, int targetUserId) { @@ -94,18 +92,15 @@ class DragAndDropPermissionsHandler extends IDragAndDropPermissions.Stub      }      @Override -    public void takeTransient(IBinder appToken) throws RemoteException { +    public void takeTransient() throws RemoteException {          if (mActivityToken != null || mPermissionOwnerToken != null) {              return;          }          if (DEBUG) { -            Log.d(TAG, this + ": taking permissions bound to app process: " -                    + toHexString(appToken.hashCode())); +            Log.d(TAG, this + ": taking transient permissions");          }          mPermissionOwnerToken = LocalServices.getService(UriGrantsManagerInternal.class)                  .newUriPermissionOwner("drop"); -        mAppToken = appToken; -        mAppToken.linkToDeath(this, 0);          doTake(mPermissionOwnerToken);      } @@ -132,10 +127,8 @@ class DragAndDropPermissionsHandler extends IDragAndDropPermissions.Stub          } else {              permissionOwner = mPermissionOwnerToken;              mPermissionOwnerToken = null; -            mAppToken.unlinkToDeath(this, 0); -            mAppToken = null;              if (DEBUG) { -                Log.d(TAG, this + ": releasing process-bound permissions"); +                Log.d(TAG, this + ": releasing transient permissions");              }          } @@ -157,15 +150,18 @@ class DragAndDropPermissionsHandler extends IDragAndDropPermissions.Stub          }      } +    /** +     * If permissions are not tied to an activity, release whenever there are no more references +     * to this object (if not already released). +     */      @Override -    public void binderDied() { +    protected void finalize() throws Throwable {          if (DEBUG) { -            Log.d(TAG, this + ": app process died: " + toHexString(mAppToken.hashCode())); +            Log.d(TAG, this + ": running finalizer");          } -        try { -            release(); -        } catch (RemoteException e) { -            // Cannot happen, local call. +        if (mActivityToken != null || mPermissionOwnerToken == null) { +            return;          } +        release();      }  } diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index dc079880d2aa..ab7e65cc64e8 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -23,7 +23,6 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;  import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;  import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;  import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; -import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;  import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;  import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;  import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; @@ -2933,17 +2932,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent>                          || rootTask.mCreatedByOrganizer) {                      return rootTask;                  } -                if (windowingMode == WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY -                        && container.getRootSplitScreenPrimaryTask() == rootTask -                        && candidateTask == rootTask.getTopMostTask()) { -                    // This is a special case when we try to launch an activity that is currently on -                    // top of root split-screen primary task, but is targeting split-screen -                    // secondary. -                    // In this case we don't want to move it to another root task. -                    // TODO(b/78788972): Remove after differentiating between preferred and required -                    // launch options. -                    return rootTask; -                }              }          } diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java index fb66c0493025..d67a0d371675 100644 --- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java +++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java @@ -163,14 +163,8 @@ class ScreenRotationAnimation {              originalWidth = displayInfo.logicalWidth;              originalHeight = displayInfo.logicalHeight;          } -        if (realOriginalRotation == Surface.ROTATION_90 -                || realOriginalRotation == Surface.ROTATION_270) { -            mWidth = originalHeight; -            mHeight = originalWidth; -        } else { -            mWidth = originalWidth; -            mHeight = originalHeight; -        } +        mWidth = originalWidth; +        mHeight = originalHeight;          mOriginalRotation = originalRotation;          // If the delta is not zero, the rotation of display may not change, but we still want to @@ -189,8 +183,14 @@ class ScreenRotationAnimation {          final SurfaceControl.Transaction t = mService.mTransactionFactory.get();          try { +            SurfaceControl.LayerCaptureArgs args = +                    new SurfaceControl.LayerCaptureArgs.Builder(displayContent.getSurfaceControl()) +                            .setCaptureSecureLayers(true) +                            .setAllowProtected(true) +                            .setSourceCrop(new Rect(0, 0, mWidth, mHeight)) +                            .build();              SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer = -                    mService.mDisplayManagerInternal.systemScreenshot(displayId); +                    SurfaceControl.captureLayers(args);              if (screenshotBuffer == null) {                  Slog.w(TAG, "Unable to take screenshot of display " + displayId);                  return; @@ -236,9 +236,6 @@ class ScreenRotationAnimation {              GraphicBuffer buffer = GraphicBuffer.createFromHardwareBuffer(                      screenshotBuffer.getHardwareBuffer()); -            // Scale the layer to the display size. -            float dsdx = (float) mWidth / hardwareBuffer.getWidth(); -            float dsdy = (float) mHeight / hardwareBuffer.getHeight();              t.setLayer(mScreenshotLayer, SCREEN_FREEZE_LAYER_BASE);              t.reparent(mBackColorSurface, displayContent.getSurfaceControl()); @@ -247,7 +244,6 @@ class ScreenRotationAnimation {              t.setAlpha(mBackColorSurface, 1);              t.setBuffer(mScreenshotLayer, buffer);              t.setColorSpace(mScreenshotLayer, screenshotBuffer.getColorSpace()); -            t.setMatrix(mScreenshotLayer, dsdx, 0, 0, dsdy);              t.show(mScreenshotLayer);              t.show(mBackColorSurface); @@ -330,9 +326,8 @@ class ScreenRotationAnimation {          // Compute the transformation matrix that must be applied          // to the snapshot to make it stay in the same original position          // with the current screen rotation. -        int delta = deltaRotation(rotation, Surface.ROTATION_0); +        int delta = deltaRotation(rotation, mOriginalRotation);          RotationAnimationUtils.createRotationMatrix(delta, mWidth, mHeight, mSnapshotInitialMatrix); -          setRotationTransform(t, mSnapshotInitialMatrix);      } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 7c95edd24718..2c592d00f90c 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -2258,7 +2258,6 @@ class Task extends WindowContainer<WindowContainer> {          mTmpPrevBounds.set(getBounds());          final boolean wasInMultiWindowMode = inMultiWindowMode();          final boolean wasInPictureInPicture = inPinnedWindowingMode(); -        final int oldOrientation = getOrientation();          super.onConfigurationChanged(newParentConfig);          // Only need to update surface size here since the super method will handle updating          // surface position. @@ -2301,11 +2300,6 @@ class Task extends WindowContainer<WindowContainer> {              mForceNotOrganized = false;          } -        // Report orientation change such as changing from freeform to fullscreen. -        if (oldOrientation != getOrientation()) { -            onDescendantOrientationChanged(this); -        } -          saveLaunchingStateIfNeeded();          final boolean taskOrgChanged = updateTaskOrganizerState(false /* forceUpdate */);          if (taskOrgChanged) { @@ -4315,11 +4309,21 @@ class Task extends WindowContainer<WindowContainer> {                  // the screen are opaque.                  return TASK_VISIBILITY_INVISIBLE;              } -            if (isAssistantType && gotRootSplitScreenTask) { -                // Assistant stack can't be visible behind split-screen. In addition to this not -                // making sense, it also works around an issue here we boost the z-order of the -                // assistant window surfaces in window manager whenever it is visible. -                return TASK_VISIBILITY_INVISIBLE; +            if (gotRootSplitScreenTask) { +                if (isAssistantType) { +                    // Assistant stack can't be visible behind split-screen. In addition to this not +                    // making sense, it also works around an issue here we boost the z-order of the +                    // assistant window surfaces in window manager whenever it is visible. +                    return TASK_VISIBILITY_INVISIBLE; +                } +                if (other.isHomeOrRecentsRootTask()) { +                    // While in split mode, home task will be reparented to the secondary split and +                    // leaving tasks not supporting split below. Due to +                    // TaskDisplayArea#assignRootTaskOrdering always adjusts home surface layer to +                    // the bottom, this makes sure those tasks below home is invisible and won't +                    // occlude home task unexpectedly. +                    return TASK_VISIBILITY_INVISIBLE; +                }              }              if (other.mAdjacentTask != null) {                  if (adjacentTasks.contains(other.mAdjacentTask)) { diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java index 4dc60070d6ec..d59654949a27 100644 --- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java +++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java @@ -130,6 +130,12 @@ public class WindowManagerShellCommand extends ShellCommand {                      return runResetLetterboxStyle(pw);                  case "set-sandbox-display-apis":                      return runSandboxDisplayApis(pw); +                case "set-multi-window-config": +                    return runSetMultiWindowConfig(); +                case "get-multi-window-config": +                    return runGetMultiWindowConfig(pw); +                case "reset-multi-window-config": +                    return runResetMultiWindowConfig();                  case "reset":                      return runReset(pw);                  case "disable-blur": @@ -815,6 +821,80 @@ public class WindowManagerShellCommand extends ShellCommand {          return 0;      } +    private int runSetMultiWindowConfig() { +        if (peekNextArg() == null) { +            getErrPrintWriter().println("Error: No arguments provided."); +        } +        int result = 0; +        while (peekNextArg() != null) { +            String arg = getNextArg(); +            switch (arg) { +                case "--supportsNonResizable": +                    result += runSetSupportsNonResizableMultiWindow(); +                    break; +                case "--respectsActivityMinWidthHeight": +                    result += runSetRespectsActivityMinWidthHeightMultiWindow(); +                    break; +                default: +                    getErrPrintWriter().println( +                            "Error: Unrecognized multi window option: " + arg); +                    return -1; +            } +        } +        return result == 0 ? 0 : -1; +    } + +    private int runSetSupportsNonResizableMultiWindow() { +        final String arg = getNextArg(); +        if (!arg.equals("-1") && !arg.equals("0") && !arg.equals("1")) { +            getErrPrintWriter().println("Error: a config value of [-1, 0, 1] must be provided as" +                    + " an argument for supportsNonResizableMultiWindow"); +            return -1; +        } +        final int configValue = Integer.parseInt(arg); +        synchronized (mInternal.mAtmService.mGlobalLock) { +            mInternal.mAtmService.mSupportsNonResizableMultiWindow = configValue; +        } +        return 0; +    } + +    private int runSetRespectsActivityMinWidthHeightMultiWindow() { +        final String arg = getNextArg(); +        if (!arg.equals("-1") && !arg.equals("0") && !arg.equals("1")) { +            getErrPrintWriter().println("Error: a config value of [-1, 0, 1] must be provided as" +                    + " an argument for respectsActivityMinWidthHeightMultiWindow"); +            return -1; +        } +        final int configValue = Integer.parseInt(arg); +        synchronized (mInternal.mAtmService.mGlobalLock) { +            mInternal.mAtmService.mRespectsActivityMinWidthHeightMultiWindow = configValue; +        } +        return 0; +    } + +    private int runGetMultiWindowConfig(PrintWriter pw) { +        synchronized (mInternal.mAtmService.mGlobalLock) { +            pw.println("Supports non-resizable in multi window: " +                    + mInternal.mAtmService.mSupportsNonResizableMultiWindow); +            pw.println("Respects activity min width/height in multi window: " +                    + mInternal.mAtmService.mRespectsActivityMinWidthHeightMultiWindow); +        } +        return 0; +    } + +    private int runResetMultiWindowConfig() { +        final int supportsNonResizable = mInternal.mContext.getResources().getInteger( +                com.android.internal.R.integer.config_supportsNonResizableMultiWindow); +        final int respectsActivityMinWidthHeight = mInternal.mContext.getResources().getInteger( +                com.android.internal.R.integer.config_respectsActivityMinWidthHeightMultiWindow); +        synchronized (mInternal.mAtmService.mGlobalLock) { +            mInternal.mAtmService.mSupportsNonResizableMultiWindow = supportsNonResizable; +            mInternal.mAtmService.mRespectsActivityMinWidthHeightMultiWindow = +                    respectsActivityMinWidthHeight; +        } +        return 0; +    } +      private void resetLetterboxStyle() {          synchronized (mInternal.mGlobalLock) {              mLetterboxConfiguration.resetFixedOrientationLetterboxAspectRatio(); @@ -879,6 +959,9 @@ public class WindowManagerShellCommand extends ShellCommand {          // set-sandbox-display-apis          mInternal.setSandboxDisplayApis(displayId, /* sandboxDisplayApis= */ true); +        // set-multi-window-config +        runResetMultiWindowConfig(); +          pw.println("Reset all settings for displayId=" + displayId);          return 0;      } @@ -916,6 +999,7 @@ public class WindowManagerShellCommand extends ShellCommand {          pw.println("    Size Compat Mode.");          printLetterboxHelp(pw); +        printMultiWindowConfigHelp(pw);          pw.println("  reset [-d DISPLAY_ID]");          pw.println("    Reset all override settings."); @@ -969,4 +1053,31 @@ public class WindowManagerShellCommand extends ShellCommand {          pw.println("  get-letterbox-style");          pw.println("    Prints letterbox style configuration.");      } + +    private void printMultiWindowConfigHelp(PrintWriter pw) { +        pw.println("  set-multi-window-config"); +        pw.println("    Sets options to determine if activity should be shown in multi window:"); +        pw.println("      --supportsNonResizable [configValue]"); +        pw.println("        Whether the device supports non-resizable activity in multi window."); +        pw.println("        -1: The device doesn't support non-resizable in multi window."); +        pw.println("         0: The device supports non-resizable in multi window only if"); +        pw.println("            this is a large screen device."); +        pw.println("         1: The device always supports non-resizable in multi window."); +        pw.println("      --respectsActivityMinWidthHeight [configValue]"); +        pw.println("        Whether the device checks the activity min width/height to determine "); +        pw.println("        if it can be shown in multi window."); +        pw.println("        -1: The device ignores the activity min width/height when determining"); +        pw.println("            if it can be shown in multi window."); +        pw.println("         0: If this is a small screen, the device compares the activity min"); +        pw.println("            width/height with the min multi window modes dimensions"); +        pw.println("            the device supports to determine if the activity can be shown in"); +        pw.println("            multi window."); +        pw.println("         1: The device always compare the activity min width/height with the"); +        pw.println("            min multi window dimensions the device supports to determine if"); +        pw.println("            the activity can be shown in multi window."); +        pw.println("  get-multi-window-config"); +        pw.println("    Prints values of the multi window config options."); +        pw.println("  reset-multi-window-config"); +        pw.println("    Resets overrides to default values of the multi window config options."); +    }  } diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java index bac1ab1264ab..26cfbdf80681 100644 --- a/services/core/java/com/android/server/wm/WindowProcessController.java +++ b/services/core/java/com/android/server/wm/WindowProcessController.java @@ -18,6 +18,7 @@ package com.android.server.wm;  import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;  import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; +import static android.content.res.Configuration.ASSETS_SEQ_UNDEFINED;  import static android.os.Build.VERSION_CODES.Q;  import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS; @@ -1318,6 +1319,11 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio      @Override      void resolveOverrideConfiguration(Configuration newParentConfig) { +        final Configuration requestedOverrideConfig = getRequestedOverrideConfiguration(); +        if (requestedOverrideConfig.assetsSeq != ASSETS_SEQ_UNDEFINED +                && newParentConfig.assetsSeq > requestedOverrideConfig.assetsSeq) { +            requestedOverrideConfig.assetsSeq = ASSETS_SEQ_UNDEFINED; +        }          super.resolveOverrideConfiguration(newParentConfig);          final Configuration resolvedConfig = getResolvedOverrideConfiguration();          // Make sure that we don't accidentally override the activity type. @@ -1396,6 +1402,28 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio          return mHasPendingConfigurationChange;      } +    void updateAssetConfiguration(int assetSeq) { +        // Update the process override configuration directly if the process configuration will +        // not be override from its activities. +        if (!mHasActivities || !mIsActivityConfigOverrideAllowed) { +            Configuration overrideConfig = new Configuration(getRequestedOverrideConfiguration()); +            overrideConfig.assetsSeq = assetSeq; +            onRequestedOverrideConfigurationChanged(overrideConfig); +            return; +        } + +        // Otherwise, we can just update the activity override configuration. +        for (int i = mActivities.size() - 1; i >= 0; i--) { +            ActivityRecord r = mActivities.get(i); +            Configuration overrideConfig = new Configuration(r.getRequestedOverrideConfiguration()); +            overrideConfig.assetsSeq = assetSeq; +            r.onRequestedOverrideConfigurationChanged(overrideConfig); +            if (r.mVisibleRequested) { +                r.ensureActivityConfiguration(0, true); +            } +        } +    } +      /**       * This is called for sending {@link android.app.servertransaction.LaunchActivityItem}.       * The caller must call {@link #setLastReportedConfiguration} if the delivered configuration diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 074eeb942377..9de50585bf67 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -7244,6 +7244,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {          Objects.requireNonNull(who, "ComponentName is null");          final CallerIdentity caller = getCallerIdentity(who);          Preconditions.checkCallAuthorization(isDeviceOwner(caller)); +        checkAllUsersAreAffiliatedWithDevice();          mInjector.binderWithCleanCallingIdentity(                  () -> mInjector.getConnectivityManager().setGlobalProxy(proxyInfo));      } @@ -15736,6 +15737,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {          Objects.requireNonNull(who, "ComponentName is null");          final CallerIdentity caller = getCallerIdentity(who);          Preconditions.checkCallAuthorization(isDeviceOwner(caller)); +        checkAllUsersAreAffiliatedWithDevice();          checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_GLOBAL_PRIVATE_DNS);          switch (mode) { diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp index f3e7d672ec95..26efbc95eedd 100644 --- a/services/incremental/IncrementalService.cpp +++ b/services/incremental/IncrementalService.cpp @@ -269,7 +269,10 @@ auto IncrementalService::IncFsMount::makeStorage(StorageId id) -> StorageMap::it  template <class Func>  static auto makeCleanup(Func&& f) requires(!std::is_lvalue_reference_v<Func>) { -    auto deleter = [f = std::move(f)](auto) { f(); }; +    // ok to move a 'forwarding' reference here as lvalues are disabled anyway +    auto deleter = [f = std::move(f)](auto) { // NOLINT +        f(); +    };      // &f is a dangling pointer here, but we actually never use it as deleter moves it in.      return std::unique_ptr<Func, decltype(deleter)>(&f, std::move(deleter));  } @@ -391,12 +394,20 @@ static const char* toString(IncrementalService::BindKind kind) {  }  template <class Duration> -static long elapsedMcs(Duration start, Duration end) { +static int64_t elapsedMcs(Duration start, Duration end) {      return std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();  } +int64_t IncrementalService::elapsedUsSinceMonoTs(uint64_t monoTsUs) { +    const auto now = mClock->now(); +    const auto nowUs = static_cast<uint64_t>( +            duration_cast<std::chrono::microseconds>(now.time_since_epoch()).count()); +    return nowUs - monoTsUs; +} +  void IncrementalService::onDump(int fd) {      dprintf(fd, "Incremental is %s\n", incfs::enabled() ? "ENABLED" : "DISABLED"); +    dprintf(fd, "IncFs features: 0x%x\n", int(mIncFs->features()));      dprintf(fd, "Incremental dir: %s\n", mIncrementalDir.c_str());      std::unique_lock l(mLock); @@ -411,6 +422,8 @@ void IncrementalService::onDump(int fd) {          } else {              dprintf(fd, "    mountId: %d\n", mnt.mountId);              dprintf(fd, "    root: %s\n", mnt.root.c_str()); +            const auto metricsInstanceName = path::basename(ifs->root); +            dprintf(fd, "    metrics instance name: %s\n", path::c_str(metricsInstanceName).get());              dprintf(fd, "    nextStorageDirNo: %d\n", mnt.nextStorageDirNo.load());              dprintf(fd, "    flags: %d\n", int(mnt.flags));              if (mnt.startLoadingTs.time_since_epoch() == Clock::duration::zero()) { @@ -440,6 +453,45 @@ void IncrementalService::onDump(int fd) {                  dprintf(fd, "        kind: %s\n", toString(bind.kind));              }              dprintf(fd, "    }\n"); + +            dprintf(fd, "    incfsMetrics: {\n"); +            const auto incfsMetrics = mIncFs->getMetrics(metricsInstanceName); +            if (incfsMetrics) { +                dprintf(fd, "      readsDelayedMin: %d\n", incfsMetrics.value().readsDelayedMin); +                dprintf(fd, "      readsDelayedMinUs: %lld\n", +                        (long long)incfsMetrics.value().readsDelayedMinUs); +                dprintf(fd, "      readsDelayedPending: %d\n", +                        incfsMetrics.value().readsDelayedPending); +                dprintf(fd, "      readsDelayedPendingUs: %lld\n", +                        (long long)incfsMetrics.value().readsDelayedPendingUs); +                dprintf(fd, "      readsFailedHashVerification: %d\n", +                        incfsMetrics.value().readsFailedHashVerification); +                dprintf(fd, "      readsFailedOther: %d\n", incfsMetrics.value().readsFailedOther); +                dprintf(fd, "      readsFailedTimedOut: %d\n", +                        incfsMetrics.value().readsFailedTimedOut); +            } else { +                dprintf(fd, "      Metrics not available. Errno: %d\n", errno); +            } +            dprintf(fd, "    }\n"); + +            const auto lastReadError = mIncFs->getLastReadError(ifs->control); +            const auto errorNo = errno; +            dprintf(fd, "    lastReadError: {\n"); +            if (lastReadError) { +                if (lastReadError->timestampUs == 0) { +                    dprintf(fd, "      No read errors.\n"); +                } else { +                    dprintf(fd, "      fileId: %s\n", +                            IncFsWrapper::toString(lastReadError->id).c_str()); +                    dprintf(fd, "      time: %llu microseconds ago\n", +                            (unsigned long long)elapsedUsSinceMonoTs(lastReadError->timestampUs)); +                    dprintf(fd, "      blockIndex: %d\n", lastReadError->block); +                    dprintf(fd, "      errno: %d\n", lastReadError->errorNo); +                } +            } else { +                dprintf(fd, "      Info not available. Errno: %d\n", errorNo); +            } +            dprintf(fd, "    }\n");          }          dprintf(fd, "  }\n");      } @@ -578,7 +630,7 @@ StorageId IncrementalService::createStorage(std::string_view mountPoint,          if (!mkdirOrLog(path::join(backing, ".incomplete"), 0777)) {              return kInvalidStorageId;          } -        auto status = mVold->mountIncFs(backing, mountTarget, 0, &controlParcel); +        auto status = mVold->mountIncFs(backing, mountTarget, 0, mountKey, &controlParcel);          if (!status.isOk()) {              LOG(ERROR) << "Vold::mountIncFs() failed: " << status.toString8();              return kInvalidStorageId; @@ -1586,9 +1638,10 @@ void IncrementalService::mountExistingImages(  bool IncrementalService::mountExistingImage(std::string_view root) {      auto mountTarget = path::join(root, constants().mount);      const auto backing = path::join(root, constants().backing); +    std::string mountKey(path::basename(path::dirname(mountTarget)));      IncrementalFileSystemControlParcel controlParcel; -    auto status = mVold->mountIncFs(backing, mountTarget, 0, &controlParcel); +    auto status = mVold->mountIncFs(backing, mountTarget, 0, mountKey, &controlParcel);      if (!status.isOk()) {          LOG(ERROR) << "Vold::mountIncFs() failed: " << status.toString8();          return false; @@ -2399,10 +2452,37 @@ void IncrementalService::getMetrics(StorageId storageId, android::os::Persistabl          LOG(ERROR) << "getMetrics failed, invalid storageId: " << storageId;          return;      } -    const auto kMetricsReadLogsEnabled = +    const auto& kMetricsReadLogsEnabled =              os::incremental::BnIncrementalService::METRICS_READ_LOGS_ENABLED(); -    result->putBoolean(String16(kMetricsReadLogsEnabled.data()), ifs->readLogsEnabled() != 0); - +    result->putBoolean(String16(kMetricsReadLogsEnabled.c_str()), ifs->readLogsEnabled() != 0); +    const auto incfsMetrics = mIncFs->getMetrics(path::basename(ifs->root)); +    if (incfsMetrics) { +        const auto& kMetricsTotalDelayedReads = +                os::incremental::BnIncrementalService::METRICS_TOTAL_DELAYED_READS(); +        const auto totalDelayedReads = +                incfsMetrics->readsDelayedMin + incfsMetrics->readsDelayedPending; +        result->putInt(String16(kMetricsTotalDelayedReads.c_str()), totalDelayedReads); +        const auto& kMetricsTotalFailedReads = +                os::incremental::BnIncrementalService::METRICS_TOTAL_FAILED_READS(); +        const auto totalFailedReads = incfsMetrics->readsFailedTimedOut + +                incfsMetrics->readsFailedHashVerification + incfsMetrics->readsFailedOther; +        result->putInt(String16(kMetricsTotalFailedReads.c_str()), totalFailedReads); +        const auto& kMetricsTotalDelayedReadsMillis = +                os::incremental::BnIncrementalService::METRICS_TOTAL_DELAYED_READS_MILLIS(); +        const int64_t totalDelayedReadsMillis = +                (incfsMetrics->readsDelayedMinUs + incfsMetrics->readsDelayedPendingUs) / 1000; +        result->putLong(String16(kMetricsTotalDelayedReadsMillis.c_str()), totalDelayedReadsMillis); +    } +    const auto lastReadError = mIncFs->getLastReadError(ifs->control); +    if (lastReadError && lastReadError->timestampUs != 0) { +        const auto& kMetricsMillisSinceLastReadError = +                os::incremental::BnIncrementalService::METRICS_MILLIS_SINCE_LAST_READ_ERROR(); +        result->putLong(String16(kMetricsMillisSinceLastReadError.c_str()), +                        (int64_t)elapsedUsSinceMonoTs(lastReadError->timestampUs) / 1000); +        const auto& kMetricsLastReadErrorNo = +                os::incremental::BnIncrementalService::METRICS_LAST_READ_ERROR_NUMBER(); +        result->putInt(String16(kMetricsLastReadErrorNo.c_str()), lastReadError->errorNo); +    }      std::unique_lock l(ifs->lock);      if (!ifs->dataLoaderStub) {          return; @@ -2562,7 +2642,9 @@ std::optional<Milliseconds> IncrementalService::DataLoaderStub::needToBind() {                       maxBindDelayMs)                      .count();      const auto bindDelayJitterRangeMs = bindDelayMs / Constants::bindDelayJitterDivider; -    const auto bindDelayJitterMs = rand() % (bindDelayJitterRangeMs * 2) - bindDelayJitterRangeMs; +    // rand() is enough, not worth maintaining a full-blown <rand> object for delay jitter +    const auto bindDelayJitterMs = rand() % (bindDelayJitterRangeMs * 2) - // NOLINT +            bindDelayJitterRangeMs;      mPreviousBindDelay = std::chrono::milliseconds(bindDelayMs + bindDelayJitterMs);      return mPreviousBindDelay;  } @@ -2947,24 +3029,24 @@ BootClockTsUs IncrementalService::DataLoaderStub::getOldestTsFromLastPendingRead  void IncrementalService::DataLoaderStub::getMetrics(android::os::PersistableBundle* result) {      const auto duration = elapsedMsSinceOldestPendingRead();      if (duration >= 0) { -        const auto kMetricsMillisSinceOldestPendingRead = +        const auto& kMetricsMillisSinceOldestPendingRead =                  os::incremental::BnIncrementalService::METRICS_MILLIS_SINCE_OLDEST_PENDING_READ(); -        result->putLong(String16(kMetricsMillisSinceOldestPendingRead.data()), duration); +        result->putLong(String16(kMetricsMillisSinceOldestPendingRead.c_str()), duration);      } -    const auto kMetricsStorageHealthStatusCode = +    const auto& kMetricsStorageHealthStatusCode =              os::incremental::BnIncrementalService::METRICS_STORAGE_HEALTH_STATUS_CODE(); -    result->putInt(String16(kMetricsStorageHealthStatusCode.data()), mHealthStatus); -    const auto kMetricsDataLoaderStatusCode = +    result->putInt(String16(kMetricsStorageHealthStatusCode.c_str()), mHealthStatus); +    const auto& kMetricsDataLoaderStatusCode =              os::incremental::BnIncrementalService::METRICS_DATA_LOADER_STATUS_CODE(); -    result->putInt(String16(kMetricsDataLoaderStatusCode.data()), mCurrentStatus); -    const auto kMetricsMillisSinceLastDataLoaderBind = +    result->putInt(String16(kMetricsDataLoaderStatusCode.c_str()), mCurrentStatus); +    const auto& kMetricsMillisSinceLastDataLoaderBind =              os::incremental::BnIncrementalService::METRICS_MILLIS_SINCE_LAST_DATA_LOADER_BIND(); -    result->putLong(String16(kMetricsMillisSinceLastDataLoaderBind.data()), -                    (long)(elapsedMcs(mPreviousBindTs, mService.mClock->now()) / 1000)); -    const auto kMetricsDataLoaderBindDelayMillis = +    result->putLong(String16(kMetricsMillisSinceLastDataLoaderBind.c_str()), +                    elapsedMcs(mPreviousBindTs, mService.mClock->now()) / 1000); +    const auto& kMetricsDataLoaderBindDelayMillis =              os::incremental::BnIncrementalService::METRICS_DATA_LOADER_BIND_DELAY_MILLIS(); -    result->putLong(String16(kMetricsDataLoaderBindDelayMillis.data()), -                    (long)(mPreviousBindDelay.count())); +    result->putLong(String16(kMetricsDataLoaderBindDelayMillis.c_str()), +                    mPreviousBindDelay.count());  }  long IncrementalService::DataLoaderStub::elapsedMsSinceOldestPendingRead() { diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h index 8dc789f4a328..a8434afe29ba 100644 --- a/services/incremental/IncrementalService.h +++ b/services/incremental/IncrementalService.h @@ -472,6 +472,7 @@ private:                                 StorageLoadingProgressListener&& progressListener);      void trimReservedSpaceV1(const IncFsMount& ifs); +    int64_t elapsedUsSinceMonoTs(uint64_t monoTsUs);  private:      const std::unique_ptr<VoldServiceWrapper> mVold; diff --git a/services/incremental/ServiceWrappers.cpp b/services/incremental/ServiceWrappers.cpp index 0755a22ab2ea..68a28b25b2a4 100644 --- a/services/incremental/ServiceWrappers.cpp +++ b/services/incremental/ServiceWrappers.cpp @@ -43,8 +43,9 @@ public:      ~RealVoldService() = default;      binder::Status mountIncFs(              const std::string& backingPath, const std::string& targetDir, int32_t flags, +            const std::string& sysfsName,              os::incremental::IncrementalFileSystemControlParcel* _aidl_return) const final { -        return mInterface->mountIncFs(backingPath, targetDir, flags, _aidl_return); +        return mInterface->mountIncFs(backingPath, targetDir, flags, sysfsName, _aidl_return);      }      binder::Status unmountIncFs(const std::string& dir) const final {          return mInterface->unmountIncFs(dir); @@ -261,6 +262,12 @@ public:              return cb(control, id);          });      } +    std::optional<Metrics> getMetrics(std::string_view sysfsName) const final { +        return incfs::getMetrics(sysfsName); +    } +    std::optional<LastReadError> getLastReadError(const Control& control) const final { +        return incfs::getLastReadError(control); +    }  };  static JNIEnv* getOrAttachJniEnv(JavaVM* jvm); diff --git a/services/incremental/ServiceWrappers.h b/services/incremental/ServiceWrappers.h index 78e9589e63ff..c0ef7ba5c85b 100644 --- a/services/incremental/ServiceWrappers.h +++ b/services/incremental/ServiceWrappers.h @@ -51,6 +51,7 @@ public:      virtual ~VoldServiceWrapper() = default;      virtual binder::Status mountIncFs(              const std::string& backingPath, const std::string& targetDir, int32_t flags, +            const std::string& sysfsName,              os::incremental::IncrementalFileSystemControlParcel* result) const = 0;      virtual binder::Status unmountIncFs(const std::string& dir) const = 0;      virtual binder::Status bindMount(const std::string& sourceDir, @@ -79,6 +80,8 @@ public:      using UniqueFd = incfs::UniqueFd;      using WaitResult = incfs::WaitResult;      using Features = incfs::Features; +    using Metrics = incfs::Metrics; +    using LastReadError = incfs::LastReadError;      using ExistingMountCallback = android::base::function_ref<              void(std::string_view root, std::string_view backingDir, @@ -124,6 +127,8 @@ public:              const = 0;      virtual ErrorCode forEachFile(const Control& control, FileCallback cb) const = 0;      virtual ErrorCode forEachIncompleteFile(const Control& control, FileCallback cb) const = 0; +    virtual std::optional<Metrics> getMetrics(std::string_view sysfsName) const = 0; +    virtual std::optional<LastReadError> getLastReadError(const Control& control) const = 0;  };  class AppOpsManagerWrapper { diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp index 68586a89ff07..6c9310bbf052 100644 --- a/services/incremental/test/IncrementalServiceTest.cpp +++ b/services/incremental/test/IncrementalServiceTest.cpp @@ -49,9 +49,9 @@ namespace android::os::incremental {  class MockVoldService : public VoldServiceWrapper {  public: -    MOCK_CONST_METHOD4(mountIncFs, +    MOCK_CONST_METHOD5(mountIncFs,                         binder::Status(const std::string& backingPath, const std::string& targetDir, -                                      int32_t flags, +                                      int32_t flags, const std::string& sysfsName,                                        IncrementalFileSystemControlParcel* _aidl_return));      MOCK_CONST_METHOD1(unmountIncFs, binder::Status(const std::string& dir));      MOCK_CONST_METHOD2(bindMount, @@ -62,16 +62,16 @@ public:                             bool, bool));      void mountIncFsFails() { -        ON_CALL(*this, mountIncFs(_, _, _, _)) +        ON_CALL(*this, mountIncFs(_, _, _, _, _))                  .WillByDefault(                          Return(binder::Status::fromExceptionCode(1, String8("failed to mount"))));      }      void mountIncFsInvalidControlParcel() { -        ON_CALL(*this, mountIncFs(_, _, _, _)) +        ON_CALL(*this, mountIncFs(_, _, _, _, _))                  .WillByDefault(Invoke(this, &MockVoldService::getInvalidControlParcel));      }      void mountIncFsSuccess() { -        ON_CALL(*this, mountIncFs(_, _, _, _)) +        ON_CALL(*this, mountIncFs(_, _, _, _, _))                  .WillByDefault(Invoke(this, &MockVoldService::incFsSuccess));      }      void bindMountFails() { @@ -93,12 +93,14 @@ public:      }      binder::Status getInvalidControlParcel(const std::string& imagePath,                                             const std::string& targetDir, int32_t flags, +                                           const std::string& sysfsName,                                             IncrementalFileSystemControlParcel* _aidl_return) {          _aidl_return = {};          return binder::Status::ok();      }      binder::Status incFsSuccess(const std::string& imagePath, const std::string& targetDir, -                                int32_t flags, IncrementalFileSystemControlParcel* _aidl_return) { +                                int32_t flags, const std::string& sysfsName, +                                IncrementalFileSystemControlParcel* _aidl_return) {          _aidl_return->pendingReads.reset(base::unique_fd(dup(STDIN_FILENO)));          _aidl_return->cmd.reset(base::unique_fd(dup(STDIN_FILENO)));          _aidl_return->log.reset(base::unique_fd(dup(STDIN_FILENO))); @@ -414,6 +416,8 @@ public:                                   const std::vector<PerUidReadTimeouts>& perUidReadTimeouts));      MOCK_CONST_METHOD2(forEachFile, ErrorCode(const Control& control, FileCallback cb));      MOCK_CONST_METHOD2(forEachIncompleteFile, ErrorCode(const Control& control, FileCallback cb)); +    MOCK_CONST_METHOD1(getMetrics, std::optional<Metrics>(std::string_view path)); +    MOCK_CONST_METHOD1(getLastReadError, std::optional<LastReadError>(const Control& control));      MockIncFs() {          ON_CALL(*this, listExistingMounts(_)).WillByDefault(Return()); @@ -631,6 +635,14 @@ public:      void advanceMs(int deltaMs) { mClock += std::chrono::milliseconds(deltaMs); }      TimePoint getClock() const { return mClock; } +    std::optional<timespec> getClockMono() const { +        const auto nsSinceEpoch = +                std::chrono::duration_cast<std::chrono::nanoseconds>(mClock.time_since_epoch()) +                        .count(); +        timespec ts = {.tv_sec = static_cast<time_t>(nsSinceEpoch / 1000000000LL), +                       .tv_nsec = static_cast<long>(nsSinceEpoch % 1000000000LL)}; +        return ts; +    }      TimePoint mClock = Clock::now();  }; @@ -2199,4 +2211,89 @@ TEST_F(IncrementalServiceTest, testInvalidMetricsKeys) {      ASSERT_EQ(6, (int)result.size());  } +TEST_F(IncrementalServiceTest, testMetricsWithNoLastReadError) { +    mVold->setIncFsMountOptionsSuccess(); +    ON_CALL(*mIncFs, getMetrics(_)) +            .WillByDefault(Return(Metrics{ +                    .readsDelayedMin = 10, +                    .readsDelayedMinUs = 5000, +                    .readsDelayedPending = 10, +                    .readsDelayedPendingUs = 5000, +                    .readsFailedHashVerification = 10, +                    .readsFailedOther = 10, +                    .readsFailedTimedOut = 10, +            })); +    ON_CALL(*mIncFs, getLastReadError(_)).WillByDefault(Return(LastReadError{})); +    TemporaryDir tempDir; +    int storageId = +            mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel, +                                               IncrementalService::CreateOptions::CreateNew); +    ASSERT_GE(storageId, 0); +    ASSERT_TRUE(mIncrementalService->startLoading(storageId, std::move(mDataLoaderParcel), {}, {}, +                                                  {}, {})); +    android::os::PersistableBundle result{}; +    mIncrementalService->getMetrics(storageId, &result); +    ASSERT_EQ(9, (int)result.size()); + +    int expectedtotalDelayedReads = 20, totalDelayedReads = -1; +    ASSERT_TRUE(result.getInt(String16(BnIncrementalService::METRICS_TOTAL_DELAYED_READS().c_str()), +                              &totalDelayedReads)); +    ASSERT_EQ(expectedtotalDelayedReads, totalDelayedReads); +    int expectedtotalFailedReads = 30, totalFailedReads = -1; +    ASSERT_TRUE(result.getInt(String16(BnIncrementalService::METRICS_TOTAL_FAILED_READS().c_str()), +                              &totalFailedReads)); +    ASSERT_EQ(expectedtotalFailedReads, totalFailedReads); +    int64_t expectedtotalDelayedReadsMillis = 10, totalDelayedReadsMillis = -1; +    ASSERT_TRUE(result.getLong(String16(BnIncrementalService::METRICS_TOTAL_DELAYED_READS_MILLIS() +                                                .c_str()), +                               &totalDelayedReadsMillis)); +    ASSERT_EQ(expectedtotalDelayedReadsMillis, totalDelayedReadsMillis); + +    int64_t expectedMillisSinceLastReadError = -1, millisSinceLastReadError = -1; +    ASSERT_FALSE( +            result.getLong(String16(BnIncrementalService::METRICS_MILLIS_SINCE_LAST_READ_ERROR() +                                            .c_str()), +                           &millisSinceLastReadError)); +    ASSERT_EQ(expectedMillisSinceLastReadError, millisSinceLastReadError); +    int expectedLastReadErrorNumber = -1, lastReadErrorNumber = -1; +    ASSERT_FALSE( +            result.getInt(String16(BnIncrementalService::METRICS_LAST_READ_ERROR_NUMBER().c_str()), +                          &lastReadErrorNumber)); +    ASSERT_EQ(expectedLastReadErrorNumber, lastReadErrorNumber); +} + +TEST_F(IncrementalServiceTest, testMetricsWithLastReadError) { +    mVold->setIncFsMountOptionsSuccess(); +    ON_CALL(*mIncFs, getMetrics(_)).WillByDefault(Return(Metrics{})); +    mClock->advanceMs(5); +    const auto now = mClock->getClock(); +    ON_CALL(*mIncFs, getLastReadError(_)) +            .WillByDefault(Return(LastReadError{.timestampUs = static_cast<uint64_t>( +                                                        duration_cast<std::chrono::microseconds>( +                                                                now.time_since_epoch()) +                                                                .count()), +                                                .errorNo = static_cast<uint32_t>(-ETIME)})); +    TemporaryDir tempDir; +    int storageId = +            mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel, +                                               IncrementalService::CreateOptions::CreateNew); +    ASSERT_GE(storageId, 0); +    ASSERT_TRUE(mIncrementalService->startLoading(storageId, std::move(mDataLoaderParcel), {}, {}, +                                                  {}, {})); +    mClock->advanceMs(10); +    android::os::PersistableBundle result{}; +    mIncrementalService->getMetrics(storageId, &result); +    ASSERT_EQ(11, (int)result.size()); +    int64_t expectedMillisSinceLastReadError = 10, millisSinceLastReadError = -1; +    ASSERT_TRUE(result.getLong(String16(BnIncrementalService::METRICS_MILLIS_SINCE_LAST_READ_ERROR() +                                                .c_str()), +                               &millisSinceLastReadError)); +    ASSERT_EQ(expectedMillisSinceLastReadError, millisSinceLastReadError); +    int expectedLastReadErrorNumber = -ETIME, lastReadErrorNumber = -1; +    ASSERT_TRUE( +            result.getInt(String16(BnIncrementalService::METRICS_LAST_READ_ERROR_NUMBER().c_str()), +                          &lastReadErrorNumber)); +    ASSERT_EQ(expectedLastReadErrorNumber, lastReadErrorNumber); +} +  } // namespace android::os::incremental diff --git a/services/net/Android.bp b/services/net/Android.bp index 800f7addbd65..f92db86bb880 100644 --- a/services/net/Android.bp +++ b/services/net/Android.bp @@ -52,7 +52,8 @@ java_library {      libs: [          "unsupportedappusage",          "framework-wifi-util-lib", -        "framework-connectivity" +        "framework-connectivity", +        "modules-utils-build_system",      ],      static_libs: [          // All the classes in netd_aidl_interface must be jarjar so they do not conflict with the @@ -60,6 +61,7 @@ java_library {          "netd_aidl_interface-V3-java",          "netlink-client",          "networkstack-client", +        "modules-utils-build_system",      ],      apex_available: [          "com.android.wifi", @@ -80,7 +82,7 @@ filegroup {      ],      visibility: [          "//frameworks/base/packages/Tethering", -        "//packages/modules/Connectivity/Tethering" +        "//packages/modules/Connectivity/Tethering",      ],  } diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/install/RequestThrottleTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/install/RequestThrottleTest.kt new file mode 100644 index 000000000000..2196ef74d6a4 --- /dev/null +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/install/RequestThrottleTest.kt @@ -0,0 +1,219 @@ +/* + * 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.pm.test.install + +import com.android.server.pm.utils.RequestThrottle +import com.android.server.testutils.TestHandler +import com.google.common.collect.Range +import com.google.common.truth.LongSubject +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import java.util.concurrent.CountDownLatch +import java.util.concurrent.CyclicBarrier +import java.util.concurrent.TimeUnit +import java.util.concurrent.atomic.AtomicBoolean +import java.util.concurrent.atomic.AtomicInteger +import java.util.concurrent.atomic.AtomicLong + +class RequestThrottleTest { + +    private val counter = AtomicInteger(0) + +    private val handler = TestHandler(null) + +    @Before +    fun resetValues() { +        handler.flush() +        counter.set(0) +        assertThat(counter.get()).isEqualTo(0) +    } + +    @Test +    fun simpleThrottle() { +        val request = RequestThrottle(handler) { +            counter.incrementAndGet() +            true +        } + +        fun sendRequests() { +            request.schedule() +            val thread = startThread { request.schedule() } +            request.schedule() +            thread.joinForTest() +        } + +        sendRequests() +        handler.flush() +        assertThat(counter.get()).isEqualTo(1) + +        sendRequests() +        handler.flush() +        assertThat(counter.get()).isEqualTo(2) +    } + +    @Test +    fun exceptionInRequest() { +        val shouldThrow = AtomicBoolean(true) +        val request = RequestThrottle(handler) { +            if (shouldThrow.get()) { +                throw RuntimeException() +            } +            counter.incrementAndGet() +            true +        } + +        fun sendRequests() { +            request.schedule() +            val thread = startThread { request.schedule() } +            request.schedule() +            thread.joinForTest() +        } + +        sendRequests() +        try { +            handler.flush() +        } catch (ignored: Exception) { +        } +        assertThat(counter.get()).isEqualTo(0) + +        shouldThrow.set(false) + +        sendRequests() +        handler.flush() +        assertThat(counter.get()).isEqualTo(1) +    } + +    @Test +    fun scheduleWhileRunning() { +        val latchForStartRequest = CountDownLatch(1) +        val latchForEndRequest = CountDownLatch(1) +        val request = RequestThrottle(handler) { +            latchForStartRequest.countDown() +            counter.incrementAndGet() +            latchForEndRequest.awaitForTest() +            true +        } + +        // Schedule and block a request +        request.schedule() +        val handlerThread = startThread { handler.timeAdvance() } +        latchForStartRequest.awaitForTest() + +        // Hit it with other requests +        request.schedule() +        (0..5).map { startThread { request.schedule() } } +                .forEach { it.joinForTest() } + +        // Release everything +        latchForEndRequest.countDown() +        handlerThread.join() +        handler.flush() + +        // Ensure another request was run after initial blocking request ends +        assertThat(counter.get()).isEqualTo(2) +    } + +    @Test +    fun backoffRetry() { +        val time = AtomicLong(0) +        val handler = TestHandler(null) { time.get() } +        val returnValue = AtomicBoolean(false) +        val request = RequestThrottle(handler, 3, 1000, 2) { +            counter.incrementAndGet() +            returnValue.get() +        } + +        request.schedule() + +        handler.timeAdvance() +        handler.pendingMessages.apply { +            assertThat(size).isEqualTo(1) +            assertThat(single().sendTime).isAround(1000) +        } + +        time.set(1000) +        handler.timeAdvance() +        handler.pendingMessages.apply { +            assertThat(size).isEqualTo(1) +            assertThat(single().sendTime).isAround(3000) +        } + +        time.set(3000) +        handler.timeAdvance() +        handler.pendingMessages.apply { +            assertThat(size).isEqualTo(1) +            assertThat(single().sendTime).isAround(7000) +        } + +        returnValue.set(true) +        time.set(7000) +        handler.timeAdvance() +        assertThat(handler.pendingMessages).isEmpty() + +        // Ensure another request was run after initial blocking request ends +        assertThat(counter.get()).isEqualTo(4) +    } + +    @Test +    fun forceWriteMultiple() { +        val request = RequestThrottle(handler) { +            counter.incrementAndGet() +            true +        } + +        request.runNow() +        request.runNow() +        request.runNow() + +        assertThat(counter.get()).isEqualTo(3) +    } + +    @Test +    fun forceWriteNowWithoutSync() { +        // When forcing a write without synchronizing the request block, 2 instances will be run. +        // There is no test for "with sync" because any logic to avoid multiple runs is left +        // entirely up to the caller. + +        val barrierForEndRequest = CyclicBarrier(2) +        val request = RequestThrottle(handler) { +            counter.incrementAndGet() +            barrierForEndRequest.awaitForTest() +            true +        } + +        // Schedule and block a request +        request.schedule() +        val thread = startThread { handler.timeAdvance() } + +        request.runNow() + +        thread.joinForTest() + +        assertThat(counter.get()).isEqualTo(2) +    } + +    private fun CountDownLatch.awaitForTest() = assertThat(await(5, TimeUnit.SECONDS)).isTrue() +    private fun CyclicBarrier.awaitForTest() = await(5, TimeUnit.SECONDS) +    private fun Thread.joinForTest() = join(5000) + +    private fun startThread(block: () -> Unit) = Thread { block() }.apply { start() } + +    // Float math means time calculations are not exact, so use a loose range +    private fun LongSubject.isAround(value: Long, threshold: Long = 10) = +            isIn(Range.closed(value - threshold, value + threshold)) +} diff --git a/services/tests/mockingservicestests/assets/SensorPrivacyServiceMockingTest/OWNERS b/services/tests/mockingservicestests/assets/SensorPrivacyServiceMockingTest/OWNERS new file mode 100644 index 000000000000..c74393b102a8 --- /dev/null +++ b/services/tests/mockingservicestests/assets/SensorPrivacyServiceMockingTest/OWNERS @@ -0,0 +1,3 @@ +# Bug component: 137825 + +file:platform/frameworks/native:/libs/sensorprivacy/OWNERS diff --git a/services/tests/mockingservicestests/assets/SensorPrivacyServiceMockingTest/persisted_file1.xml b/services/tests/mockingservicestests/assets/SensorPrivacyServiceMockingTest/persisted_file1.xml new file mode 100644 index 000000000000..a4de08a85487 --- /dev/null +++ b/services/tests/mockingservicestests/assets/SensorPrivacyServiceMockingTest/persisted_file1.xml @@ -0,0 +1,7 @@ +<?xml version='1.0' encoding='UTF-8' standalone='yes' ?> +<sensor-privacy persistence-version="1" version="1"> +    <user id="0" enabled="false"> +        <individual-sensor-privacy sensor="1" enabled="true" /> +        <individual-sensor-privacy sensor="2" enabled="true" /> +    </user> +</sensor-privacy> diff --git a/services/tests/mockingservicestests/assets/SensorPrivacyServiceMockingTest/persisted_file2.xml b/services/tests/mockingservicestests/assets/SensorPrivacyServiceMockingTest/persisted_file2.xml new file mode 100644 index 000000000000..361075eba7da --- /dev/null +++ b/services/tests/mockingservicestests/assets/SensorPrivacyServiceMockingTest/persisted_file2.xml @@ -0,0 +1,16 @@ +<?xml version='1.0' encoding='UTF-8' standalone='yes' ?> +<sensor-privacy persistence-version="1" version="1"> +    <user id="0" enabled="false"> +        <individual-sensor-privacy sensor="1" enabled="true" /> +        <individual-sensor-privacy sensor="2" enabled="true" /> +    </user> +    <user id="10" enabled="false"> +        <individual-sensor-privacy sensor="1" enabled="true" /> +        <individual-sensor-privacy sensor="2" enabled="false" /> +    </user> +    <user id="11" enabled="false"> +    </user> +    <user id="12" enabled="false"> +        <individual-sensor-privacy sensor="1" enabled="true" /> +    </user> +</sensor-privacy> diff --git a/services/tests/mockingservicestests/assets/SensorPrivacyServiceMockingTest/persisted_file3.xml b/services/tests/mockingservicestests/assets/SensorPrivacyServiceMockingTest/persisted_file3.xml new file mode 100644 index 000000000000..e8f9edfde2d7 --- /dev/null +++ b/services/tests/mockingservicestests/assets/SensorPrivacyServiceMockingTest/persisted_file3.xml @@ -0,0 +1,7 @@ +<?xml version='1.0' encoding='UTF-8' standalone='yes' ?> +<sensor-privacy persistence-version="1" version="1"> +    <user id="0" enabled="false"> +        <individual-sensor-privacy sensor="1" enabled="false" /> +        <individual-sensor-privacy sensor="2" enabled="false" /> +    </user> +</sensor-privacy> diff --git a/services/tests/mockingservicestests/assets/SensorPrivacyServiceMockingTest/persisted_file4.xml b/services/tests/mockingservicestests/assets/SensorPrivacyServiceMockingTest/persisted_file4.xml new file mode 100644 index 000000000000..d26c27594773 --- /dev/null +++ b/services/tests/mockingservicestests/assets/SensorPrivacyServiceMockingTest/persisted_file4.xml @@ -0,0 +1,10 @@ +<?xml version='1.0' encoding='UTF-8' standalone='yes' ?> +<sensor-privacy persistence-version="1" version="1"> +    <user id="0" enabled="false"> +        <individual-sensor-privacy sensor="1" enabled="true" /> +        <individual-sensor-privacy sensor="2" enabled="false" /> +    </user> +    <user id="10" enabled="false"> +        <individual-sensor-privacy sensor="1" enabled="false" /> +    </user> +</sensor-privacy> diff --git a/services/tests/mockingservicestests/assets/SensorPrivacyServiceMockingTest/persisted_file5.xml b/services/tests/mockingservicestests/assets/SensorPrivacyServiceMockingTest/persisted_file5.xml new file mode 100644 index 000000000000..5c9d0cdccd1b --- /dev/null +++ b/services/tests/mockingservicestests/assets/SensorPrivacyServiceMockingTest/persisted_file5.xml @@ -0,0 +1,9 @@ +<?xml version='1.0' encoding='UTF-8' standalone='yes' ?> +<sensor-privacy persistence-version="1" version="1"> +    <user id="0" enabled="false"> +        <individual-sensor-privacy sensor="2" enabled="false" /> +    </user> +    <user id="10" enabled="false"> +        <individual-sensor-privacy sensor="2" enabled="false" /> +    </user> +</sensor-privacy> diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java index 64dad7f0feab..8382ff4cb506 100644 --- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java @@ -71,7 +71,9 @@ import static com.android.server.alarm.AlarmManagerService.Constants.KEY_CRASH_N  import static com.android.server.alarm.AlarmManagerService.Constants.KEY_EXACT_ALARM_DENY_LIST;  import static com.android.server.alarm.AlarmManagerService.Constants.KEY_LAZY_BATCHING;  import static com.android.server.alarm.AlarmManagerService.Constants.KEY_LISTENER_TIMEOUT; +import static com.android.server.alarm.AlarmManagerService.Constants.KEY_MAX_DEVICE_IDLE_FUZZ;  import static com.android.server.alarm.AlarmManagerService.Constants.KEY_MAX_INTERVAL; +import static com.android.server.alarm.AlarmManagerService.Constants.KEY_MIN_DEVICE_IDLE_FUZZ;  import static com.android.server.alarm.AlarmManagerService.Constants.KEY_MIN_FUTURITY;  import static com.android.server.alarm.AlarmManagerService.Constants.KEY_MIN_INTERVAL;  import static com.android.server.alarm.AlarmManagerService.Constants.KEY_MIN_WINDOW; @@ -654,6 +656,8 @@ public class AlarmManagerServiceTest {          setDeviceConfigLong(KEY_LISTENER_TIMEOUT, 45);          setDeviceConfigLong(KEY_MIN_WINDOW, 50);          setDeviceConfigLong(KEY_PRIORITY_ALARM_DELAY, 55); +        setDeviceConfigLong(KEY_MIN_DEVICE_IDLE_FUZZ, 60); +        setDeviceConfigLong(KEY_MAX_DEVICE_IDLE_FUZZ, 65);          assertEquals(5, mService.mConstants.MIN_FUTURITY);          assertEquals(10, mService.mConstants.MIN_INTERVAL);          assertEquals(15, mService.mConstants.MAX_INTERVAL); @@ -665,6 +669,8 @@ public class AlarmManagerServiceTest {          assertEquals(45, mService.mConstants.LISTENER_TIMEOUT);          assertEquals(50, mService.mConstants.MIN_WINDOW);          assertEquals(55, mService.mConstants.PRIORITY_ALARM_DELAY); +        assertEquals(60, mService.mConstants.MIN_DEVICE_IDLE_FUZZ); +        assertEquals(65, mService.mConstants.MAX_DEVICE_IDLE_FUZZ);      }      @Test @@ -737,6 +743,20 @@ public class AlarmManagerServiceTest {      }      @Test +    public void deviceIdleFuzzRangeNonNegative() { +        final long newMinFuzz = mService.mConstants.MAX_DEVICE_IDLE_FUZZ + 1542; +        final long newMaxFuzz = mService.mConstants.MIN_DEVICE_IDLE_FUZZ - 131; + +        setDeviceConfigLong(KEY_MIN_DEVICE_IDLE_FUZZ, newMinFuzz); +        assertTrue("Negative device-idle fuzz range", mService.mConstants.MAX_DEVICE_IDLE_FUZZ +                >= mService.mConstants.MIN_DEVICE_IDLE_FUZZ); + +        setDeviceConfigLong(KEY_MAX_DEVICE_IDLE_FUZZ, newMaxFuzz); +        assertTrue("Negative device-idle fuzz range", mService.mConstants.MAX_DEVICE_IDLE_FUZZ +                >= mService.mConstants.MIN_DEVICE_IDLE_FUZZ); +    } + +    @Test      public void testMinFuturity() {          setDeviceConfigLong(KEY_MIN_FUTURITY, 10L);          assertEquals(10, mService.mConstants.MIN_FUTURITY); @@ -1431,7 +1451,7 @@ public class AlarmManagerServiceTest {      @Test      public void singleIdleUntil() { -        doReturn(0).when(mService).fuzzForDuration(anyLong()); +        setDeviceConfigLong(KEY_MAX_DEVICE_IDLE_FUZZ, 0);          final PendingIntent idleUntilPi6 = getNewMockPendingIntent();          setIdleUntilAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 6, idleUntilPi6); @@ -1504,44 +1524,67 @@ public class AlarmManagerServiceTest {          assertNull(mService.mNextWakeFromIdle);      } +    private static void assertInRange(String message, long minIncl, long maxIncl, long val) { +        assertTrue(message, val >= minIncl && val <= maxIncl); +    } +      @Test -    public void idleUntilBeforeWakeFromIdle() { -        doReturn(0).when(mService).fuzzForDuration(anyLong()); +    public void idleUntilFuzzedBeforeWakeFromIdle() { +        final long minFuzz = 6; +        final long maxFuzz = 17; +        setDeviceConfigLong(KEY_MIN_DEVICE_IDLE_FUZZ, minFuzz); +        setDeviceConfigLong(KEY_MAX_DEVICE_IDLE_FUZZ, maxFuzz); + +        mNowElapsedTest = 119; // Arbitrary, just to ensure we are not testing on 0.          final PendingIntent idleUntilPi = getNewMockPendingIntent(); -        final long requestedIdleUntil = mNowElapsedTest + 10; +        final long requestedIdleUntil = mNowElapsedTest + 12;          setIdleUntilAlarm(ELAPSED_REALTIME_WAKEUP, requestedIdleUntil, idleUntilPi);          assertEquals(requestedIdleUntil, mService.mPendingIdleUntil.getWhenElapsed());          final PendingIntent wakeFromIdle5 = getNewMockPendingIntent();          setWakeFromIdle(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 5, wakeFromIdle5); -        assertEquals(mNowElapsedTest + 5, mService.mPendingIdleUntil.getWhenElapsed()); +        // Anything before now, gets snapped to now. It is not necessary for it to fire +        // immediately, just how it is implemented today for simplicity. +        assertEquals(mNowElapsedTest, mService.mPendingIdleUntil.getWhenElapsed());          final PendingIntent wakeFromIdle8 = getNewMockPendingIntent();          setWakeFromIdle(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 8, wakeFromIdle8); -        assertEquals(mNowElapsedTest + 5, mService.mPendingIdleUntil.getWhenElapsed()); +        // Next wake from idle is still the same. +        assertEquals(mNowElapsedTest, mService.mPendingIdleUntil.getWhenElapsed()); -        final PendingIntent wakeFromIdle12 = getNewMockPendingIntent(); -        setWakeFromIdle(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 12, wakeFromIdle12); -        assertEquals(mNowElapsedTest + 5, mService.mPendingIdleUntil.getWhenElapsed()); +        final PendingIntent wakeFromIdle19 = getNewMockPendingIntent(); +        setWakeFromIdle(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 19, wakeFromIdle19); +        // Next wake from idle is still the same. +        assertEquals(mNowElapsedTest, mService.mPendingIdleUntil.getWhenElapsed());          mService.removeLocked(wakeFromIdle5, null, REMOVE_REASON_UNDEFINED); -        assertEquals(mNowElapsedTest + 8, mService.mPendingIdleUntil.getWhenElapsed()); +        // Next wake from idle is at now + 8. +        long min = mNowElapsedTest; +        long max = mNowElapsedTest + 8 - minFuzz; +        assertInRange("Idle until alarm time not in expected range [" + min + ", " + max + "]", +                min, max, mService.mPendingIdleUntil.getWhenElapsed());          mService.removeLocked(wakeFromIdle8, null, REMOVE_REASON_UNDEFINED); +        // Next wake from idle is at now + 19, which is > minFuzz distance from +        // the requested idle until time: now + 12.          assertEquals(requestedIdleUntil, mService.mPendingIdleUntil.getWhenElapsed());          mService.removeLocked(idleUntilPi, null, REMOVE_REASON_UNDEFINED);          assertNull(mService.mPendingIdleUntil); -        setIdleUntilAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 15, idleUntilPi); -        assertEquals(mNowElapsedTest + 12, mService.mPendingIdleUntil.getWhenElapsed()); +        setIdleUntilAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 21, idleUntilPi); +        // Next wake from idle is at now + 19, which means this alarm should get pulled back. +        min = mNowElapsedTest + 19 - maxFuzz; +        max = mNowElapsedTest + 19 - minFuzz; +        assertInRange("Idle until alarm time not in expected range [" + min + ", " + max + "]", +                min, max, mService.mPendingIdleUntil.getWhenElapsed());      }      @Test      public void allowWhileIdleAlarmsWhileDeviceIdle() throws Exception { -        doReturn(0).when(mService).fuzzForDuration(anyLong()); +        setDeviceConfigLong(KEY_MAX_DEVICE_IDLE_FUZZ, 0);          setIdleUntilAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + mAllowWhileIdleWindow + 1000,                  getNewMockPendingIntent()); @@ -1571,7 +1614,7 @@ public class AlarmManagerServiceTest {      @Test      public void allowWhileIdleUnrestricted() throws Exception { -        doReturn(0).when(mService).fuzzForDuration(anyLong()); +        setDeviceConfigLong(KEY_MAX_DEVICE_IDLE_FUZZ, 0);          // Both battery saver and doze are on.          setIdleUntilAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 1000, @@ -1597,7 +1640,7 @@ public class AlarmManagerServiceTest {      @Test      public void deviceIdleDeferralOnSet() throws Exception { -        doReturn(0).when(mService).fuzzForDuration(anyLong()); +        setDeviceConfigLong(KEY_MAX_DEVICE_IDLE_FUZZ, 0);          final long deviceIdleUntil = mNowElapsedTest + 1234;          setIdleUntilAlarm(ELAPSED_REALTIME_WAKEUP, deviceIdleUntil, getNewMockPendingIntent()); @@ -1622,7 +1665,7 @@ public class AlarmManagerServiceTest {      @Test      public void deviceIdleStateChanges() throws Exception { -        doReturn(0).when(mService).fuzzForDuration(anyLong()); +        setDeviceConfigLong(KEY_MAX_DEVICE_IDLE_FUZZ, 0);          final int numAlarms = 10;          final PendingIntent[] pis = new PendingIntent[numAlarms]; @@ -1740,7 +1783,7 @@ public class AlarmManagerServiceTest {      @Test      public void prioritizedAlarmsInDeviceIdle() throws Exception { -        doReturn(0).when(mService).fuzzForDuration(anyLong()); +        setDeviceConfigLong(KEY_MAX_DEVICE_IDLE_FUZZ, 0);          final long minDelay = 5;          setDeviceConfigLong(KEY_PRIORITY_ALARM_DELAY, minDelay); @@ -1791,7 +1834,7 @@ public class AlarmManagerServiceTest {      @Test      public void dispatchOrder() throws Exception { -        doReturn(0).when(mService).fuzzForDuration(anyLong()); +        setDeviceConfigLong(KEY_MAX_DEVICE_IDLE_FUZZ, 0);          final long deviceIdleUntil = mNowElapsedTest + 1234;          final PendingIntent idleUntilPi = getNewMockPendingIntent(); diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java index a8d8a90e8935..96495701811e 100644 --- a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java +++ b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java @@ -19,6 +19,7 @@ package com.android.server.app;  import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;  import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull;  import static org.junit.Assert.assertTrue;  import static org.junit.Assert.fail;  import static org.mockito.ArgumentMatchers.anyInt; @@ -32,8 +33,10 @@ import android.content.ContextWrapper;  import android.content.pm.ApplicationInfo;  import android.content.pm.PackageInfo;  import android.content.pm.PackageManager; +import android.os.Bundle;  import android.platform.test.annotations.Presubmit;  import android.provider.DeviceConfig; +import android.util.ArraySet;  import androidx.test.InstrumentationRegistry;  import androidx.test.filters.SmallTest; @@ -140,15 +143,19 @@ public class GameManagerServiceTests {          applicationInfo.category = ApplicationInfo.CATEGORY_GAME;          final PackageInfo pi = new PackageInfo();          pi.packageName = mPackageName; +        pi.applicationInfo = applicationInfo;          final List<PackageInfo> packages = new ArrayList<>();          packages.add(pi); -        when(mMockPackageManager.getInstalledPackages(anyInt())).thenReturn(packages); +        when(mMockPackageManager.getInstalledPackagesAsUser(anyInt(), anyInt())) +                .thenReturn(packages);          when(mMockPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))                  .thenReturn(applicationInfo);      }      @After      public void tearDown() throws Exception { +        GameManagerService gameManagerService = new GameManagerService(mMockContext); +        gameManagerService.disableCompatScale(mPackageName);          if (mMockingSession != null) {              mMockingSession.finishMocking();          } @@ -165,57 +172,95 @@ public class GameManagerServiceTests {      }      private void mockDeviceConfigDefault() { -        DeviceConfig.Properties properties = new DeviceConfig.Properties.Builder( -                DeviceConfig.NAMESPACE_GAME_OVERLAY).setString(mPackageName, "").build(); -        when(DeviceConfig.getProperties(anyString(), anyString())) -                .thenReturn(properties); +        when(DeviceConfig.getProperty(anyString(), anyString())) +                .thenReturn("");      }      private void mockDeviceConfigNone() { -        DeviceConfig.Properties properties = new DeviceConfig.Properties.Builder( -                DeviceConfig.NAMESPACE_GAME_OVERLAY).build(); -        when(DeviceConfig.getProperties(anyString(), anyString())) -                .thenReturn(properties); +        when(DeviceConfig.getProperty(anyString(), anyString())) +                .thenReturn(null);      }      private void mockDeviceConfigPerformance() {          String configString = "mode=2,downscaleFactor=0.5"; -        DeviceConfig.Properties properties = new DeviceConfig.Properties.Builder( -                DeviceConfig.NAMESPACE_GAME_OVERLAY).setString(mPackageName, configString).build(); -        when(DeviceConfig.getProperties(anyString(), anyString())) -                .thenReturn(properties); +        when(DeviceConfig.getProperty(anyString(), anyString())) +                .thenReturn(configString);      }      private void mockDeviceConfigBattery() {          String configString = "mode=3,downscaleFactor=0.7"; -        DeviceConfig.Properties properties = new DeviceConfig.Properties.Builder( -                DeviceConfig.NAMESPACE_GAME_OVERLAY).setString(mPackageName, configString).build(); -        when(DeviceConfig.getProperties(anyString(), anyString())) -                .thenReturn(properties); +        when(DeviceConfig.getProperty(anyString(), anyString())) +                .thenReturn(configString);      }      private void mockDeviceConfigAll() {          String configString = "mode=3,downscaleFactor=0.7:mode=2,downscaleFactor=0.5"; -        DeviceConfig.Properties properties = new DeviceConfig.Properties.Builder( -                DeviceConfig.NAMESPACE_GAME_OVERLAY).setString(mPackageName, configString).build(); -        when(DeviceConfig.getProperties(anyString(), anyString())) -                .thenReturn(properties); +        when(DeviceConfig.getProperty(anyString(), anyString())) +                .thenReturn(configString);      }      private void mockDeviceConfigInvalid() {          String configString = "mode=2,downscaleFactor=0.55"; -        DeviceConfig.Properties properties = new DeviceConfig.Properties.Builder( -                DeviceConfig.NAMESPACE_GAME_OVERLAY).setString(mPackageName, configString).build(); -        when(DeviceConfig.getProperties(anyString(), anyString())) -                .thenReturn(properties); +        when(DeviceConfig.getProperty(anyString(), anyString())) +                .thenReturn(configString);      }      private void mockDeviceConfigMalformed() {          String configString = "adsljckv=nin3rn9hn1231245:8795tq=21ewuydg"; -        DeviceConfig.Properties properties = new DeviceConfig.Properties.Builder( -                DeviceConfig.NAMESPACE_GAME_OVERLAY).setString(mPackageName, configString).build(); -        when(DeviceConfig.getProperties(anyString(), anyString())) -                .thenReturn(properties); +        when(DeviceConfig.getProperty(anyString(), anyString())) +                .thenReturn(configString); +    } + +    private void mockGameModeOptInAll() throws Exception { +        final ApplicationInfo applicationInfo = new ApplicationInfo(); +        Bundle metaDataBundle = new Bundle(); +        metaDataBundle.putBoolean( +                GameManagerService.GamePackageConfiguration.METADATA_PERFORMANCE_MODE_ENABLE, true); +        metaDataBundle.putBoolean( +                GameManagerService.GamePackageConfiguration.METADATA_BATTERY_MODE_ENABLE, true); +        applicationInfo.metaData = metaDataBundle; +        when(mMockPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) +                .thenReturn(applicationInfo); +    } + +    private void mockGameModeOptInPerformance() throws Exception { +        final ApplicationInfo applicationInfo = new ApplicationInfo(); +        Bundle metaDataBundle = new Bundle(); +        metaDataBundle.putBoolean( +                GameManagerService.GamePackageConfiguration.METADATA_PERFORMANCE_MODE_ENABLE, true); +        applicationInfo.metaData = metaDataBundle; +        when(mMockPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) +                .thenReturn(applicationInfo); +    } + +    private void mockGameModeOptInBattery() throws Exception { +        final ApplicationInfo applicationInfo = new ApplicationInfo(); +        Bundle metaDataBundle = new Bundle(); +        metaDataBundle.putBoolean( +                GameManagerService.GamePackageConfiguration.METADATA_BATTERY_MODE_ENABLE, true); +        applicationInfo.metaData = metaDataBundle; +        when(mMockPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) +                .thenReturn(applicationInfo); +    } + +    private void mockInterventionAllowDownscaleTrue() throws Exception { +        final ApplicationInfo applicationInfo = new ApplicationInfo(); +        Bundle metaDataBundle = new Bundle(); +        metaDataBundle.putBoolean( +                GameManagerService.GamePackageConfiguration.METADATA_WM_ALLOW_DOWNSCALE, true); +        applicationInfo.metaData = metaDataBundle; +        when(mMockPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) +                .thenReturn(applicationInfo); +    } + +    private void mockInterventionAllowDownscaleFalse() throws Exception { +        final ApplicationInfo applicationInfo = new ApplicationInfo(); +        Bundle metaDataBundle = new Bundle(); +        metaDataBundle.putBoolean( +                GameManagerService.GamePackageConfiguration.METADATA_WM_ALLOW_DOWNSCALE, false); +        applicationInfo.metaData = metaDataBundle; +        when(mMockPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) +                .thenReturn(applicationInfo);      }      /** @@ -353,136 +398,209 @@ public class GameManagerServiceTests {                  gameManagerService.getGameMode(mPackageName, USER_ID_2));      } +    private void checkReportedModes(int ...requiredModes) { +        GameManagerService gameManagerService = new GameManagerService(mMockContext); +        gameManagerService.onUserStarting(USER_ID_1); +        gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName); +        ArraySet<Integer> reportedModes = new ArraySet<>(); +        int[] modes = gameManagerService.getAvailableGameModes(mPackageName); +        for (int mode : modes) { +            reportedModes.add(mode); +        } +        assertEquals(requiredModes.length, reportedModes.size()); +        for (int requiredMode : reportedModes) { +            assertTrue("Required game mode not supported: " + requiredMode, +                    reportedModes.contains(requiredMode)); +        } +    } + +    private void checkDownscaling(int gameMode, String scaling) { +        GameManagerService gameManagerService = new GameManagerService(mMockContext); +        gameManagerService.onUserStarting(USER_ID_1); +        gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName); +        GameManagerService.GamePackageConfiguration config = +                gameManagerService.getConfig(mPackageName); +        assertEquals(config.getGameModeConfiguration(gameMode).getScaling(), scaling); +    } +      /** -     * Phonesky device config exists, but is only propagating the default value. +     * Phenotype device config exists, but is only propagating the default value.       */      @Test      public void testDeviceConfigDefault() {          mockDeviceConfigDefault();          mockModifyGameModeGranted(); -        GameManagerService gameManagerService = new GameManagerService(mMockContext); -        gameManagerService.onUserStarting(USER_ID_1); -        gameManagerService.loadDeviceConfigLocked(); - -        int[] modes = gameManagerService.getAvailableGameModes(mPackageName); -        assertEquals(modes.length, 1); -        assertEquals(modes[0], GameManager.GAME_MODE_UNSUPPORTED); +        checkReportedModes(GameManager.GAME_MODE_UNSUPPORTED);      }      /** -     * Phonesky device config does not exists. +     * Phenotype device config does not exists.       */      @Test      public void testDeviceConfigNone() {          mockDeviceConfigNone();          mockModifyGameModeGranted(); -        GameManagerService gameManagerService = new GameManagerService(mMockContext); -        gameManagerService.onUserStarting(USER_ID_1); -        gameManagerService.loadDeviceConfigLocked(); - -        int[] modes = gameManagerService.getAvailableGameModes(mPackageName); -        assertEquals(modes.length, 1); -        assertEquals(modes[0], GameManager.GAME_MODE_UNSUPPORTED); +        checkReportedModes(GameManager.GAME_MODE_UNSUPPORTED);      }      /** -     * Phonesky device config for performance mode exists and is valid. +     * Phenotype device config for performance mode exists and is valid.       */      @Test      public void testDeviceConfigPerformance() {          mockDeviceConfigPerformance();          mockModifyGameModeGranted(); -        GameManagerService gameManagerService = new GameManagerService(mMockContext); -        gameManagerService.onUserStarting(USER_ID_1); -        gameManagerService.loadDeviceConfigLocked(); - -        boolean perfModeExists = false; -        int[] modes = gameManagerService.getAvailableGameModes(mPackageName); -        for (int mode : modes) { -            if (mode == GameManager.GAME_MODE_PERFORMANCE) { -                perfModeExists = true; -            } -        } -        assertEquals(modes.length, 1); -        assertTrue(perfModeExists); +        checkReportedModes(GameManager.GAME_MODE_PERFORMANCE, GameManager.GAME_MODE_STANDARD);      }      /** -     * Phonesky device config for battery mode exists and is valid. +     * Phenotype device config for battery mode exists and is valid.       */      @Test      public void testDeviceConfigBattery() {          mockDeviceConfigBattery();          mockModifyGameModeGranted(); -        GameManagerService gameManagerService = new GameManagerService(mMockContext); -        gameManagerService.onUserStarting(USER_ID_1); -        gameManagerService.loadDeviceConfigLocked(); - -        boolean batteryModeExists = false; -        int[] modes = gameManagerService.getAvailableGameModes(mPackageName); -        for (int mode : modes) { -            if (mode == GameManager.GAME_MODE_BATTERY) { -                batteryModeExists = true; -            } -        } -        assertEquals(modes.length, 1); -        assertTrue(batteryModeExists); +        checkReportedModes(GameManager.GAME_MODE_BATTERY, GameManager.GAME_MODE_STANDARD);      }      /** -     * Phonesky device configs for both battery and performance modes exists and are valid. +     * Phenotype device configs for both battery and performance modes exists and are valid.       */      @Test      public void testDeviceConfigAll() {          mockDeviceConfigAll();          mockModifyGameModeGranted(); -        GameManagerService gameManagerService = new GameManagerService(mMockContext); -        gameManagerService.onUserStarting(USER_ID_1); -        gameManagerService.loadDeviceConfigLocked(); - -        boolean batteryModeExists = false; -        boolean perfModeExists = false; -        int[] modes = gameManagerService.getAvailableGameModes(mPackageName); -        for (int mode : modes) { -            if (mode == GameManager.GAME_MODE_BATTERY) { -                batteryModeExists = true; -            } else if (mode == GameManager.GAME_MODE_PERFORMANCE) { -                perfModeExists = true; -            } -        } -        assertTrue(batteryModeExists); -        assertTrue(perfModeExists); +        checkReportedModes(GameManager.GAME_MODE_PERFORMANCE, GameManager.GAME_MODE_BATTERY, +                GameManager.GAME_MODE_STANDARD);      }      /** -     * Phonesky device config contains values that parse correctly but are not valid in game mode. +     * Phenotype device config contains values that parse correctly but are not valid in game mode.       */      @Test      public void testDeviceConfigInvalid() {          mockDeviceConfigInvalid();          mockModifyGameModeGranted(); -        GameManagerService gameManagerService = new GameManagerService(mMockContext); -        gameManagerService.onUserStarting(USER_ID_1); -        gameManagerService.loadDeviceConfigLocked(); - -        int[] modes = gameManagerService.getAvailableGameModes(mPackageName); -        assertEquals(modes.length, 1); -        assertEquals(modes[0], GameManager.GAME_MODE_UNSUPPORTED); +        checkReportedModes(GameManager.GAME_MODE_UNSUPPORTED);      }      /** -     * Phonesky device config is garbage. +     * Phenotype device config is garbage.       */      @Test      public void testDeviceConfigMalformed() {          mockDeviceConfigMalformed();          mockModifyGameModeGranted(); +        checkReportedModes(GameManager.GAME_MODE_UNSUPPORTED); +    } + +    /** +     * Game modes are made available only through app manifest opt-in. +     */ +    @Test +    public void testGameModeOptInAll() throws Exception { +        mockGameModeOptInAll(); +        mockDeviceConfigNone(); +        mockModifyGameModeGranted(); +        checkReportedModes(GameManager.GAME_MODE_PERFORMANCE, GameManager.GAME_MODE_BATTERY, +                GameManager.GAME_MODE_STANDARD); +    } + +    /** +     * BATTERY game mode is available through the app manifest opt-in. +     */ +    @Test +    public void testGameModeOptInBattery() throws Exception { +        mockGameModeOptInBattery(); +        mockDeviceConfigNone(); +        mockModifyGameModeGranted(); +        checkReportedModes(GameManager.GAME_MODE_BATTERY, GameManager.GAME_MODE_STANDARD); +    } + +    /** +     * PERFORMANCE game mode is available through the app manifest opt-in. +     */ +    @Test +    public void testGameModeOptInPerformance() throws Exception { +        mockGameModeOptInPerformance(); +        mockDeviceConfigNone(); +        mockModifyGameModeGranted(); +        checkReportedModes(GameManager.GAME_MODE_PERFORMANCE, GameManager.GAME_MODE_STANDARD); +    } + +    /** +     * BATTERY game mode is available through the app manifest opt-in and PERFORMANCE game mode is +     * available through Phenotype. +     */ +    @Test +    public void testGameModeOptInBatteryMixed() throws Exception { +        mockGameModeOptInBattery(); +        mockDeviceConfigPerformance(); +        mockModifyGameModeGranted(); +        checkReportedModes(GameManager.GAME_MODE_PERFORMANCE, GameManager.GAME_MODE_BATTERY, +                GameManager.GAME_MODE_STANDARD); +    } + +    /** +     * PERFORMANCE game mode is available through the app manifest opt-in and BATTERY game mode is +     * available through Phenotype. +     */ +    @Test +    public void testGameModeOptInPerformanceMixed() throws Exception { +        mockGameModeOptInPerformance(); +        mockDeviceConfigBattery(); +        mockModifyGameModeGranted(); +        checkReportedModes(GameManager.GAME_MODE_PERFORMANCE, GameManager.GAME_MODE_BATTERY, +                GameManager.GAME_MODE_STANDARD); +    } + +    /** +     * PERFORMANCE game mode is configured through Phenotype. The app hasn't specified any metadata. +     */ +    @Test +    public void testInterventionAllowScalingDefault() throws Exception { +        mockDeviceConfigPerformance(); +        mockModifyGameModeGranted(); +        checkDownscaling(GameManager.GAME_MODE_PERFORMANCE, "0.5"); +    } + +    /** +     * PERFORMANCE game mode is configured through Phenotype. The app has opted-out of scaling. +     */ +    @Test +    public void testInterventionAllowDownscaleFalse() throws Exception { +        mockDeviceConfigPerformance(); +        mockInterventionAllowDownscaleFalse(); +        mockModifyGameModeGranted(); +        checkDownscaling(GameManager.GAME_MODE_PERFORMANCE, "1.0"); +    } + +    /** +     * PERFORMANCE game mode is configured through Phenotype. The app has redundantly specified +     * the downscaling metadata default value of "true". +     */ +    @Test +    public void testInterventionAllowDownscaleTrue() throws Exception { +        mockDeviceConfigPerformance(); +        mockInterventionAllowDownscaleTrue(); +        mockModifyGameModeGranted(); +        checkDownscaling(GameManager.GAME_MODE_PERFORMANCE, "0.5"); +    } + +    /** +     * PERFORMANCE game mode is configured through Phenotype, but the app has also opted into the +     * same mode. No interventions for this game mode should be available in this case. +     */ +    @Test +    public void testDeviceConfigOptInOverlap() throws Exception { +        mockDeviceConfigPerformance(); +        mockGameModeOptInPerformance(); +        mockModifyGameModeGranted();          GameManagerService gameManagerService = new GameManagerService(mMockContext);          gameManagerService.onUserStarting(USER_ID_1); -        gameManagerService.loadDeviceConfigLocked(); - -        int[] modes = gameManagerService.getAvailableGameModes(mPackageName); -        assertEquals(modes.length, 1); -        assertEquals(modes[0], GameManager.GAME_MODE_UNSUPPORTED); +        gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName); +        GameManagerService.GamePackageConfiguration config = +                gameManagerService.getConfig(mPackageName); +        assertNull(config.getGameModeConfiguration(GameManager.GAME_MODE_PERFORMANCE));      }  } diff --git a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java index 24b85f056731..92e4ec9d2e8b 100644 --- a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java @@ -61,6 +61,8 @@ import android.location.ILocationListener;  import android.location.LastLocationRequest;  import android.location.Location;  import android.location.LocationManagerInternal; +import android.location.LocationManagerInternal.LocationTagInfo; +import android.location.LocationManagerInternal.OnProviderLocationTagsChangeListener;  import android.location.LocationManagerInternal.ProviderEnabledListener;  import android.location.LocationRequest;  import android.location.LocationResult; @@ -90,6 +92,7 @@ import org.junit.After;  import org.junit.Before;  import org.junit.Test;  import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor;  import org.mockito.InOrder;  import org.mockito.Mock; @@ -216,6 +219,21 @@ public class LocationProviderManagerTest {      }      @Test +    public void testAttributionTags() { +        OnProviderLocationTagsChangeListener listener = mock( +                OnProviderLocationTagsChangeListener.class); +        mManager.setOnProviderLocationTagsChangeListener(listener); + +        mProvider.setExtraAttributionTags(Collections.singleton("extra")); + +        ArgumentCaptor<LocationTagInfo> captor = ArgumentCaptor.forClass(LocationTagInfo.class); +        verify(listener, times(2)).onLocationTagsChanged(captor.capture()); + +        assertThat(captor.getAllValues().get(0).getTags()).isEmpty(); +        assertThat(captor.getAllValues().get(1).getTags()).containsExactly("extra", "attribution"); +    } + +    @Test      public void testRemoveProvider() {          mManager.setRealProvider(null);          assertThat(mManager.hasProvider()).isFalse(); diff --git a/services/tests/mockingservicestests/src/com/android/server/sensorprivacy/OWNERS b/services/tests/mockingservicestests/src/com/android/server/sensorprivacy/OWNERS new file mode 100644 index 000000000000..c74393b102a8 --- /dev/null +++ b/services/tests/mockingservicestests/src/com/android/server/sensorprivacy/OWNERS @@ -0,0 +1,3 @@ +# Bug component: 137825 + +file:platform/frameworks/native:/libs/sensorprivacy/OWNERS diff --git a/services/tests/mockingservicestests/src/com/android/server/sensorprivacy/SensorPrivacyServiceMockingTest.java b/services/tests/mockingservicestests/src/com/android/server/sensorprivacy/SensorPrivacyServiceMockingTest.java new file mode 100644 index 000000000000..844687f34555 --- /dev/null +++ b/services/tests/mockingservicestests/src/com/android/server/sensorprivacy/SensorPrivacyServiceMockingTest.java @@ -0,0 +1,142 @@ +/* + * 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.sensorprivacy; + +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; + +import android.app.ActivityManager; +import android.app.ActivityTaskManager; +import android.app.AppOpsManager; +import android.content.Context; +import android.content.pm.UserInfo; +import android.os.Environment; +import android.telephony.TelephonyManager; +import android.testing.AndroidTestingRunner; + +import androidx.test.platform.app.InstrumentationRegistry; + +import com.android.dx.mockito.inline.extended.ExtendedMockito; +import com.android.server.LocalServices; +import com.android.server.SensorPrivacyService; +import com.android.server.pm.UserManagerInternal; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoSession; +import org.mockito.quality.Strictness; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; + +@RunWith(AndroidTestingRunner.class) +public class SensorPrivacyServiceMockingTest { + +    private static final String PERSISTENCE_FILE_PATHS_TEMPLATE = +            "SensorPrivacyServiceMockingTest/persisted_file%d.xml"; +    public static final String PERSISTENCE_FILE1 = +            String.format(PERSISTENCE_FILE_PATHS_TEMPLATE, 1); +    public static final String PERSISTENCE_FILE2 = +            String.format(PERSISTENCE_FILE_PATHS_TEMPLATE, 2); +    public static final String PERSISTENCE_FILE3 = +            String.format(PERSISTENCE_FILE_PATHS_TEMPLATE, 3); +    public static final String PERSISTENCE_FILE4 = +            String.format(PERSISTENCE_FILE_PATHS_TEMPLATE, 4); +    public static final String PERSISTENCE_FILE5 = +            String.format(PERSISTENCE_FILE_PATHS_TEMPLATE, 5); + +    private Context mContext; +    @Mock +    private AppOpsManager mMockedAppOpsManager; +    @Mock +    private UserManagerInternal mMockedUserManagerInternal; +    @Mock +    private ActivityManager mMockedActivityManager; +    @Mock +    private ActivityTaskManager mMockedActivityTaskManager; +    @Mock +    private TelephonyManager mMockedTelephonyManager; + +    @Test +    public void testServiceInit() throws IOException { +        MockitoSession mockitoSession = ExtendedMockito.mockitoSession() +                .initMocks(this) +                .strictness(Strictness.WARN) +                .spyStatic(LocalServices.class) +                .spyStatic(Environment.class) +                .startMocking(); + +        try { +            mContext = InstrumentationRegistry.getInstrumentation().getContext(); +            spyOn(mContext); + +            doReturn(mMockedAppOpsManager).when(mContext).getSystemService(AppOpsManager.class); +            doReturn(mMockedUserManagerInternal) +                    .when(() -> LocalServices.getService(UserManagerInternal.class)); +            doReturn(mMockedActivityManager).when(mContext).getSystemService(ActivityManager.class); +            doReturn(mMockedActivityTaskManager) +                    .when(mContext).getSystemService(ActivityTaskManager.class); +            doReturn(mMockedTelephonyManager).when(mContext).getSystemService( +                    TelephonyManager.class); + +            String dataDir = mContext.getApplicationInfo().dataDir; +            doReturn(new File(dataDir)).when(() -> Environment.getDataSystemDirectory()); + +            File onDeviceFile = new File(dataDir, "sensor_privacy.xml"); +            onDeviceFile.delete(); + +            // Try all files with one known user +            doReturn(new int[]{0}).when(mMockedUserManagerInternal).getUserIds(); +            doReturn(ExtendedMockito.mock(UserInfo.class)).when(mMockedUserManagerInternal) +                    .getUserInfo(0); +            initServiceWithPersistenceFile(onDeviceFile, null); +            initServiceWithPersistenceFile(onDeviceFile, PERSISTENCE_FILE1); +            initServiceWithPersistenceFile(onDeviceFile, PERSISTENCE_FILE2); +            initServiceWithPersistenceFile(onDeviceFile, PERSISTENCE_FILE3); +            initServiceWithPersistenceFile(onDeviceFile, PERSISTENCE_FILE4); +            initServiceWithPersistenceFile(onDeviceFile, PERSISTENCE_FILE5); + +            // Try all files with two known users +            doReturn(new int[]{0, 10}).when(mMockedUserManagerInternal).getUserIds(); +            doReturn(ExtendedMockito.mock(UserInfo.class)).when(mMockedUserManagerInternal) +                    .getUserInfo(0); +            doReturn(ExtendedMockito.mock(UserInfo.class)).when(mMockedUserManagerInternal) +                    .getUserInfo(10); +            initServiceWithPersistenceFile(onDeviceFile, null); +            initServiceWithPersistenceFile(onDeviceFile, PERSISTENCE_FILE1); +            initServiceWithPersistenceFile(onDeviceFile, PERSISTENCE_FILE2); +            initServiceWithPersistenceFile(onDeviceFile, PERSISTENCE_FILE3); +            initServiceWithPersistenceFile(onDeviceFile, PERSISTENCE_FILE4); +            initServiceWithPersistenceFile(onDeviceFile, PERSISTENCE_FILE5); + +        } finally { +            mockitoSession.finishMocking(); +        } +    } + +    private void initServiceWithPersistenceFile(File onDeviceFile, +            String persistenceFilePath) throws IOException { +        if (persistenceFilePath != null) { +            Files.copy(mContext.getAssets().open(persistenceFilePath), +                    onDeviceFile.toPath()); +        } +        new SensorPrivacyService(mContext); +        onDeviceFile.delete(); +    } +} diff --git a/services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java b/services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java index 638b1b4c57c4..834404926310 100644 --- a/services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java +++ b/services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java @@ -30,6 +30,7 @@ import android.app.ActivityManager;  import android.app.usage.UsageStatsManagerInternal;  import android.content.ComponentName;  import android.content.Context; +import android.content.pm.ApplicationInfo;  import android.content.pm.PackageManagerInternal;  import com.android.server.LocalServices; @@ -57,8 +58,36 @@ public class OomAdjusterTests {      private ProcessRecord mProcessRecord;      private static final long ZERO = 0L; -    private static final long USAGE_STATS_INTERACTION = 2 * 60 * 60 * 1000L; -    private static final long SERVICE_USAGE_INTERACTION = 30 * 60 * 1000; +    private static final long USAGE_STATS_INTERACTION = 10 * 60 * 1000L; +    private static final long SERVICE_USAGE_INTERACTION = 60 * 1000; + +    static class MyOomAdjuster extends OomAdjuster { + +        private final PlatformCompatCache mPlatformCompatCache; + +        MyOomAdjuster(ActivityManagerService service, ProcessList processList, +                ActiveUids activeUids) { +            super(service, processList, activeUids); +            mPlatformCompatCache = new MyPlatformCompatCache(new long[]{}); +        } + +        static class MyPlatformCompatCache extends PlatformCompatCache { + +            MyPlatformCompatCache(long[] compatChanges) { +                super(compatChanges); +            } + +            @Override +            boolean isChangeEnabled(long changeId, ApplicationInfo app, boolean defaultValue) { +                return true; +            } +        } + +        @Override +        protected OomAdjuster.PlatformCompatCache getPlatformCompatCache() { +            return mPlatformCompatCache; +        } +    }      @BeforeClass      public static void setUpOnce() { @@ -84,7 +113,7 @@ public class OomAdjusterTests {              final AppProfiler profiler = mock(AppProfiler.class);              setFieldValue(AppProfiler.class, profiler, "mProfilerLock", new Object());              setFieldValue(ActivityManagerService.class, sService, "mAppProfiler", profiler); -            sService.mOomAdjuster = new OomAdjuster(sService, sService.mProcessList, null); +            sService.mOomAdjuster = new MyOomAdjuster(sService, sService.mProcessList, null);              LocalServices.addService(UsageStatsManagerInternal.class,                      mock(UsageStatsManagerInternal.class));              sService.mUsageStatsService = LocalServices.getService(UsageStatsManagerInternal.class); @@ -119,8 +148,10 @@ public class OomAdjusterTests {          // Ensure certain services and constants are defined properly          assertNotNull(sService.mUsageStatsService); -        assertEquals(USAGE_STATS_INTERACTION, sService.mConstants.USAGE_STATS_INTERACTION_INTERVAL); -        assertEquals(SERVICE_USAGE_INTERACTION, sService.mConstants.SERVICE_USAGE_INTERACTION_TIME); +        assertEquals(USAGE_STATS_INTERACTION, +                sService.mConstants.USAGE_STATS_INTERACTION_INTERVAL_POST_S); +        assertEquals(SERVICE_USAGE_INTERACTION, +                sService.mConstants.SERVICE_USAGE_INTERACTION_TIME_POST_S);      }      @Test diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index 1b42dfa0712e..c54dffc3c431 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -30,6 +30,7 @@ import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_HIGH;  import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_LOW;  import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_MEDIUM;  import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE; +import static android.app.admin.DevicePolicyManager.PRIVATE_DNS_SET_NO_ERROR;  import static android.app.admin.DevicePolicyManager.WIPE_EUICC;  import static android.app.admin.PasswordMetrics.computeForPasswordOrPin;  import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE; @@ -7333,6 +7334,48 @@ public class DevicePolicyManagerTest extends DpmTestBase {          assertThat(dpm.getPolicyExemptApps()).containsExactly("4", "8", "15", "16", "23", "42");      } +    @Test +    public void testSetGlobalPrivateDnsModeOpportunistic_asDeviceOwner() throws Exception { +        setDeviceOwner(); +        // setUp() adds a secondary user for CALLER_USER_HANDLE. Remove it as otherwise the +        // feature is disabled because there are non-affiliated secondary users. +        getServices().removeUser(CALLER_USER_HANDLE); +        clearInvocations(getServices().settings); + +        int result = dpm.setGlobalPrivateDnsModeOpportunistic(admin1); + +        assertThat(result).isEqualTo(PRIVATE_DNS_SET_NO_ERROR); +    } + +    @Test +    public void testSetGlobalPrivateDnsModeOpportunistic_hasUnaffiliatedUsers() throws Exception { +        setDeviceOwner(); +        setAsProfileOwner(admin2); + +        assertThrows(SecurityException.class, +                () -> dpm.setGlobalPrivateDnsModeOpportunistic(admin1)); +    } + +    @Test +    public void testSetRecommendedGlobalProxy_asDeviceOwner() throws Exception { +        setDeviceOwner(); +        // setUp() adds a secondary user for CALLER_USER_HANDLE. Remove it as otherwise the +        // feature is disabled because there are non-affiliated secondary users. +        getServices().removeUser(CALLER_USER_HANDLE); + +        dpm.setRecommendedGlobalProxy(admin1, null); + +        verify(getServices().connectivityManager).setGlobalProxy(null); +    } + +    @Test +    public void testSetRecommendedGlobalProxy_hasUnaffiliatedUsers() throws Exception { +        setDeviceOwner(); +        setAsProfileOwner(admin2); + +        assertThrows(SecurityException.class, () -> dpm.setRecommendedGlobalProxy(admin1, null)); +    } +      private void setUserUnlocked(int userHandle, boolean unlocked) {          when(getServices().userManager.isUserUnlocked(eq(userHandle))).thenReturn(unlocked);      } diff --git a/services/tests/servicestests/src/com/android/server/pm/WatchedIntentHandlingTest.java b/services/tests/servicestests/src/com/android/server/pm/WatchedIntentHandlingTest.java index 153938cbbbf1..b2c300255aef 100644 --- a/services/tests/servicestests/src/com/android/server/pm/WatchedIntentHandlingTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/WatchedIntentHandlingTest.java @@ -18,6 +18,7 @@ package com.android.server.pm;  import static org.junit.Assert.assertTrue; +import android.content.ComponentName;  import android.content.IntentFilter;  import androidx.test.filters.SmallTest; @@ -83,4 +84,80 @@ public class WatchedIntentHandlingTest {          watcher.verifyNoChangeReported("pulled snapshot");      } +    @Test +    public void testPreferredActivity() { +        // Create a bunch of nondescript component names +        ComponentName component = new ComponentName("Package_A", "Class_A"); +        ComponentName[] components = new ComponentName[10]; +        for (int i = 0; i < components.length; i++) { +            components[i] = new ComponentName("Package_" + i, "Class_" + i); +        } +        IntentFilter i = new IntentFilter("TEST_ACTION"); +        PreferredActivity a = new PreferredActivity(i, 1, components, component, true); +        final WatchableTester watcher = new WatchableTester(a, "PreferredIntentResolver"); +        watcher.register(); + +        // Verify that the initial IntentFilter and the PreferredActivity are truly +        // independent.  This is in addition to verifying that the PreferredActivity +        // properly reports its changes. +        i.setPriority(i.getPriority() + 1); +        watcher.verifyNoChangeReported("indepenent intent"); +        a.setPriority(a.getPriority() + 2); +        watcher.verifyChangeReported("dependent intent"); +        // Verify independence of i and a +        assertTrue(i.getPriority() != a.getPriority()); + +        // Verify that snapshots created from the PreferredActivity are stable when the +        // source PreferredActivity changes. +        a.setPriority(3); +        watcher.verifyChangeReported("initialize intent priority"); +        PreferredActivity s1 = a.snapshot(); +        watcher.verifyNoChangeReported("pulled snapshot"); +        // Verify snapshot cache.  In the absence of changes to the PreferredActivity, the +        // snapshot will not be rebuilt and will be the exact same object as before. +        assertTrue(s1 == a.snapshot()); +        // Force a change by incrementing the priority.  The next snapshot must be +        // different from the first snapshot. +        a.setPriority(a.getPriority() + 1); +        watcher.verifyChangeReported("increment priority"); +        PreferredActivity s2 = a.snapshot(); +        watcher.verifyNoChangeReported("pulled second snapshot"); +        assertTrue(s1 != s2); +        // Assert the two snapshots are different.  s1 should have priority 3 and s2 +        // should have priority 4.  s2 should match the current value in a. +        assertTrue(a.getPriority() == s2.getPriority()); +        assertTrue(s1.getPriority() != s2.getPriority()); +    } + +    @Test +    public void testPreferredIntentResolver() { +        PreferredIntentResolver r = new PreferredIntentResolver(); +        final WatchableTester watcher = new WatchableTester(r, "PreferredIntentResolver"); +        watcher.register(); +        // Create a bunch of nondescript component names +        ComponentName component = new ComponentName("Package_A", "Class_A"); +        ComponentName[] components = new ComponentName[10]; +        for (int i = 0; i < components.length; i++) { +            components[i] = new ComponentName("Package_" + i, "Class_" + i); +        } +        IntentFilter i = new IntentFilter("TEST_ACTION"); +        PreferredActivity a1 = new PreferredActivity(i, 1, components, component, true); + +        r.addFilter(a1); +        watcher.verifyChangeReported("addFilter"); +        i.setPriority(i.getPriority() + 1); +        watcher.verifyNoChangeReported("indepenent intent"); +        a1.setPriority(a1.getPriority() + 1); +        watcher.verifyChangeReported("dependent intent"); + +        PreferredActivity s1 = a1.snapshot(); +        watcher.verifyNoChangeReported("pulled snapshot"); +        // Verify snapshot cache. +        assertTrue(s1 == a1.snapshot()); +        a1.setPriority(a1.getPriority() + 1); +        watcher.verifyChangeReported("increment priority"); +        PreferredActivity s2 = a1.snapshot(); +        watcher.verifyNoChangeReported("pulled second snapshot"); +        assertTrue(s1.getPriority() != s2.getPriority()); +    }  } diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/OrdinalGeneratorTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/OrdinalGeneratorTest.java index af954d599334..3fdac66225a8 100644 --- a/services/tests/servicestests/src/com/android/server/timezonedetector/OrdinalGeneratorTest.java +++ b/services/tests/servicestests/src/com/android/server/timezonedetector/OrdinalGeneratorTest.java @@ -25,13 +25,14 @@ import org.junit.Test;  import org.junit.runner.RunWith;  import java.util.Arrays; +import java.util.function.Function;  @RunWith(AndroidJUnit4.class)  public class OrdinalGeneratorTest {      @Test -    public void testOrdinal() { -        OrdinalGenerator<String> ordinalGenerator = new OrdinalGenerator<>(); +    public void testOrdinal_withIdentityFunction() { +        OrdinalGenerator<String> ordinalGenerator = new OrdinalGenerator<>(Function.identity());          int oneOrd = ordinalGenerator.ordinal("One");          int twoOrd = ordinalGenerator.ordinal("Two");          assertNotEquals(oneOrd, twoOrd); @@ -45,8 +46,8 @@ public class OrdinalGeneratorTest {      }      @Test -    public void testOrdinals() { -        OrdinalGenerator<String> ordinalGenerator = new OrdinalGenerator<>(); +    public void testOrdinals_withIdentityFunction() { +        OrdinalGenerator<String> ordinalGenerator = new OrdinalGenerator<>(Function.identity());          int[] oneTwoOrds = ordinalGenerator.ordinals(Arrays.asList("One", "Two"));          int[] twoThreeOrds = ordinalGenerator.ordinals(Arrays.asList("Two", "Three"));          assertEquals(oneTwoOrds[0], ordinalGenerator.ordinal("One")); @@ -54,4 +55,33 @@ public class OrdinalGeneratorTest {          assertEquals(twoThreeOrds[0], ordinalGenerator.ordinal("Two"));          assertEquals(twoThreeOrds[1], ordinalGenerator.ordinal("Three"));      } + +    @Test +    public void testOrdinal_withCanonicalizationFunction() { +        OrdinalGenerator<String> ordinalGenerator = new OrdinalGenerator<>(String::toLowerCase); + +        int oneOrd = ordinalGenerator.ordinal("One"); +        int twoOrd = ordinalGenerator.ordinal("Two"); +        assertNotEquals(oneOrd, twoOrd); + +        assertEquals(oneOrd, ordinalGenerator.ordinal("ONE")); +        assertEquals(twoOrd, ordinalGenerator.ordinal("two")); + +        int threeOrd = ordinalGenerator.ordinal("Three"); +        assertNotEquals(oneOrd, threeOrd); +        assertNotEquals(twoOrd, threeOrd); +    } + +    @Test +    public void testOrdinals_withCanonicalizationFunction() { +        OrdinalGenerator<String> ordinalGenerator = new OrdinalGenerator<>(String::toLowerCase); + +        int[] oneTwoOrds = ordinalGenerator.ordinals(Arrays.asList("One", "Two")); +        int[] twoThreeOrds = ordinalGenerator.ordinals(Arrays.asList("Two", "Three")); + +        assertEquals(oneTwoOrds[0], ordinalGenerator.ordinal("ONE")); +        assertEquals(oneTwoOrds[1], ordinalGenerator.ordinal("two")); +        assertEquals(twoThreeOrds[0], ordinalGenerator.ordinal("TWO")); +        assertEquals(twoThreeOrds[1], ordinalGenerator.ordinal("threE")); +    }  } diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneCanonicalizerTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneCanonicalizerTest.java new file mode 100644 index 000000000000..0c78f5b85fac --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneCanonicalizerTest.java @@ -0,0 +1,54 @@ +/* + * 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.timezonedetector; + +import static com.google.common.truth.Truth.assertThat; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class TimeZoneCanonicalizerTest { + +    TimeZoneCanonicalizer mFunction = new TimeZoneCanonicalizer(); + +    @Test +    public void deprecatedTimeZonesAreEqualToCanonical() { +        assertThat(mFunction.apply("America/Godthab")).isEqualTo("America/Nuuk"); +        assertThat(mFunction.apply("Australia/Currie")).isEqualTo("Australia/Hobart"); +    } + +    @Test +    public void wellKnownCanonicalIDs() { +        assertThat(mFunction.apply("America/Detroit")).isEqualTo("America/Detroit"); +        assertThat(mFunction.apply("Europe/London")).isEqualTo("Europe/London"); +        assertThat(mFunction.apply("America/New_York")).isEqualTo("America/New_York"); +        assertThat(mFunction.apply("Europe/Volgograd")).isEqualTo("Europe/Volgograd"); +    } + +    @Test +    public void timeZonesAsGmtOffsetsTreatedAsCanonical() { +        assertThat(mFunction.apply("Etc/GMT-11")).isEqualTo("Etc/GMT-11"); +    } + +    @Test +    public void nonExistingOneMappedToThemselves() { +        assertThat(mFunction.apply("Mars/Base")).isEqualTo("Mars/Base"); +    } +} diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java index 47475a66c0d5..331f76cf7dc2 100644 --- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java +++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java @@ -56,6 +56,7 @@ import java.util.Arrays;  import java.util.Collections;  import java.util.List;  import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Function;  /**   * White-box unit tests for {@link TimeZoneDetectorStrategyImpl}. @@ -1008,7 +1009,7 @@ public class TimeZoneDetectorStrategyImplTest {          // Check the various feature state values are what we expect.          assertFeatureStateMatchesConfig(expectedInternalConfig, actualState, expectedDetectionMode); -        OrdinalGenerator<String> tzIdOrdinalGenerator = new OrdinalGenerator<>(); +        OrdinalGenerator<String> tzIdOrdinalGenerator = new OrdinalGenerator<>(Function.identity());          MetricsTimeZoneDetectorState expectedState =                  MetricsTimeZoneDetectorState.create(                          tzIdOrdinalGenerator, expectedInternalConfig, expectedDeviceTimeZoneId, diff --git a/services/tests/servicestests/src/com/android/server/utils/OWNERS b/services/tests/servicestests/src/com/android/server/utils/OWNERS new file mode 100644 index 000000000000..1853220b9433 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/utils/OWNERS @@ -0,0 +1,4 @@ +per-file WatchableTester.java = file:/services/core/java/com/android/server/pm/OWNERS +per-file WatchableTester.java = shombert@google.com +per-file WatcherTest.java = file:/services/core/java/com/android/server/pm/OWNERS +per-file WatcherTest.java = shombert@google.com diff --git a/services/tests/servicestests/src/com/android/server/utils/WatcherTest.java b/services/tests/servicestests/src/com/android/server/utils/WatcherTest.java index f255c67cf47d..9679e58c4e7d 100644 --- a/services/tests/servicestests/src/com/android/server/utils/WatcherTest.java +++ b/services/tests/servicestests/src/com/android/server/utils/WatcherTest.java @@ -916,5 +916,14 @@ public class WatcherTest {          assertTrue(s1 != s2);          assertTrue(leafA.get() == s1.get() + 1);          assertTrue(leafA.get() == s2.get()); + +        // Test sealed snapshots +        SnapshotCache<Leaf> sealed = new SnapshotCache.Sealed(); +        try { +            Leaf x1 = sealed.snapshot(); +            fail(name + " sealed snapshot did not throw"); +        } catch (UnsupportedOperationException e) { +            // This is the passing scenario - the exception is expected. +        }      }  } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java index a05fea2c8f70..1126e1ece452 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java @@ -21,6 +21,8 @@ import static android.service.notification.NotificationListenerService.REASON_CA  import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.fail; +  import android.app.Notification;  import android.os.UserHandle;  import android.service.notification.StatusBarNotification; @@ -37,7 +39,11 @@ import org.mockito.MockitoAnnotations;  import java.util.ArrayList;  import java.util.Arrays; +import java.util.ConcurrentModificationException;  import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean;  @SmallTest  @RunWith(AndroidJUnit4.class) @@ -165,4 +171,54 @@ public class ArchiveTest extends UiServiceTestCase {              assertThat(expected).contains(sbn.getKey());          }      } + +    @Test +    public void testRemoveChannelNotifications_concurrently() throws InterruptedException { +        List<String> expected = new ArrayList<>(); +        // Add one extra notification to the beginning to test when 2 adjacent notifications will be +        // removed in the same pass. +        StatusBarNotification sbn0 = getNotification("pkg", 0, UserHandle.of(USER_CURRENT)); +        mArchive.record(sbn0, REASON_CANCEL); +        for (int i = 0; i < SIZE; i++) { +            StatusBarNotification sbn = getNotification("pkg", i, UserHandle.of(USER_CURRENT)); +            mArchive.record(sbn, REASON_CANCEL); +            if (i >= SIZE - 2) { +                // Remove everything < SIZE - 2 +                expected.add(sbn.getKey()); +            } +        } + +        // Remove these in multiple threads to try to get them to happen at the same time +        int numThreads = SIZE - 2; +        AtomicBoolean error = new AtomicBoolean(false); +        CountDownLatch startThreadsLatch = new CountDownLatch(1); +        CountDownLatch threadsDone = new CountDownLatch(numThreads); +        for (int i = 0; i < numThreads; i++) { +            final int idx = i; +            new Thread(() -> { +                try { +                    startThreadsLatch.await(10, TimeUnit.SECONDS); +                } catch (InterruptedException e) { +                    throw new RuntimeException(e); +                } +                try { +                    mArchive.removeChannelNotifications("pkg", USER_CURRENT, "test" + idx); +                } catch (ConcurrentModificationException e) { +                    error.compareAndSet(false, true); +                } +            }).start(); +        } + +        startThreadsLatch.countDown(); +        threadsDone.await(10, TimeUnit.SECONDS); +        if (error.get()) { +            fail("Concurrent modification exception"); +        } + +        List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(SIZE, true)); +        assertThat(actual).hasSize(expected.size()); +        for (StatusBarNotification sbn : actual) { +            assertThat(expected).contains(sbn.getKey()); +        } +    }  } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index 537bc2c7d52c..c33287c57377 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -141,6 +141,7 @@ import android.os.Binder;  import android.os.Build;  import android.os.Bundle;  import android.os.IBinder; +import android.os.Looper;  import android.os.Parcel;  import android.os.Process;  import android.os.RemoteException; @@ -267,6 +268,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {      RankingHandler mRankingHandler;      @Mock      ActivityManagerInternal mAmi; +    @Mock +    private Looper mMainLooper;      @Mock      IIntentSender pi1; @@ -514,7 +517,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {                  mAppUsageStats, mock(DevicePolicyManagerInternal.class), mUgm, mUgmInternal,                  mAppOpsManager, mUm, mHistoryManager, mStatsManager, mock(TelephonyManager.class),                  mAmi, mToastRateLimiter); -        mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY); +        // Return first true for RoleObserver main-thread check +        when(mMainLooper.isCurrentThread()).thenReturn(true).thenReturn(false); +        mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY, mMainLooper);          mService.setAudioManager(mAudioManager); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java index 4ce237e3aadc..27ae46c87b28 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java @@ -16,6 +16,7 @@  package com.android.server.notification; +import static android.app.role.RoleManager.ROLE_BROWSER;  import static android.app.role.RoleManager.ROLE_DIALER;  import static android.app.role.RoleManager.ROLE_EMERGENCY;  import static android.content.pm.PackageManager.MATCH_ALL; @@ -23,6 +24,7 @@ import static android.content.pm.PackageManager.MATCH_ALL;  import static junit.framework.Assert.assertFalse;  import static junit.framework.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyBoolean;  import static org.mockito.Matchers.eq;  import static org.mockito.Mockito.any;  import static org.mockito.Mockito.mock; @@ -31,6 +33,8 @@ import static org.mockito.Mockito.times;  import static org.mockito.Mockito.verify;  import static org.mockito.Mockito.when; +import static java.util.Arrays.asList; +  import android.app.ActivityManager;  import android.app.ActivityManagerInternal;  import android.app.AppOpsManager; @@ -44,7 +48,6 @@ import android.companion.ICompanionDeviceManager;  import android.content.Context;  import android.content.pm.IPackageManager;  import android.content.pm.PackageManager; -import android.content.pm.UserInfo;  import android.os.Looper;  import android.os.UserHandle;  import android.os.UserManager; @@ -80,7 +83,6 @@ import org.mockito.MockitoAnnotations;  import java.util.ArrayList;  import java.util.List; -import java.util.concurrent.Executor;  @SmallTest  @RunWith(AndroidTestingRunner.class) @@ -98,13 +100,13 @@ public class RoleObserverTest extends UiServiceTestCase {      @Mock      private UserManager mUm;      @Mock -    private Executor mExecutor; -    @Mock      private RoleManager mRoleManager; +    @Mock +    private Looper mMainLooper;      NotificationRecordLoggerFake mNotificationRecordLogger = new NotificationRecordLoggerFake();      private InstanceIdSequence mNotificationInstanceIdSequence = new InstanceIdSequenceFake(              1 << 30); -    private List<UserInfo> mUsers; +    private List<UserHandle> mUsers;      private static class TestableNotificationManagerService extends NotificationManagerService {          TestableNotificationManagerService(Context context, @@ -133,13 +135,15 @@ public class RoleObserverTest extends UiServiceTestCase {          mContext.addMockSystemService(AppOpsManager.class, mock(AppOpsManager.class));          mUsers = new ArrayList<>(); -        mUsers.add(new UserInfo(0, "system", 0)); -        mUsers.add(new UserInfo(10, "second", 0)); -        when(mUm.getUsers()).thenReturn(mUsers); +        mUsers.add(new UserHandle(0)); +        mUsers.add(new UserHandle(10)); +        when(mUm.getUserHandles(anyBoolean())).thenReturn(mUsers); + +        when(mMainLooper.isCurrentThread()).thenReturn(true);          mService = new TestableNotificationManagerService(mContext, mNotificationRecordLogger,                  mNotificationInstanceIdSequence); -        mRoleObserver = mService.new RoleObserver(mRoleManager, mPm, mExecutor); +        mRoleObserver = mService.new RoleObserver(mContext, mRoleManager, mPm, mMainLooper);          try {              mService.init(mService.new WorkerHandler(mock(Looper.class)), @@ -174,7 +178,7 @@ public class RoleObserverTest extends UiServiceTestCase {      }      @Test -    public void testInit() throws Exception { +    public void testInit_forNonBlockableDefaultApps() throws Exception {          List<String> dialer0 = new ArrayList<>();          dialer0.add("dialer");          List<String> emer0 = new ArrayList<>(); @@ -191,29 +195,29 @@ public class RoleObserverTest extends UiServiceTestCase {          when(mRoleManager.getRoleHoldersAsUser(                  ROLE_DIALER, -                mUsers.get(0).getUserHandle())). -                thenReturn(dialer0); +                mUsers.get(0))) +                .thenReturn(dialer0);          when(mRoleManager.getRoleHoldersAsUser(                  ROLE_EMERGENCY, -                mUsers.get(0).getUserHandle())). -                thenReturn(emer0); +                mUsers.get(0))) +                .thenReturn(emer0);          mRoleObserver.init();          // verify internal records of current state of the world          assertTrue(mRoleObserver.isApprovedPackageForRoleForUser( -                ROLE_DIALER, dialer0.get(0), mUsers.get(0).id)); +                ROLE_DIALER, dialer0.get(0), mUsers.get(0).getIdentifier()));          assertFalse(mRoleObserver.isApprovedPackageForRoleForUser( -                ROLE_DIALER, dialer0.get(0), mUsers.get(1).id)); +                ROLE_DIALER, dialer0.get(0), mUsers.get(1).getIdentifier()));          assertTrue(mRoleObserver.isApprovedPackageForRoleForUser( -                ROLE_EMERGENCY, emer0.get(0), mUsers.get(0).id)); +                ROLE_EMERGENCY, emer0.get(0), mUsers.get(0).getIdentifier()));          assertFalse(mRoleObserver.isApprovedPackageForRoleForUser( -                ROLE_EMERGENCY, emer0.get(0), mUsers.get(1).id)); +                ROLE_EMERGENCY, emer0.get(0), mUsers.get(1).getIdentifier()));          // make sure we're listening to updates          verify(mRoleManager, times(1)).addOnRoleHoldersChangedListenerAsUser( -                eq(mExecutor), any(), eq(UserHandle.ALL)); +                any(), any(), eq(UserHandle.ALL));          // make sure we told pref helper about the state of the world          verify(mPreferencesHelper, times(1)).updateDefaultApps(0, null, dialer0Pair); @@ -221,14 +225,31 @@ public class RoleObserverTest extends UiServiceTestCase {      }      @Test -    public void testSwapDefault() throws Exception { +    public void testInit_forTrampolines() throws Exception { +        when(mPm.getPackageUid("com.browser", MATCH_ALL, 0)).thenReturn(30); +        when(mRoleManager.getRoleHoldersAsUser( +                ROLE_BROWSER, +                mUsers.get(0))) +                .thenReturn(asList("com.browser")); + +        mRoleObserver.init(); + +        assertTrue(mRoleObserver.isUidExemptFromTrampolineRestrictions(30)); + +        // make sure we're listening to updates +        verify(mRoleManager, times(1)).addOnRoleHoldersChangedListenerAsUser(any(), any(), +                eq(UserHandle.ALL)); +    } + +    @Test +    public void testSwapDefault_forNonBlockableDefaultApps() throws Exception {          List<String> dialer0 = new ArrayList<>();          dialer0.add("dialer");          when(mRoleManager.getRoleHoldersAsUser(                  ROLE_DIALER, -                mUsers.get(0).getUserHandle())). -                thenReturn(dialer0); +                mUsers.get(0))) +                .thenReturn(dialer0);          mRoleObserver.init(); @@ -241,8 +262,8 @@ public class RoleObserverTest extends UiServiceTestCase {          when(mRoleManager.getRoleHoldersAsUser(                  ROLE_DIALER, -                mUsers.get(0).getUserHandle())). -                thenReturn(newDefault); +                mUsers.get(0))) +                .thenReturn(newDefault);          mRoleObserver.onRoleHoldersChanged(ROLE_DIALER, UserHandle.of(0)); @@ -251,15 +272,39 @@ public class RoleObserverTest extends UiServiceTestCase {      }      @Test -    public void testSwapDefault_multipleOverlappingApps() throws Exception { +    public void testSwapDefault_forTrampolines() throws Exception { +        List<String> dialer0 = new ArrayList<>(); +        when(mPm.getPackageUid("com.browser", MATCH_ALL, 0)).thenReturn(30); +        when(mPm.getPackageUid("com.browser2", MATCH_ALL, 0)).thenReturn(31); +        when(mRoleManager.getRoleHoldersAsUser( +                ROLE_BROWSER, +                mUsers.get(0))) +                .thenReturn(asList("com.browser")); +        mRoleObserver.init(); +        assertTrue(mRoleObserver.isUidExemptFromTrampolineRestrictions(30)); +        assertFalse(mRoleObserver.isUidExemptFromTrampolineRestrictions(31)); +        // Default changed +        when(mRoleManager.getRoleHoldersAsUser( +                ROLE_BROWSER, +                mUsers.get(0))) +                .thenReturn(asList("com.browser2")); +        mRoleObserver.onRoleHoldersChanged(ROLE_BROWSER, UserHandle.of(0)); + +        assertFalse(mRoleObserver.isUidExemptFromTrampolineRestrictions(30)); +        assertTrue(mRoleObserver.isUidExemptFromTrampolineRestrictions(31)); +    } + +    @Test +    public void testSwapDefault_multipleOverlappingApps_forNonBlockableDefaultApps() +            throws Exception {          List<String> dialer0 = new ArrayList<>();          dialer0.add("dialer");          dialer0.add("phone");          when(mRoleManager.getRoleHoldersAsUser(                  ROLE_DIALER, -                mUsers.get(0).getUserHandle())). -                thenReturn(dialer0); +                mUsers.get(0))) +                .thenReturn(dialer0);          mRoleObserver.init(); @@ -273,8 +318,8 @@ public class RoleObserverTest extends UiServiceTestCase {          when(mRoleManager.getRoleHoldersAsUser(                  ROLE_DIALER, -                mUsers.get(0).getUserHandle())). -                thenReturn(newDefault); +                mUsers.get(0))) +                .thenReturn(newDefault);          ArraySet<String> expectedRemove = new ArraySet<>();          expectedRemove.add("dialer"); @@ -294,14 +339,14 @@ public class RoleObserverTest extends UiServiceTestCase {      }      @Test -    public void testSwapDefault_newUser() throws Exception { +    public void testSwapDefault_newUser_forNonBlockableDefaultApps() throws Exception {          List<String> dialer0 = new ArrayList<>();          dialer0.add("dialer");          when(mRoleManager.getRoleHoldersAsUser(                  ROLE_DIALER, -                mUsers.get(0).getUserHandle())). -                thenReturn(dialer0); +                mUsers.get(0))) +                .thenReturn(dialer0);          mRoleObserver.init(); @@ -310,8 +355,8 @@ public class RoleObserverTest extends UiServiceTestCase {          when(mRoleManager.getRoleHoldersAsUser(                  ROLE_DIALER, -                mUsers.get(1).getUserHandle())). -                thenReturn(dialer10); +                mUsers.get(1))) +                .thenReturn(dialer10);          ArraySet<Pair<String, Integer>> expectedAddPair = new ArraySet<>();          expectedAddPair.add(new Pair("phone", 30)); @@ -329,4 +374,27 @@ public class RoleObserverTest extends UiServiceTestCase {          assertTrue(mRoleObserver.isApprovedPackageForRoleForUser(ROLE_DIALER, "phone", 10));          assertTrue(mRoleObserver.isApprovedPackageForRoleForUser(ROLE_DIALER, "dialer", 0));      } + +    @Test +    public void testSwapDefault_newUser_forTrampolines() throws Exception { +        List<String> dialer0 = new ArrayList<>(); +        when(mPm.getPackageUid("com.browser", MATCH_ALL, 0)).thenReturn(30); +        when(mPm.getPackageUid("com.browser2", MATCH_ALL, 10)).thenReturn(1031); +        when(mRoleManager.getRoleHoldersAsUser( +                ROLE_BROWSER, +                mUsers.get(0))) +                .thenReturn(asList("com.browser")); +        mRoleObserver.init(); +        assertTrue(mRoleObserver.isUidExemptFromTrampolineRestrictions(30)); +        assertFalse(mRoleObserver.isUidExemptFromTrampolineRestrictions(1031)); +        // New user +        when(mRoleManager.getRoleHoldersAsUser( +                ROLE_BROWSER, +                mUsers.get(1))) +                .thenReturn(asList("com.browser2")); +        mRoleObserver.onRoleHoldersChanged(ROLE_BROWSER, UserHandle.of(10)); + +        assertTrue(mRoleObserver.isUidExemptFromTrampolineRestrictions(30)); +        assertTrue(mRoleObserver.isUidExemptFromTrampolineRestrictions(1031)); +    }  } 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 fdeb7a6eb71a..4bbea94060c4 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -1723,6 +1723,15 @@ public class ActivityRecordTests extends WindowTestsBase {          assertFalse(display.hasTopFixedRotationLaunchingApp());          assertFalse(activity.hasFixedRotationTransform()); + +        // Simulate that the activity requests the same orientation as display. +        activity.setOrientation(display.getConfiguration().orientation); +        // Skip the real freezing. +        activity.mVisibleRequested = false; +        clearInvocations(activity); +        activity.onCancelFixedRotationTransform(originalRotation); +        // The implementation of cancellation must be executed. +        verify(activity).startFreezingScreen(originalRotation);      }      @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java index 4f5511b55d3a..7614579b9c3b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java @@ -20,7 +20,6 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;  import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;  import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;  import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; -import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;  import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;  import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;  import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE; @@ -486,31 +485,6 @@ public class RootWindowContainerTests extends WindowTestsBase {      }      /** -     * Verify that split-screen primary root task will be chosen if activity is launched that -     * targets split-screen secondary, but a matching existing instance is found on top of -     * split-screen primary root task. -     */ -    @Test -    public void testSplitScreenPrimaryChosenWhenTopActivityLaunchedToSecondary() { -        // Create primary split-screen root task with a task and an activity. -        final Task primaryRootTask = mRootWindowContainer.getDefaultTaskDisplayArea() -                .createRootTask(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, -                        true /* onTop */); -        final Task task = new TaskBuilder(mSupervisor).setParentTask(primaryRootTask).build(); -        final ActivityRecord r = new ActivityBuilder(mAtm).setTask(task).build(); - -        // Find a launch root task for the top activity in split-screen primary, while requesting -        // split-screen secondary. -        final ActivityOptions options = ActivityOptions.makeBasic(); -        options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY); -        final Task result = -                mRootWindowContainer.getLaunchRootTask(r, options, task, true /* onTop */); - -        // Assert that the primary root task is returned. -        assertEquals(primaryRootTask, result); -    } - -    /**       * Verify that home root task would be moved to front when the top activity is Recents.       */      @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java index 13ef9982494e..9226c0b6f32b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java @@ -62,7 +62,6 @@ import static org.mockito.ArgumentMatchers.eq;  import static org.mockito.ArgumentMatchers.same;  import static org.mockito.Mockito.clearInvocations;  import static org.mockito.Mockito.never; -import static org.mockito.Mockito.reset;  import android.app.ActivityManager;  import android.app.TaskInfo; @@ -1323,20 +1322,22 @@ public class TaskTests extends WindowTestsBase {      }      @Test -    public void testNotifyOrientationChangeCausedByConfigurationChange() { +    public void testTaskOrientationOnDisplayWindowingModeChange() { +        // Skip unnecessary operations to speed up the test. +        mAtm.deferWindowLayout();          final Task task = getTestTask();          final ActivityRecord activity = task.getTopMostActivity();          final DisplayContent display = task.getDisplayContent(); -        display.setWindowingMode(WINDOWING_MODE_FREEFORM); +        mWm.setWindowingMode(display.mDisplayId, WINDOWING_MODE_FREEFORM);          activity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);          assertEquals(SCREEN_ORIENTATION_UNSET, task.getOrientation()); -        verify(display).onDescendantOrientationChanged(same(task)); -        reset(display); +        assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, display.getLastOrientation()); -        display.setWindowingMode(WINDOWING_MODE_FULLSCREEN); +        mWm.setWindowingMode(display.mDisplayId, WINDOWING_MODE_FULLSCREEN);          assertEquals(SCREEN_ORIENTATION_LANDSCAPE, task.getOrientation()); -        verify(display).onDescendantOrientationChanged(same(task)); +        assertEquals(SCREEN_ORIENTATION_LANDSCAPE, display.getLastOrientation()); +        assertEquals(Configuration.ORIENTATION_LANDSCAPE, display.getConfiguration().orientation);      }      @Test diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java index d77ab2b24b31..f0d43faed5ed 100755 --- a/telecomm/java/android/telecom/Call.java +++ b/telecomm/java/android/telecom/Call.java @@ -2543,6 +2543,7 @@ public final class Call {          } else if (mRttCall != null && parcelableCall.getParcelableRttCall() == null                  && parcelableCall.getIsRttCallChanged()) {              isRttChanged = true; +            mRttCall.close();              mRttCall = null;          } diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 2616ec8cc04f..114c90bbd87a 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -3402,7 +3402,10 @@ public class SubscriptionManager {       * Set uicc applications being enabled or disabled.       * The value will be remembered on the subscription and will be applied whenever it's present.       * If the subscription in currently present, it will also apply the setting to modem -     * immediately. +     * immediately (the setting in the modem will not change until the modem receives and responds +     * to the request, but typically this should only take a few seconds. The user visible setting +     * available from SubscriptionInfo.areUiccApplicationsEnabled() will be updated +     * immediately.)       *       * Permissions android.Manifest.permission.MODIFY_PHONE_STATE is required       * diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index d9001bd488f4..78da86c57ef1 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -15016,6 +15016,15 @@ public class TelephonyManager {              "CAPABILITY_SLICING_CONFIG_SUPPORTED";      /** +     * Indicates whether PHYSICAL_CHANNEL_CONFIG HAL1.6 is supported. See comments on +     * respective methods for more information. +     * +     * @hide +     */ +    public static final String CAPABILITY_PHYSICAL_CHANNEL_CONFIG_1_6_SUPPORTED = +            "CAPABILITY_PHYSICAL_CHANNEL_CONFIG_1_6_SUPPORTED"; + +    /**       * A list of the radio interface capability values with public valid constants.       *       * Here is a related list for the systemapi-only valid constants: diff --git a/telephony/java/android/telephony/ims/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java index ddd6fbe38cf4..18cc37d7fbda 100644 --- a/telephony/java/android/telephony/ims/feature/RcsFeature.java +++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java @@ -398,16 +398,6 @@ public class RcsFeature extends ImsFeature {      /**       * Remove the given CapabilityExchangeImplBase instance. -     * @param capExchangeImpl The {@link RcsCapabilityExchangeImplBase} instance to be removed. -     * @hide -     */ -    public void removeCapabilityExchangeImpl( -            @NonNull RcsCapabilityExchangeImplBase capExchangeImpl) { -        // Override to implement the process of removing RcsCapabilityExchangeImplBase instance. -    } - -    /** -     * Remove the given CapabilityExchangeImplBase instance.       * @param capExchangeImpl The {@link RcsCapabilityExchangeImplBase} instance to be destroyed.       */      public void destroyCapabilityExchangeImpl( @@ -450,7 +440,7 @@ public class RcsFeature extends ImsFeature {                  // Remove the RcsCapabilityExchangeImplBase instance when the capability exchange                  // instance has been removed in the framework.                  if (mCapabilityExchangeImpl != null) { -                    removeCapabilityExchangeImpl(mCapabilityExchangeImpl); +                    destroyCapabilityExchangeImpl(mCapabilityExchangeImpl);                  }                  mCapabilityExchangeImpl = null;              } @@ -468,7 +458,7 @@ public class RcsFeature extends ImsFeature {          synchronized (mLock) {              // Remove the original instance              if (mCapabilityExchangeImpl != null) { -                removeCapabilityExchangeImpl(mCapabilityExchangeImpl); +                destroyCapabilityExchangeImpl(mCapabilityExchangeImpl);              }              mCapabilityExchangeImpl = createCapabilityExchangeImpl(listener);          } diff --git a/test-mock/Android.bp b/test-mock/Android.bp index a2447d71c3bd..b83bce654a85 100644 --- a/test-mock/Android.bp +++ b/test-mock/Android.bp @@ -38,6 +38,7 @@ java_sdk_library {      ],      libs: [          "framework", +        "framework-annotations-lib",          "app-compat-annotations",          "unsupportedappusage",      ], diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml index 6bf44920ee26..04a55d6038b0 100644 --- a/tests/HwAccelerationTest/AndroidManifest.xml +++ b/tests/HwAccelerationTest/AndroidManifest.xml @@ -409,6 +409,15 @@              </intent-filter>          </activity> +        <activity android:name="ScrollingStretchSurfaceViewActivity" +                  android:label="SurfaceView/Scrolling Stretched SurfaceView" +                  android:exported="true"> +            <intent-filter> +                <action android:name="android.intent.action.MAIN"/> +                <category android:name="com.android.test.hwui.TEST"/> +            </intent-filter> +        </activity> +          <activity android:name="GetBitmapSurfaceViewActivity"               android:label="SurfaceView/GetBitmap with Camera source"               android:exported="true"> diff --git a/tests/HwAccelerationTest/res/layout/scrolling_stretch_surfaceview.xml b/tests/HwAccelerationTest/res/layout/scrolling_stretch_surfaceview.xml new file mode 100644 index 000000000000..77f5e60dc091 --- /dev/null +++ b/tests/HwAccelerationTest/res/layout/scrolling_stretch_surfaceview.xml @@ -0,0 +1,76 @@ +<?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. +  --> + +<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" +            android:overScrollMode="always" +            android:fillViewport="true" +            android:layout_width="match_parent" +            android:layout_height="match_parent"> + +    <LinearLayout +        android:layout_width="match_parent" +        android:layout_height="match_parent" +        android:orientation="vertical" +    > +        <LinearLayout +            android:layout_width="match_parent" +            android:layout_height="100dp" +            android:layout_marginTop="100dp" +            android:orientation="horizontal" +        > + +            <ImageView +                android:id="@+id/vertical_imageview" +                android:layout_width="0dp" +                android:layout_weight="1" +                android:layout_height="match_parent"/> +            <FrameLayout +                android:id="@+id/vertical_surfaceview_container" +                android:layout_width="0dp" +                android:layout_height="match_parent" +                android:layout_weight="1"/> +        </LinearLayout> + +        <HorizontalScrollView +            android:overScrollMode="always" +            android:layout_width="400dp" +            android:layout_height="0dp" +            android:background="#FF0000" +            android:layout_weight="1" +        > +            <LinearLayout +                android:layout_width="400dp" +                android:layout_height="400dp" +                android:layout_marginLeft="100dp" +                android:orientation="vertical"> + +                <ImageView +                    android:id="@+id/horizontal_imageview" +                    android:layout_width="100dp" +                    android:layout_weight="1" +                    android:layout_height="0dp"/> + +                <FrameLayout +                    android:id="@+id/horizontal_surfaceview_container" +                    android:layout_width="100dp" +                    android:layout_height="0dp" +                    android:layout_weight="1"/> + +            </LinearLayout> +        </HorizontalScrollView> +    </LinearLayout> +</ScrollView>
\ No newline at end of file diff --git a/tests/HwAccelerationTest/res/layout/stretch_layout.xml b/tests/HwAccelerationTest/res/layout/stretch_layout.xml index df5f297da729..81e0c019490f 100644 --- a/tests/HwAccelerationTest/res/layout/stretch_layout.xml +++ b/tests/HwAccelerationTest/res/layout/stretch_layout.xml @@ -16,7 +16,6 @@  <ScrollView      xmlns:android="http://schemas.android.com/apk/res/android"      android:id="@+id/scroll_view" -    android:edgeEffectType="stretch"      android:layout_width="match_parent"      android:layout_height="match_parent" >      <LinearLayout @@ -26,7 +25,6 @@          <HorizontalScrollView              android:id="@+id/horizontal_scroll_view" -            android:edgeEffectType="stretch"              android:layout_width="match_parent"              android:layout_height="match_parent">              <LinearLayout diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/PositionListenerActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/PositionListenerActivity.java index 6b6287da2711..2ad034cd143e 100644 --- a/tests/HwAccelerationTest/src/com/android/test/hwui/PositionListenerActivity.java +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/PositionListenerActivity.java @@ -74,12 +74,10 @@ public class PositionListenerActivity extends Activity {                  float maxStretchAmount = 100f;                  // Although we could do this in a single call, the real one won't be - so mimic that                  if (dir.x != 0f) { -                    node.stretch(0f, 0f, (float) getWidth(), (float) getHeight(), -                            dir.x, 0f, maxStretchAmount, maxStretchAmount); +                    node.stretch(dir.x, 0f, maxStretchAmount, maxStretchAmount);                  }                  if (dir.y != 0f) { -                    node.stretch(0f, 0f, (float) getWidth(), (float) getHeight(), -                            0f, dir.y, maxStretchAmount, maxStretchAmount); +                    node.stretch(0f, dir.y, maxStretchAmount, maxStretchAmount);                  }              }          }; @@ -94,10 +92,13 @@ public class PositionListenerActivity extends Activity {          int mCurrentCount = 0;          int mTranslateY = 0;          Rect mPosition = new Rect(); -        RectF mStretchArea = new RectF(); +        float mWidth = 0f; +        float mHeight = 0f; +        RectF mMappedBounds = new RectF();          float mStretchX = 0.0f;          float mStretchY = 0.0f; -        float mStretchMax = 0.0f; +        float mStretchMaxX = 0.0f; +        float mStretchMaxY = 0.0f;          MyPositionReporter(Context c) {              super(c); @@ -128,9 +129,12 @@ public class PositionListenerActivity extends Activity {          }          void updateText() { -            setText(String.format("%d: Position %s, stretch area %s, vec %f,%f, amount %f", -                    mCurrentCount, mPosition.toShortString(), mStretchArea.toShortString(), -                    mStretchX, mStretchY, mStretchMax)); +            String posText = +              "%d: Position %s, stretch width %f, height %f, vec %f,%f, amountX %f amountY %f mappedBounds %s"; +            setText(String.format(posText, +                    mCurrentCount, mPosition.toShortString(), mWidth, mHeight, +                    mStretchX, mStretchY, mStretchMaxX, mStretchMaxY, +                    mMappedBounds.toShortString()));          }          @Override @@ -143,13 +147,19 @@ public class PositionListenerActivity extends Activity {          }          @Override -        public void applyStretch(long frameNumber, float left, float top, float right, float bottom, -                float vecX, float vecY, float maxStretch) { +        public void applyStretch(long frameNumber, float width, float height, +                float vecX, float vecY, +                float maxStretchX, float maxStretchY, float childRelativeLeft, +                float childRelativeTop, float childRelativeRight, float childRelativeBottom) {              getHandler().postAtFrontOfQueue(() -> { -                mStretchArea.set(left, top, right, bottom); +                mWidth = width; +                mHeight = height;                  mStretchX = vecX;                  mStretchY = vecY; -                mStretchMax = maxStretch; +                mStretchMaxX = maxStretchX; +                mStretchMaxY = maxStretchY; +                mMappedBounds.set(childRelativeLeft, childRelativeTop, childRelativeRight, +                        childRelativeBottom);                  updateText();              });          } diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ScrollingStretchSurfaceViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ScrollingStretchSurfaceViewActivity.java new file mode 100644 index 000000000000..040bff5d74d8 --- /dev/null +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ScrollingStretchSurfaceViewActivity.java @@ -0,0 +1,113 @@ +/* + * 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.test.hwui; + +import android.app.Activity; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.view.SurfaceHolder; +import android.view.SurfaceHolder.Callback; +import android.view.SurfaceView; +import android.widget.FrameLayout; +import android.widget.ImageView; + +public class ScrollingStretchSurfaceViewActivity extends Activity implements Callback { + +    SurfaceView mVerticalSurfaceView; +    SurfaceView mHorizontalSurfaceView; + +    @Override +    protected void onCreate(Bundle savedInstanceState) { +        super.onCreate(savedInstanceState); +        setContentView(R.layout.scrolling_stretch_surfaceview); + +        mVerticalSurfaceView = new SurfaceView(this); +        mVerticalSurfaceView.getHolder().addCallback(this); + +        mHorizontalSurfaceView = new SurfaceView(this); +        mHorizontalSurfaceView.getHolder().addCallback(this); + +        FrameLayout verticalContainer = findViewById(R.id.vertical_surfaceview_container); +        verticalContainer.addView(mVerticalSurfaceView, +            new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, +                FrameLayout.LayoutParams.MATCH_PARENT)); + +        FrameLayout horizontalContainer = findViewById(R.id.horizontal_surfaceview_container); +        horizontalContainer.addView(mHorizontalSurfaceView, +            new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, +                FrameLayout.LayoutParams.MATCH_PARENT)); + +        ImageView verticalImageView = findViewById(R.id.vertical_imageview); +        verticalImageView.setImageDrawable(new LineDrawable()); + +        ImageView horizontalImageView = findViewById(R.id.horizontal_imageview); +        horizontalImageView.setImageDrawable(new LineDrawable()); +    } + +    @Override +    public void surfaceCreated(SurfaceHolder holder) { +    } + +    @Override +    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { +        Canvas canvas = holder.lockCanvas(); + +        drawLine(canvas, width, height); +        holder.unlockCanvasAndPost(canvas); +    } + +    private static void drawLine(Canvas canvas, int width, int height) { +        canvas.drawColor(Color.GRAY); + +        Paint paint = new Paint(); +        paint.setAntiAlias(true); +        paint.setColor(Color.GREEN); +        paint.setStyle(Paint.Style.STROKE); +        paint.setStrokeWidth(10f); +        canvas.drawLine(0, 0, width, height, paint); +    } + +    private static class LineDrawable extends Drawable { +        @Override +        public void draw(Canvas canvas) { +            drawLine(canvas, getBounds().width(), getBounds().height()); +        } + +        @Override +        public void setAlpha(int alpha) { +            // NO-OP +        } + +        @Override +        public void setColorFilter(ColorFilter colorFilter) { +            // NO-OP +        } + +        @Override +        public int getOpacity() { +            return 0; +        } +    } + +    @Override +    public void surfaceDestroyed(SurfaceHolder holder) { +    } +} diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/StretchShaderActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/StretchShaderActivity.java index ade94a9672bc..3307c36d9d1a 100644 --- a/tests/HwAccelerationTest/src/com/android/test/hwui/StretchShaderActivity.java +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/StretchShaderActivity.java @@ -409,10 +409,6 @@ public class StretchShaderActivity extends Activity {              if (mStretchDistance > 0 && canvas instanceof RecordingCanvas) {                  Rect bounds = getBounds();                  ((RecordingCanvas) canvas).mNode.stretch( -                        0, -                        0, -                        bounds.width(), -                        bounds.height(),                          mOverScrollX,                          mOverScrollY,                          mStretchDistance, diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/StretchySurfaceViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/StretchySurfaceViewActivity.java index 67b9be580ba6..acb872cd23b8 100644 --- a/tests/HwAccelerationTest/src/com/android/test/hwui/StretchySurfaceViewActivity.java +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/StretchySurfaceViewActivity.java @@ -99,7 +99,7 @@ public class StretchySurfaceViewActivity extends Activity implements Callback {                  super.onDraw(canvas);                  RenderNode node = ((RecordingCanvas) canvas).mNode; -                node.stretch(0f, 0f, getWidth(), getHeight() / 2f, 0f, +                node.stretch(0f,                          1f, 400f, 400f);              }          }; diff --git a/tests/Input/src/com/android/test/input/ViewFrameInfoTest.kt b/tests/Input/src/com/android/test/input/ViewFrameInfoTest.kt index c01d32bf4cd2..6ef1ecdae59b 100644 --- a/tests/Input/src/com/android/test/input/ViewFrameInfoTest.kt +++ b/tests/Input/src/com/android/test/input/ViewFrameInfoTest.kt @@ -35,7 +35,7 @@ class ViewFrameInfoTest {      fun setUp() {          mViewFrameInfo.reset()          mViewFrameInfo.setInputEvent(139) -        mViewFrameInfo.flags = mViewFrameInfo.flags or FrameInfo.FLAG_WINDOW_LAYOUT_CHANGED +        mViewFrameInfo.flags = mViewFrameInfo.flags or FrameInfo.FLAG_WINDOW_VISIBILITY_CHANGED          mTimeStarted = SystemClock.uptimeNanos()          mViewFrameInfo.markDrawStart()      } @@ -43,7 +43,7 @@ class ViewFrameInfoTest {      @Test      fun testPopulateFields() {          assertThat(mViewFrameInfo.drawStart).isGreaterThan(mTimeStarted) -        assertThat(mViewFrameInfo.flags).isEqualTo(FrameInfo.FLAG_WINDOW_LAYOUT_CHANGED) +        assertThat(mViewFrameInfo.flags).isEqualTo(FrameInfo.FLAG_WINDOW_VISIBILITY_CHANGED)      }      @Test @@ -66,7 +66,7 @@ class ViewFrameInfoTest {          mViewFrameInfo.populateFrameInfo(frameInfo)          assertThat(frameInfo.frameInfo[FrameInfo.INPUT_EVENT_ID]).isEqualTo(139)          assertThat(frameInfo.frameInfo[FrameInfo.FLAGS]).isEqualTo( -                FrameInfo.FLAG_WINDOW_LAYOUT_CHANGED) +                FrameInfo.FLAG_WINDOW_VISIBILITY_CHANGED)          assertThat(frameInfo.frameInfo[FrameInfo.DRAW_START]).isGreaterThan(mTimeStarted)      }  }
\ No newline at end of file diff --git a/tests/UpdatableSystemFontTest/Android.bp b/tests/UpdatableSystemFontTest/Android.bp index 8b0ae5c37bae..ea5a43104bba 100644 --- a/tests/UpdatableSystemFontTest/Android.bp +++ b/tests/UpdatableSystemFontTest/Android.bp @@ -21,16 +21,15 @@ package {      default_applicable_licenses: ["frameworks_base_license"],  } -java_test_host { +android_test {      name: "UpdatableSystemFontTest",      srcs: ["src/**/*.java"], -    libs: [ -        "tradefed", -        "compatibility-tradefed", -        "compatibility-host-util", -    ], +    libs: ["android.test.runner"],      static_libs: [ -        "frameworks-base-hostutils", +        "androidx.test.ext.junit", +        "compatibility-device-util-axt", +        "platform-test-annotations", +        "truth-prebuilt",      ],      test_suites: [          "general-tests", @@ -47,4 +46,5 @@ java_test_host {          ":UpdatableSystemFontTestNotoColorEmojiVPlus2Ttf",          ":UpdatableSystemFontTestNotoColorEmojiVPlus2TtfFsvSig",      ], +    sdk_version: "test_current",  } diff --git a/tests/UpdatableSystemFontTest/AndroidManifest.xml b/tests/UpdatableSystemFontTest/AndroidManifest.xml new file mode 100644 index 000000000000..531ee981a92c --- /dev/null +++ b/tests/UpdatableSystemFontTest/AndroidManifest.xml @@ -0,0 +1,30 @@ +<?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. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" +    package="com.android.updatablesystemfont"> + +    <application android:label="UpdatableSystemFontTest"> +        <uses-library android:name="android.test.runner"/> +    </application> + +    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" +         android:label="UpdatableSystemFontTest" +         android:targetPackage="com.android.updatablesystemfont"> +    </instrumentation> + +</manifest> diff --git a/tests/UpdatableSystemFontTest/AndroidTest.xml b/tests/UpdatableSystemFontTest/AndroidTest.xml index 4f116698ba72..4f6487e7e953 100644 --- a/tests/UpdatableSystemFontTest/AndroidTest.xml +++ b/tests/UpdatableSystemFontTest/AndroidTest.xml @@ -21,6 +21,7 @@      <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">          <option name="cleanup-apks" value="true" /> +        <option name="test-file-name" value="UpdatableSystemFontTest.apk" />          <option name="test-file-name" value="EmojiRenderingTestApp.apk" />      </target_preparer> @@ -37,7 +38,7 @@          <option name="push" value="UpdatableSystemFontTestNotoColorEmojiVPlus2.ttf.fsv_sig->/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiVPlus2.ttf.fsv_sig" />      </target_preparer> -    <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" > -        <option name="jar" value="UpdatableSystemFontTest.jar" /> +    <test class="com.android.tradefed.testtype.AndroidJUnitTest"> +        <option name="package" value="com.android.updatablesystemfont" />      </test>  </configuration> diff --git a/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java b/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java index 74f6bca4d7a0..9793c3447ff2 100644 --- a/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java +++ b/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java @@ -16,44 +16,59 @@  package com.android.updatablesystemfont; +import static android.os.ParcelFileDescriptor.MODE_READ_ONLY; +  import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth.assertWithMessage; + +import static org.junit.Assume.assumeTrue;  import static java.util.concurrent.TimeUnit.SECONDS; +import android.app.UiAutomation; +import android.content.Context; +import android.graphics.fonts.FontFamilyUpdateRequest; +import android.graphics.fonts.FontFileUpdateRequest; +import android.graphics.fonts.FontManager; +import android.os.ParcelFileDescriptor;  import android.platform.test.annotations.RootPermissionTest; +import android.security.FileIntegrityManager; +import android.text.FontConfig; +import android.util.Log; +import android.util.Pair; -import com.android.fsverity.AddFsVerityCertRule; -import com.android.tradefed.device.DeviceNotAvailableException; -import com.android.tradefed.log.LogUtil.CLog; -import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; -import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; -import com.android.tradefed.util.CommandResult; -import com.android.tradefed.util.CommandStatus; +import androidx.annotation.Nullable; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.platform.app.InstrumentationRegistry; + +import com.android.compatibility.common.util.StreamUtil; +import com.android.compatibility.common.util.SystemUtil;  import org.junit.After;  import org.junit.Before; -import org.junit.Rule;  import org.junit.Test;  import org.junit.runner.RunWith; -import java.util.regex.Matcher; -import java.util.regex.Pattern; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Paths;  /** - * Tests if fonts can be updated by 'cmd font'. + * Tests if fonts can be updated by {@link FontManager} API.   */  @RootPermissionTest -@RunWith(DeviceJUnit4ClassRunner.class) -public class UpdatableSystemFontTest extends BaseHostJUnit4Test { +@RunWith(AndroidJUnit4.class) +public class UpdatableSystemFontTest { +    private static final String TAG = "UpdatableSystemFontTest";      private static final String SYSTEM_FONTS_DIR = "/system/fonts/";      private static final String DATA_FONTS_DIR = "/data/fonts/files/"; -      private static final String CERT_PATH = "/data/local/tmp/UpdatableSystemFontTestCert.der"; - -    private static final Pattern PATTERN_FONT = Pattern.compile("path = ([^, \n]*)"); -    private static final String NOTO_COLOR_EMOJI_TTF = "NotoColorEmoji.ttf"; +    private static final String NOTO_COLOR_EMOJI_POSTSCRIPT_NAME = "NotoColorEmoji";      private static final String ORIGINAL_NOTO_COLOR_EMOJI_TTF =              "/data/local/tmp/NotoColorEmoji.ttf"; @@ -80,64 +95,75 @@ public class UpdatableSystemFontTest extends BaseHostJUnit4Test {              EMOJI_RENDERING_TEST_APP_ID + "/.EmojiRenderingTestActivity";      private static final long ACTIVITY_TIMEOUT_MILLIS = SECONDS.toMillis(10); -    private interface ThrowingSupplier<T> { -        T get() throws Exception; -    } - -    @Rule -    public final AddFsVerityCertRule mAddFsverityCertRule = -            new AddFsVerityCertRule(this, CERT_PATH); +    private String mKeyId; +    private FontManager mFontManager;      @Before      public void setUp() throws Exception { -        expectRemoteCommandToSucceed("cmd font clear"); +        Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); +        // Run tests only if updatable system font is enabled. +        FileIntegrityManager fim = context.getSystemService(FileIntegrityManager.class); +        assumeTrue(fim != null); +        assumeTrue(fim.isApkVeritySupported()); +        mKeyId = insertCert(CERT_PATH); +        mFontManager = context.getSystemService(FontManager.class); +        expectCommandToSucceed("cmd font clear");      }      @After      public void tearDown() throws Exception { -        expectRemoteCommandToSucceed("cmd font clear"); +        expectCommandToSucceed("cmd font clear"); +        if (mKeyId != null) { +            expectCommandToSucceed("mini-keyctl unlink " + mKeyId + " .fs-verity"); +        }      }      @Test      public void updateFont() throws Exception { -        expectRemoteCommandToSucceed(String.format("cmd font update %s %s", -                TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG)); -        String fontPath = getFontPath(NOTO_COLOR_EMOJI_TTF); +        assertThat(updateFontFile( +                TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG)) +                .isEqualTo(FontManager.RESULT_SUCCESS); +        String fontPath = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);          assertThat(fontPath).startsWith(DATA_FONTS_DIR);          // The updated font should be readable and unmodifiable. -        expectRemoteCommandToSucceed("cat " + fontPath + " > /dev/null"); -        expectRemoteCommandToFail("echo -n '' >> " + fontPath); +        expectCommandToSucceed("dd status=none if=" + fontPath + " of=/dev/null"); +        expectCommandToFail("dd status=none if=" + CERT_PATH + " of=" + fontPath);      }      @Test      public void updateFont_twice() throws Exception { -        expectRemoteCommandToSucceed(String.format("cmd font update %s %s", -                TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG)); -        String fontPath = getFontPath(NOTO_COLOR_EMOJI_TTF); -        expectRemoteCommandToSucceed(String.format("cmd font update %s %s", -                TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF_FSV_SIG)); -        String fontPath2 = getFontPath(NOTO_COLOR_EMOJI_TTF); +        assertThat(updateFontFile( +                TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG)) +                .isEqualTo(FontManager.RESULT_SUCCESS); +        String fontPath = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME); +        assertThat(updateFontFile( +                TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF_FSV_SIG)) +                .isEqualTo(FontManager.RESULT_SUCCESS); +        String fontPath2 = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);          assertThat(fontPath2).startsWith(DATA_FONTS_DIR);          assertThat(fontPath2).isNotEqualTo(fontPath);          // The new file should be readable. -        expectRemoteCommandToSucceed("cat " + fontPath2 + " > /dev/null"); +        expectCommandToSucceed("dd status=none if=" + fontPath2 + " of=/dev/null");          // The old file should be still readable. -        expectRemoteCommandToSucceed("cat " + fontPath + " > /dev/null"); +        expectCommandToSucceed("dd status=none if=" + fontPath + " of=/dev/null");      }      @Test      public void updateFont_allowSameVersion() throws Exception {          // Update original font to the same version -        expectRemoteCommandToSucceed(String.format("cmd font update %s %s", -                ORIGINAL_NOTO_COLOR_EMOJI_TTF, ORIGINAL_NOTO_COLOR_EMOJI_TTF_FSV_SIG)); -        String fontPath = getFontPath(NOTO_COLOR_EMOJI_TTF); -        expectRemoteCommandToSucceed(String.format("cmd font update %s %s", -                TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG)); -        String fontPath2 = getFontPath(NOTO_COLOR_EMOJI_TTF); +        assertThat(updateFontFile( +                ORIGINAL_NOTO_COLOR_EMOJI_TTF, ORIGINAL_NOTO_COLOR_EMOJI_TTF_FSV_SIG)) +                .isEqualTo(FontManager.RESULT_SUCCESS); +        String fontPath = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME); +        assertThat(updateFontFile( +                TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG)) +                .isEqualTo(FontManager.RESULT_SUCCESS); +        String fontPath2 = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);          // Update updated font to the same version -        expectRemoteCommandToSucceed(String.format("cmd font update %s %s", -                TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG)); -        String fontPath3 = getFontPath(NOTO_COLOR_EMOJI_TTF); +        assertThat(updateFontFile( +                TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG)) +                .isEqualTo(FontManager.RESULT_SUCCESS); +        String fontPath3 = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);          assertThat(fontPath).startsWith(DATA_FONTS_DIR);          assertThat(fontPath2).isNotEqualTo(fontPath);          assertThat(fontPath2).startsWith(DATA_FONTS_DIR); @@ -147,134 +173,171 @@ public class UpdatableSystemFontTest extends BaseHostJUnit4Test {      @Test      public void updateFont_invalidCert() throws Exception { -        expectRemoteCommandToFail(String.format("cmd font update %s %s", -                TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF_FSV_SIG)); +        assertThat(updateFontFile( +                TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF_FSV_SIG)) +                .isEqualTo(FontManager.RESULT_ERROR_VERIFICATION_FAILURE);      }      @Test      public void updateFont_downgradeFromSystem() throws Exception { -        expectRemoteCommandToFail(String.format("cmd font update %s %s", -                TEST_NOTO_COLOR_EMOJI_V0_TTF, TEST_NOTO_COLOR_EMOJI_V0_TTF_FSV_SIG)); +        assertThat(updateFontFile( +                TEST_NOTO_COLOR_EMOJI_V0_TTF, TEST_NOTO_COLOR_EMOJI_V0_TTF_FSV_SIG)) +                .isEqualTo(FontManager.RESULT_ERROR_DOWNGRADING);      }      @Test      public void updateFont_downgradeFromData() throws Exception { -        expectRemoteCommandToSucceed(String.format("cmd font update %s %s", -                TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF_FSV_SIG)); -        expectRemoteCommandToFail(String.format("cmd font update %s %s", -                TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG)); +        assertThat(updateFontFile( +                TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF_FSV_SIG)) +                .isEqualTo(FontManager.RESULT_SUCCESS); +        assertThat(updateFontFile( +                TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG)) +                .isEqualTo(FontManager.RESULT_ERROR_DOWNGRADING);      }      @Test      public void launchApp() throws Exception { -        String fontPath = getFontPath(NOTO_COLOR_EMOJI_TTF); +        String fontPath = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);          assertThat(fontPath).startsWith(SYSTEM_FONTS_DIR);          startActivity(EMOJI_RENDERING_TEST_APP_ID, EMOJI_RENDERING_TEST_ACTIVITY); -        waitUntil(ACTIVITY_TIMEOUT_MILLIS, () -> -                isFileOpenedBy(fontPath, EMOJI_RENDERING_TEST_APP_ID)); +        SystemUtil.eventually( +                () -> assertThat(isFileOpenedBy(fontPath, EMOJI_RENDERING_TEST_APP_ID)).isTrue(), +                ACTIVITY_TIMEOUT_MILLIS);      }      @Test      public void launchApp_afterUpdateFont() throws Exception { -        String originalFontPath = getFontPath(NOTO_COLOR_EMOJI_TTF); +        String originalFontPath = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);          assertThat(originalFontPath).startsWith(SYSTEM_FONTS_DIR); -        expectRemoteCommandToSucceed(String.format("cmd font update %s %s", -                TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG)); -        String updatedFontPath = getFontPath(NOTO_COLOR_EMOJI_TTF); +        assertThat(updateFontFile( +                TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG)) +                .isEqualTo(FontManager.RESULT_SUCCESS); +        String updatedFontPath = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);          assertThat(updatedFontPath).startsWith(DATA_FONTS_DIR);          startActivity(EMOJI_RENDERING_TEST_APP_ID, EMOJI_RENDERING_TEST_ACTIVITY);          // The original font should NOT be opened by the app. -        waitUntil(ACTIVITY_TIMEOUT_MILLIS, () -> -                isFileOpenedBy(updatedFontPath, EMOJI_RENDERING_TEST_APP_ID) -                        && !isFileOpenedBy(originalFontPath, EMOJI_RENDERING_TEST_APP_ID)); +        SystemUtil.eventually(() -> { +            assertThat(isFileOpenedBy(updatedFontPath, EMOJI_RENDERING_TEST_APP_ID)).isTrue(); +            assertThat(isFileOpenedBy(originalFontPath, EMOJI_RENDERING_TEST_APP_ID)).isFalse(); +        }, ACTIVITY_TIMEOUT_MILLIS);      }      @Test      public void reboot() throws Exception { -        expectRemoteCommandToSucceed(String.format("cmd font update %s %s", +        expectCommandToSucceed(String.format("cmd font update %s %s",                  TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG)); -        String fontPath = getFontPath(NOTO_COLOR_EMOJI_TTF); +        String fontPath = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);          assertThat(fontPath).startsWith(DATA_FONTS_DIR);          // Emulate reboot by 'cmd font restart'. -        expectRemoteCommandToSucceed("cmd font restart"); -        String fontPathAfterReboot = getFontPath(NOTO_COLOR_EMOJI_TTF); +        expectCommandToSucceed("cmd font restart"); +        String fontPathAfterReboot = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);          assertThat(fontPathAfterReboot).isEqualTo(fontPath);      } -    private String getFontPath(String fontFileName) throws Exception { -        // TODO: add a dedicated command for testing. -        String lines = expectRemoteCommandToSucceed("cmd font dump"); -        for (String line : lines.split("\n")) { -            Matcher m = PATTERN_FONT.matcher(line); -            if (m.find() && m.group(1).endsWith(fontFileName)) { -                return m.group(1); -            } +    private static String insertCert(String certPath) throws Exception { +        Pair<String, String> result; +        try (InputStream is = new FileInputStream(certPath)) { +            result = runShellCommand("mini-keyctl padd asymmetric fsv_test .fs-verity", is); +        } +        // Assert that there are no errors. +        assertThat(result.second).isEmpty(); +        String keyId = result.first.trim(); +        assertThat(keyId).matches("^\\d+$"); +        return keyId; +    } + +    private int updateFontFile(String fontPath, String signaturePath) throws IOException { +        byte[] signature = Files.readAllBytes(Paths.get(signaturePath)); +        try (ParcelFileDescriptor fd = +                ParcelFileDescriptor.open(new File(fontPath), MODE_READ_ONLY)) { +            return SystemUtil.runWithShellPermissionIdentity(() -> { +                FontConfig fontConfig = mFontManager.getFontConfig(); +                return mFontManager.updateFontFamily( +                        new FontFamilyUpdateRequest.Builder() +                                .addFontFileUpdateRequest(new FontFileUpdateRequest(fd, signature)) +                                .build(), +                        fontConfig.getConfigVersion()); +            });          } -        CLog.e("Font not found: " + fontFileName); -        return null;      } -    private void startActivity(String appId, String activityId) throws Exception { -        // Make sure that the app is installed and enabled. -        waitUntil(ACTIVITY_TIMEOUT_MILLIS, () -> { -            String packageInfo = expectRemoteCommandToSucceed( -                    "pm list packages -e " + EMOJI_RENDERING_TEST_APP_ID); -            return !packageInfo.isEmpty(); +    private String getFontPath(String psName) { +        return SystemUtil.runWithShellPermissionIdentity(() -> { +            FontConfig fontConfig = mFontManager.getFontConfig(); +            for (FontConfig.FontFamily family : fontConfig.getFontFamilies()) { +                for (FontConfig.Font font : family.getFontList()) { +                    if (psName.equals(font.getPostScriptName())) { +                        return font.getFile().getAbsolutePath(); +                    } +                } +            } +            throw new AssertionError("Font not found: " + psName);          }); -        expectRemoteCommandToSucceed("am force-stop " + EMOJI_RENDERING_TEST_APP_ID); -        expectRemoteCommandToSucceed("am start-activity -n " + EMOJI_RENDERING_TEST_ACTIVITY);      } -    private String expectRemoteCommandToSucceed(String cmd) throws Exception { -        CommandResult result = getDevice().executeShellV2Command(cmd); -        assertWithMessage("`" + cmd + "` failed: " + result.getStderr()) -                .that(result.getStatus()) -                .isEqualTo(CommandStatus.SUCCESS); -        return result.getStdout(); +    private static void startActivity(String appId, String activityId) throws Exception { +        expectCommandToSucceed("am force-stop " + appId); +        expectCommandToSucceed("am start-activity -n " + activityId); +    } + +    private static String expectCommandToSucceed(String cmd) throws IOException { +        Pair<String, String> result = runShellCommand(cmd, null); +        // UiAutomation.runShellCommand() does not return exit code. +        // Assume that the command fails if stderr is not empty. +        assertThat(result.second.trim()).isEmpty(); +        return result.first;      } -    private void expectRemoteCommandToFail(String cmd) throws Exception { -        CommandResult result = getDevice().executeShellV2Command(cmd); -        assertWithMessage("Unexpected success from `" + cmd + "`: " + result.getStderr()) -                .that(result.getStatus()) -                .isNotEqualTo(CommandStatus.SUCCESS); +    private static void expectCommandToFail(String cmd) throws IOException { +        Pair<String, String> result = runShellCommand(cmd, null); +        // UiAutomation.runShellCommand() does not return exit code. +        // Assume that the command fails if stderr is not empty. +        assertThat(result.second.trim()).isNotEmpty();      } -    private void waitUntil(long timeoutMillis, ThrowingSupplier<Boolean> func) { -        long untilMillis = System.currentTimeMillis() + timeoutMillis; -        do { -            try { -                if (func.get()) return; -                Thread.sleep(100); -            } catch (InterruptedException e) { -                throw new AssertionError("Interrupted", e); -            } catch (Exception e) { -                throw new AssertionError("Unexpected exception", e); +    /** Runs a command and returns (stdout, stderr). */ +    private static Pair<String, String> runShellCommand(String cmd, @Nullable InputStream input) +            throws IOException  { +        Log.i(TAG, "runShellCommand: " + cmd); +        UiAutomation automation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); +        ParcelFileDescriptor[] rwe = automation.executeShellCommandRwe(cmd); +        // executeShellCommandRwe returns [stdout, stdin, stderr]. +        try (ParcelFileDescriptor outFd = rwe[0]; +             ParcelFileDescriptor inFd = rwe[1]; +             ParcelFileDescriptor errFd = rwe[2]) { +            if (input != null) { +                try (OutputStream os = new FileOutputStream(inFd.getFileDescriptor())) { +                    StreamUtil.copyStreams(input, os); +                }              } -        } while (System.currentTimeMillis() < untilMillis); -        throw new AssertionError("Timed out"); +            // We have to close stdin before reading stdout and stderr. +            // It's safe to close ParcelFileDescriptor multiple times. +            inFd.close(); +            String stdout; +            try (InputStream is = new FileInputStream(outFd.getFileDescriptor())) { +                stdout = StreamUtil.readInputStream(is); +            } +            Log.i(TAG, "stdout =  " + stdout); +            String stderr; +            try (InputStream is = new FileInputStream(errFd.getFileDescriptor())) { +                stderr = StreamUtil.readInputStream(is); +            } +            Log.i(TAG, "stderr =  " + stderr); +            return new Pair<>(stdout, stderr); +        }      } -    private boolean isFileOpenedBy(String path, String appId) throws DeviceNotAvailableException { +    private static boolean isFileOpenedBy(String path, String appId) throws Exception {          String pid = pidOf(appId);          if (pid.isEmpty()) {              return false;          } -        CommandResult result = getDevice().executeShellV2Command( -                String.format("lsof -t -p %s '%s'", pid, path)); -        if (result.getStatus() != CommandStatus.SUCCESS) { -            return false; -        } -        // The file is open if the output of lsof is non-empty. -        return !result.getStdout().trim().isEmpty(); +        String cmd = String.format("lsof -t -p %s %s", pid, path); +        return !expectCommandToSucceed(cmd).trim().isEmpty();      } -    private String pidOf(String appId) throws DeviceNotAvailableException { -        CommandResult result = getDevice().executeShellV2Command("pidof " + appId); -        if (result.getStatus() != CommandStatus.SUCCESS) { -            return ""; -        } -        return result.getStdout().trim(); +    private static String pidOf(String appId) throws Exception { +        return expectCommandToSucceed("pidof " + appId).trim();      }  } diff --git a/tools/aapt/Android.bp b/tools/aapt/Android.bp index c75ba71c4432..a19d183d617b 100644 --- a/tools/aapt/Android.bp +++ b/tools/aapt/Android.bp @@ -124,6 +124,9 @@ cc_binary_host {      srcs: ["Main.cpp"],      use_version_lib: true,      static_libs: ["libaapt"], +    dist: { +        targets: ["aapt2_artifacts"], +    },  }  // ========================================================== diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp index 21386b88ce2c..f2c3b86e409e 100644 --- a/tools/aapt/Command.cpp +++ b/tools/aapt/Command.cpp @@ -969,6 +969,8 @@ int doDump(Bundle* bundle)                  densities.add(dens);              } +            std::vector<ResXMLParser::ResXMLPosition> tagsToSkip; +              size_t len;              ResXMLTree::event_code_t code;              int depth = 0; @@ -1091,6 +1093,42 @@ int doDump(Bundle* bundle)              Vector<FeatureGroup> featureGroups;              KeyedVector<String8, ImpliedFeature> impliedFeatures; +            { +                int curDepth = 0; +                ResXMLParser::ResXMLPosition initialPos; +                tree.getPosition(&initialPos); + +                // Find all of the "uses-sdk" tags within the "manifest" tag. +                std::vector<ResXMLParser::ResXMLPosition> usesSdkTagPositions; +                ResXMLParser::ResXMLPosition curPos; +                while ((code = tree.next()) != ResXMLTree::END_DOCUMENT && +                       code != ResXMLTree::BAD_DOCUMENT) { +                    if (code == ResXMLTree::END_TAG) { +                        curDepth--; +                        continue; +                    } +                    if (code == ResXMLTree::START_TAG) { +                        curDepth++; +                    } +                    const char16_t* ctag16 = tree.getElementName(&len); +                    if (ctag16 == NULL || String8(ctag16) != "uses-sdk" || curDepth != 2) { +                        continue; +                    } + +                    tree.getPosition(&curPos); +                    usesSdkTagPositions.emplace_back(curPos); +                } + +                // Skip all "uses-sdk" tags besides the very last tag. The android runtime only uses +                // the attribute values from the last defined tag. +                for (size_t i = 0; i < usesSdkTagPositions.size() - 1; i++) { +                    tagsToSkip.emplace_back(usesSdkTagPositions[i]); +                } + +                // Reset the position before parsing. +                tree.setPosition(initialPos); +            } +              while ((code=tree.next()) != ResXMLTree::END_DOCUMENT &&                      code != ResXMLTree::BAD_DOCUMENT) {                  if (code == ResXMLTree::END_TAG) { @@ -1202,8 +1240,25 @@ int doDump(Bundle* bundle)                  if (code != ResXMLTree::START_TAG) {                      continue;                  } +                  depth++; +                // If this tag should be skipped, skip to the end of this tag. +                ResXMLParser::ResXMLPosition curPos; +                tree.getPosition(&curPos); +                if (std::find(tagsToSkip.begin(), tagsToSkip.end(), curPos) != tagsToSkip.end()) { +                    const int breakDepth = depth - 1; +                    while ((code = tree.next()) != ResXMLTree::END_DOCUMENT && +                           code != ResXMLTree::BAD_DOCUMENT) { +                        if (code == ResXMLTree::END_TAG && --depth == breakDepth) { +                            break; +                        } else if (code == ResXMLTree::START_TAG) { +                            depth++; +                        } +                    } +                    continue; +                } +                  const char16_t* ctag16 = tree.getElementName(&len);                  if (ctag16 == NULL) {                      SourcePos(manifestFile, tree.getLineNumber()).error( diff --git a/tools/aapt2/ResourceValues.h b/tools/aapt2/ResourceValues.h index d11b013f14d5..d903b7e1b8b3 100644 --- a/tools/aapt2/ResourceValues.h +++ b/tools/aapt2/ResourceValues.h @@ -154,18 +154,18 @@ struct BaseItem : public Item {  // A reference can be symbolic (with the name set to a valid resource name) or be  // numeric (the id is set to a valid resource ID).  struct Reference : public TransformableItem<Reference, BaseItem<Reference>> { -  enum class Type { +  enum class Type : uint8_t {      kResource,      kAttribute,    };    Maybe<ResourceName> name;    Maybe<ResourceId> id; +  std::optional<uint32_t> type_flags;    Reference::Type reference_type;    bool private_reference = false;    bool is_dynamic = false; -  std::optional<uint32_t> type_flags; -  bool allow_raw; +  bool allow_raw = false;    Reference();    explicit Reference(const ResourceNameRef& n, Type type = Type::kResource); diff --git a/tools/aapt2/dump/DumpManifest.cpp b/tools/aapt2/dump/DumpManifest.cpp index f29c9185cafa..61ba09b6a3c9 100644 --- a/tools/aapt2/dump/DumpManifest.cpp +++ b/tools/aapt2/dump/DumpManifest.cpp @@ -132,6 +132,12 @@ class ManifestExtractor {      /** Adds an element to the list of children of the element. */      void AddChild(std::unique_ptr<Element>& child) { children_.push_back(std::move(child)); } +    template <typename Predicate> +    void Filter(Predicate&& func) { +      children_.erase(std::remove_if(children_.begin(), children_.end(), +                                     [&](const auto& e) { return func(e.get()); })); +    } +      /** Retrieves the list of children of the element. */      const std::vector<std::unique_ptr<Element>>& children() const {        return children_; @@ -1963,6 +1969,21 @@ bool ManifestExtractor::Dump(text::Printer* printer, IDiagnostics* diag) {    // Extract badging information    auto root = Visit(element); +  // Filter out all "uses-sdk" tags besides the very last tag. The android runtime only uses the +  // attribute values from the last defined tag. +  std::vector<UsesSdkBadging*> filtered_uses_sdk_tags; +  for (const auto& child : root->children()) { +    if (auto uses_sdk = ElementCast<UsesSdkBadging>(child.get())) { +      filtered_uses_sdk_tags.emplace_back(uses_sdk); +    } +  } +  filtered_uses_sdk_tags.pop_back(); + +  root->Filter([&](const ManifestExtractor::Element* e) { +    return std::find(filtered_uses_sdk_tags.begin(), filtered_uses_sdk_tags.end(), e) != +           filtered_uses_sdk_tags.end(); +  }); +    // Print the elements in order seen    Print(root.get(), printer);  |