Merge "Rename T to Tiramisu"
diff --git a/apct-tests/perftests/core/src/android/util/ArraySetPerfTest.java b/apct-tests/perftests/core/src/android/util/ArraySetPerfTest.java
index b24bf42..c299e99 100644
--- a/apct-tests/perftests/core/src/android/util/ArraySetPerfTest.java
+++ b/apct-tests/perftests/core/src/android/util/ArraySetPerfTest.java
@@ -26,6 +26,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.function.Consumer;
import java.util.function.Predicate;
@RunWith(AndroidJUnit4.class)
@@ -39,6 +40,38 @@
public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@Test
+ public void testForEach_Small() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ Consumer<Integer> consumer = (i) -> {
+ };
+ while (state.keepRunning()) {
+ for (int i = 0; i < NUM_ITERATIONS; ++i) {
+ ArraySet<Integer> set = new ArraySet<>();
+ for (int j = 0; j < SET_SIZE_SMALL; j++) {
+ set.add(j);
+ }
+ set.forEach(consumer);
+ }
+ }
+ }
+
+ @Test
+ public void testForEach_Large() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ Consumer<Integer> consumer = (i) -> {
+ };
+ while (state.keepRunning()) {
+ for (int i = 0; i < NUM_ITERATIONS; ++i) {
+ ArraySet<Integer> set = new ArraySet<>();
+ for (int j = 0; j < SET_SIZE_LARGE; j++) {
+ set.add(j);
+ }
+ set.forEach(consumer);
+ }
+ }
+ }
+
+ @Test
public void testValueAt_InBounds() {
BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
ArraySet<Integer> set = new ArraySet<>();
diff --git a/apex/appsearch/framework/Android.bp b/apex/appsearch/framework/Android.bp
index cd9be9b..8964668 100644
--- a/apex/appsearch/framework/Android.bp
+++ b/apex/appsearch/framework/Android.bp
@@ -57,12 +57,8 @@
// This list must be kept in sync with jarjar.txt
"modules-utils-preconditions",
],
- libs: ["unsupportedappusage"], // TODO(b/181887768) should be removed
defaults: ["framework-module-defaults"],
permitted_packages: ["android.app.appsearch"],
- aidl: {
- include_dirs: ["frameworks/base/core/java"], // TODO(b/146218515) should be removed
- },
jarjar_rules: "jarjar-rules.txt",
apex_available: ["com.android.appsearch"],
impl_library_visibility: [
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
index b5e3662..82b6d62 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
@@ -25,7 +25,6 @@
import android.app.appsearch.aidl.IAppSearchResultCallback;
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;
@@ -309,19 +308,6 @@
}
/**
- * @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.
*
@@ -521,19 +507,6 @@
}
/**
- * @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 0ee5e65..2e04d71 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java
@@ -22,7 +22,6 @@
import android.app.appsearch.exceptions.IllegalSchemaException;
import android.app.appsearch.util.BundleUtil;
import android.app.appsearch.util.IndentingStringBuilder;
-import android.compat.annotation.UnsupportedAppUsage;
import android.os.Bundle;
import android.util.ArraySet;
@@ -643,60 +642,8 @@
}
}
- /**
- * @deprecated TODO(b/181887768): Exists for dogfood transition; must be removed.
- * @hide
- */
- @Deprecated
- public static class Int64PropertyConfig extends PropertyConfig {
- @UnsupportedAppUsage
- Int64PropertyConfig(@NonNull Bundle bundle) {
- super(bundle);
- }
-
- /** Builder for {@link Int64PropertyConfig}. */
- public static final class Builder {
- private final String mPropertyName;
- private @Cardinality int mCardinality = CARDINALITY_OPTIONAL;
-
- /** Creates a new {@link Int64PropertyConfig.Builder}. */
- @UnsupportedAppUsage
- public Builder(@NonNull String propertyName) {
- mPropertyName = Objects.requireNonNull(propertyName);
- }
-
- /**
- * The cardinality of the property (whether it is optional, required or repeated).
- *
- * <p>If this method is not called, the default cardinality is {@link
- * PropertyConfig#CARDINALITY_OPTIONAL}.
- */
- @SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass
- @NonNull
- @UnsupportedAppUsage
- public Int64PropertyConfig.Builder setCardinality(@Cardinality int cardinality) {
- Preconditions.checkArgumentInRange(
- cardinality, CARDINALITY_REPEATED, CARDINALITY_REQUIRED, "cardinality");
- mCardinality = cardinality;
- return this;
- }
-
- /** Constructs a new {@link Int64PropertyConfig} from the contents of this builder. */
- @NonNull
- @UnsupportedAppUsage
- public Int64PropertyConfig build() {
- Bundle bundle = new Bundle();
- bundle.putString(NAME_FIELD, mPropertyName);
- bundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_LONG);
- bundle.putInt(CARDINALITY_FIELD, mCardinality);
- return new Int64PropertyConfig(bundle);
- }
- }
- }
-
/** Configuration for a property containing a 64-bit integer. */
- // TODO(b/181887768): This should extend directly from PropertyConfig
- public static final class LongPropertyConfig extends Int64PropertyConfig {
+ public static final class LongPropertyConfig extends PropertyConfig {
LongPropertyConfig(@NonNull Bundle bundle) {
super(bundle);
}
@@ -896,8 +843,7 @@
/** Builder for {@link DocumentPropertyConfig}. */
public static final class Builder {
private final String mPropertyName;
- // TODO(b/181887768): This should be final
- private String mSchemaType;
+ private final String mSchemaType;
private @Cardinality int mCardinality = CARDINALITY_OPTIONAL;
private boolean mShouldIndexNestedProperties = false;
@@ -916,29 +862,6 @@
}
/**
- * @deprecated TODO(b/181887768): Exists for dogfood transition; must be removed.
- * @hide
- */
- @Deprecated
- @UnsupportedAppUsage
- public Builder(@NonNull String propertyName) {
- mPropertyName = Objects.requireNonNull(propertyName);
- mSchemaType = null;
- }
-
- /**
- * @deprecated TODO(b/181887768): Exists for dogfood transition; must be removed.
- * @hide
- */
- @Deprecated
- @UnsupportedAppUsage
- @NonNull
- public Builder setSchemaType(@NonNull String schemaType) {
- mSchemaType = Objects.requireNonNull(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
@@ -967,18 +890,6 @@
return this;
}
- /**
- * @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. */
@NonNull
public DocumentPropertyConfig build() {
@@ -987,9 +898,7 @@
bundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_DOCUMENT);
bundle.putInt(CARDINALITY_FIELD, mCardinality);
bundle.putBoolean(INDEX_NESTED_PROPERTIES_FIELD, mShouldIndexNestedProperties);
- // TODO(b/181887768): Remove checkNotNull after the deprecated constructor (which
- // is the only way to get null here) is removed
- bundle.putString(SCHEMA_TYPE_FIELD, Objects.requireNonNull(mSchemaType));
+ bundle.putString(SCHEMA_TYPE_FIELD, mSchemaType);
return new DocumentPropertyConfig(bundle);
}
}
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 c905f95..4d27519 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java
@@ -23,7 +23,6 @@
import android.annotation.SuppressLint;
import android.app.appsearch.util.BundleUtil;
import android.app.appsearch.util.IndentingStringBuilder;
-import android.compat.annotation.UnsupportedAppUsage;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.Log;
@@ -51,9 +50,6 @@
public class GenericDocument {
private static final String TAG = "AppSearchGenericDocumen";
- /** The maximum {@link String#length} of a {@link String} field. */
- private static final int MAX_STRING_LENGTH = 20_000;
-
/** The maximum number of indexed properties a document can have. */
private static final int MAX_INDEXED_PROPERTIES = 16;
@@ -134,17 +130,6 @@
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() {
@@ -1286,15 +1271,6 @@
for (int i = 0; i < values.length; i++) {
if (values[i] == null) {
throw new IllegalArgumentException("The String at " + i + " is null.");
- } else if (values[i].length() > MAX_STRING_LENGTH) {
- throw new IllegalArgumentException(
- "The String at "
- + i
- + " length is: "
- + values[i].length()
- + ", which exceeds length limit: "
- + MAX_STRING_LENGTH
- + ".");
}
}
mProperties.putStringArray(name, values);
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/GetByUriRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/GetByUriRequest.java
deleted file mode 100644
index 7b05eac..0000000
--- a/apex/appsearch/framework/java/external/android/app/appsearch/GetByUriRequest.java
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * 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
deleted file mode 100644
index 9c74966..0000000
--- a/apex/appsearch/framework/java/external/android/app/appsearch/RemoveByUriRequest.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * 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 c388bde..e807803 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/ReportUsageRequest.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/ReportUsageRequest.java
@@ -18,7 +18,6 @@
import android.annotation.CurrentTimeMillisLong;
import android.annotation.NonNull;
-import android.compat.annotation.UnsupportedAppUsage;
import java.util.Objects;
@@ -67,8 +66,7 @@
/** Builder for {@link ReportUsageRequest} objects. */
public static final class Builder {
private final String mNamespace;
- // TODO(b/181887768): Make this final
- private String mDocumentId;
+ private final String mDocumentId;
private Long mUsageTimestampMillis;
/**
@@ -85,40 +83,6 @@
}
/**
- * @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 4beb667..f6a597c 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/SearchResult.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/SearchResult.java
@@ -18,7 +18,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.compat.annotation.UnsupportedAppUsage;
import android.os.Bundle;
import com.android.internal.util.Preconditions;
@@ -84,17 +83,6 @@
}
/**
- * @deprecated TODO(b/181887768): Exists for dogfood transition; must be removed.
- * @hide
- */
- @Deprecated
- @UnsupportedAppUsage
- @NonNull
- public List<MatchInfo> getMatches() {
- return getMatchInfos();
- }
-
- /**
* Returns a list of {@link MatchInfo}s providing information about how the document in {@link
* #getGenericDocument} matched the query.
*
@@ -196,17 +184,6 @@
return this;
}
- /**
- * @deprecated TODO(b/181887768): Exists for dogfood transition; must be removed.
- * @hide
- */
- @Deprecated
- @UnsupportedAppUsage
- @NonNull
- public Builder addMatch(@NonNull MatchInfo matchInfo) {
- return addMatchInfo(matchInfo);
- }
-
/** Adds another match to this SearchResult. */
@NonNull
public Builder addMatchInfo(@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 3e5a2ca..a3a4a23 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java
@@ -18,7 +18,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.compat.annotation.UnsupportedAppUsage;
import android.os.Bundle;
import android.util.ArraySet;
@@ -342,17 +341,6 @@
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/appsearch/service/Android.bp b/apex/appsearch/service/Android.bp
index b101895..b6521ff 100644
--- a/apex/appsearch/service/Android.bp
+++ b/apex/appsearch/service/Android.bp
@@ -52,7 +52,6 @@
libs: [
"framework-appsearch.impl",
"framework-statsd.stubs.module_lib",
- "unsupportedappusage", // TODO(b/181887768) should be removed
],
defaults: ["framework-system-server-module-defaults"],
permitted_packages: [
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchConfig.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchConfig.java
index c44fd40..29048b2 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchConfig.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchConfig.java
@@ -81,6 +81,14 @@
"sampling_interval_for_batch_call_stats";
public static final String KEY_SAMPLING_INTERVAL_FOR_PUT_DOCUMENT_STATS =
"sampling_interval_for_put_document_stats";
+ public static final String KEY_SAMPLING_INTERVAL_FOR_INITIALIZE_STATS =
+ "sampling_interval_for_initialize_stats";
+ public static final String KEY_SAMPLING_INTERVAL_FOR_SEARCH_STATS =
+ "sampling_interval_for_search_stats";
+ public static final String KEY_SAMPLING_INTERVAL_FOR_GLOBAL_SEARCH_STATS =
+ "sampling_interval_for_global_search_stats";
+ public static final String KEY_SAMPLING_INTERVAL_FOR_OPTIMIZE_STATS =
+ "sampling_interval_for_optimize_stats";
public static final String KEY_LIMIT_CONFIG_MAX_DOCUMENT_SIZE_BYTES =
"limit_config_max_document_size_bytes";
public static final String KEY_LIMIT_CONFIG_MAX_DOCUMENT_COUNT =
@@ -95,6 +103,10 @@
KEY_SAMPLING_INTERVAL_DEFAULT,
KEY_SAMPLING_INTERVAL_FOR_BATCH_CALL_STATS,
KEY_SAMPLING_INTERVAL_FOR_PUT_DOCUMENT_STATS,
+ KEY_SAMPLING_INTERVAL_FOR_INITIALIZE_STATS,
+ KEY_SAMPLING_INTERVAL_FOR_SEARCH_STATS,
+ KEY_SAMPLING_INTERVAL_FOR_GLOBAL_SEARCH_STATS,
+ KEY_SAMPLING_INTERVAL_FOR_OPTIMIZE_STATS,
KEY_LIMIT_CONFIG_MAX_DOCUMENT_SIZE_BYTES,
KEY_LIMIT_CONFIG_MAX_DOCUMENT_COUNT,
KEY_BYTES_OPTIMIZE_THRESHOLD,
@@ -245,6 +257,58 @@
}
}
+ /**
+ * Returns cached value for sampling interval for initialize.
+ *
+ * <p>For example, sampling_interval=10 means that one out of every 10 stats was logged.
+ */
+ public int getCachedSamplingIntervalForInitializeStats() {
+ synchronized (mLock) {
+ throwIfClosedLocked();
+ return mBundleLocked.getInt(KEY_SAMPLING_INTERVAL_FOR_INITIALIZE_STATS,
+ getCachedSamplingIntervalDefault());
+ }
+ }
+
+ /**
+ * Returns cached value for sampling interval for search.
+ *
+ * <p>For example, sampling_interval=10 means that one out of every 10 stats was logged.
+ */
+ public int getCachedSamplingIntervalForSearchStats() {
+ synchronized (mLock) {
+ throwIfClosedLocked();
+ return mBundleLocked.getInt(KEY_SAMPLING_INTERVAL_FOR_SEARCH_STATS,
+ getCachedSamplingIntervalDefault());
+ }
+ }
+
+ /**
+ * Returns cached value for sampling interval for globalSearch.
+ *
+ * <p>For example, sampling_interval=10 means that one out of every 10 stats was logged.
+ */
+ public int getCachedSamplingIntervalForGlobalSearchStats() {
+ synchronized (mLock) {
+ throwIfClosedLocked();
+ return mBundleLocked.getInt(KEY_SAMPLING_INTERVAL_FOR_GLOBAL_SEARCH_STATS,
+ getCachedSamplingIntervalDefault());
+ }
+ }
+
+ /**
+ * Returns cached value for sampling interval for optimize.
+ *
+ * <p>For example, sampling_interval=10 means that one out of every 10 stats was logged.
+ */
+ public int getCachedSamplingIntervalForOptimizeStats() {
+ synchronized (mLock) {
+ throwIfClosedLocked();
+ return mBundleLocked.getInt(KEY_SAMPLING_INTERVAL_FOR_OPTIMIZE_STATS,
+ getCachedSamplingIntervalDefault());
+ }
+ }
+
/** Returns the maximum serialized size an indexed document can be, in bytes. */
public int getCachedLimitConfigMaxDocumentSizeBytes() {
synchronized (mLock) {
@@ -343,6 +407,10 @@
case KEY_SAMPLING_INTERVAL_DEFAULT:
case KEY_SAMPLING_INTERVAL_FOR_BATCH_CALL_STATS:
case KEY_SAMPLING_INTERVAL_FOR_PUT_DOCUMENT_STATS:
+ case KEY_SAMPLING_INTERVAL_FOR_INITIALIZE_STATS:
+ case KEY_SAMPLING_INTERVAL_FOR_SEARCH_STATS:
+ case KEY_SAMPLING_INTERVAL_FOR_GLOBAL_SEARCH_STATS:
+ case KEY_SAMPLING_INTERVAL_FOR_OPTIMIZE_STATS:
synchronized (mLock) {
mBundleLocked.putInt(key, properties.getInt(key, DEFAULT_SAMPLING_INTERVAL));
}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
index 666d497..db23a6d 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
@@ -18,7 +18,6 @@
import static android.app.appsearch.AppSearchResult.throwableToFailedResult;
import static android.os.Process.INVALID_UID;
-import android.Manifest;
import android.annotation.ElapsedRealtimeLong;
import android.annotation.NonNull;
import android.app.appsearch.AppSearchBatchResult;
@@ -60,6 +59,7 @@
import com.android.server.LocalManagerRegistry;
import com.android.server.SystemService;
import com.android.server.appsearch.external.localstorage.stats.CallStats;
+import com.android.server.appsearch.external.localstorage.stats.OptimizeStats;
import com.android.server.appsearch.external.localstorage.visibilitystore.VisibilityStore;
import com.android.server.appsearch.stats.StatsCollector;
import com.android.server.appsearch.util.PackageUtil;
@@ -1354,43 +1354,26 @@
/**
* Helper for dealing with incoming user arguments to system service calls.
*
- * <p>Takes care of checking permissions and converting USER_CURRENT to the actual current user.
- *
* @param requestedUser The user which the caller is requesting to execute as.
* @param callingUid The actual uid of the caller as determined by Binder.
* @return the user handle that the call should run as. Will always be a concrete user.
*/
@NonNull
private UserHandle handleIncomingUser(@NonNull UserHandle requestedUser, int callingUid) {
- int callingPid = Binder.getCallingPid();
UserHandle callingUser = UserHandle.getUserHandleForUid(callingUid);
if (callingUser.equals(requestedUser)) {
return requestedUser;
}
+
// Duplicates UserController#ensureNotSpecialUser
if (requestedUser.getIdentifier() < 0) {
throw new IllegalArgumentException(
"Call does not support special user " + requestedUser);
}
- boolean canInteractAcrossUsers = mContext.checkPermission(
- Manifest.permission.INTERACT_ACROSS_USERS,
- callingPid,
- callingUid) == PackageManager.PERMISSION_GRANTED;
- if (!canInteractAcrossUsers) {
- canInteractAcrossUsers = mContext.checkPermission(
- Manifest.permission.INTERACT_ACROSS_USERS_FULL,
- callingPid,
- callingUid) == PackageManager.PERMISSION_GRANTED;
- }
- if (canInteractAcrossUsers) {
- return requestedUser;
- }
+
throw new SecurityException(
- "Permission denied while calling from uid " + callingUid
- + " with " + requestedUser + "; Need to run as either the calling user ("
- + callingUser + "), or with one of the following permissions: "
- + Manifest.permission.INTERACT_ACROSS_USERS + " or "
- + Manifest.permission.INTERACT_ACROSS_USERS_FULL);
+ "Requested user, " + requestedUser + ", is not the same as the calling user, "
+ + callingUser + ".");
}
/**
@@ -1497,20 +1480,42 @@
private void checkForOptimize(AppSearchUserInstance instance, int mutateBatchSize) {
EXECUTOR.execute(() -> {
+ long totalLatencyStartMillis = SystemClock.elapsedRealtime();
+ OptimizeStats.Builder builder = new OptimizeStats.Builder();
try {
- instance.getAppSearchImpl().checkForOptimize(mutateBatchSize);
+ instance.getAppSearchImpl().checkForOptimize(mutateBatchSize, builder);
} catch (AppSearchException e) {
Log.w(TAG, "Error occurred when check for optimize", e);
+ } finally {
+ OptimizeStats oStats = builder
+ .setTotalLatencyMillis(
+ (int) (SystemClock.elapsedRealtime() - totalLatencyStartMillis))
+ .build();
+ if (oStats.getOriginalDocumentCount() > 0) {
+ // see if optimize has been run by checking originalDocumentCount
+ instance.getLogger().logStats(oStats);
+ }
}
});
}
private void checkForOptimize(AppSearchUserInstance instance) {
EXECUTOR.execute(() -> {
+ long totalLatencyStartMillis = SystemClock.elapsedRealtime();
+ OptimizeStats.Builder builder = new OptimizeStats.Builder();
try {
- instance.getAppSearchImpl().checkForOptimize();
+ instance.getAppSearchImpl().checkForOptimize(builder);
} catch (AppSearchException e) {
Log.w(TAG, "Error occurred when check for optimize", e);
+ } finally {
+ OptimizeStats oStats = builder
+ .setTotalLatencyMillis(
+ (int) (SystemClock.elapsedRealtime() - totalLatencyStartMillis))
+ .build();
+ if (oStats.getOriginalDocumentCount() > 0) {
+ // see if optimize has been run by checking originalDocumentCount
+ instance.getLogger().logStats(oStats);
+ }
}
});
}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
index 830e76c..15916cc 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
@@ -55,6 +55,7 @@
import com.android.server.appsearch.external.localstorage.converter.SetSchemaResponseToProtoConverter;
import com.android.server.appsearch.external.localstorage.converter.TypePropertyPathToProtoConverter;
import com.android.server.appsearch.external.localstorage.stats.InitializeStats;
+import com.android.server.appsearch.external.localstorage.stats.OptimizeStats;
import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats;
import com.android.server.appsearch.external.localstorage.stats.RemoveStats;
import com.android.server.appsearch.external.localstorage.stats.SearchStats;
@@ -145,6 +146,9 @@
public final class AppSearchImpl implements Closeable {
private static final String TAG = "AppSearchImpl";
+ /** A value 0 means that there're no more pages in the search results. */
+ private static final long EMPTY_PAGE_TOKEN = 0;
+
@VisibleForTesting static final int CHECK_OPTIMIZE_INTERVAL = 100;
private final ReadWriteLock mReadWriteLock = new ReentrantReadWriteLock();
@@ -284,6 +288,9 @@
// Log the time it took to read the data that goes into the cache maps
if (initStatsBuilder != null) {
+ // In case there is some error for getAllNamespaces, we can still
+ // set the latency for preparation.
+ // If there is no error, the value will be overridden by the actual one later.
initStatsBuilder
.setStatusCode(
statusProtoToResultCode(
@@ -1135,6 +1142,16 @@
searchResultProto.getResultsCount(),
searchResultProto);
checkSuccess(searchResultProto.getStatus());
+ if (nextPageToken != EMPTY_PAGE_TOKEN
+ && searchResultProto.getNextPageToken() == EMPTY_PAGE_TOKEN) {
+ // At this point, we're guaranteed that this nextPageToken exists for this package,
+ // otherwise checkNextPageToken would've thrown an exception.
+ // Since the new token is 0, this is the last page. We should remove the old token
+ // from our cache since it no longer refers to this query.
+ synchronized (mNextPageTokensLocked) {
+ mNextPageTokensLocked.get(packageName).remove(nextPageToken);
+ }
+ }
return rewriteSearchResultProto(searchResultProto, mSchemaMapLocked);
} finally {
mReadWriteLock.readLock().unlock();
@@ -1326,8 +1343,7 @@
deleteResultProto.getStatus(), StatusProto.Code.OK, StatusProto.Code.NOT_FOUND);
// Update derived maps
- int numDocumentsDeleted =
- deleteResultProto.getDeleteStats().getNumDocumentsDeleted();
+ int numDocumentsDeleted = deleteResultProto.getDeleteStats().getNumDocumentsDeleted();
updateDocumentCountAfterRemovalLocked(packageName, numDocumentsDeleted);
} finally {
mReadWriteLock.writeLock().unlock();
@@ -2056,6 +2072,10 @@
}
private void addNextPageToken(String packageName, long nextPageToken) {
+ if (nextPageToken == EMPTY_PAGE_TOKEN) {
+ // There is no more pages. No need to add it.
+ return;
+ }
synchronized (mNextPageTokensLocked) {
Set<Long> tokens = mNextPageTokensLocked.get(packageName);
if (tokens == null) {
@@ -2068,6 +2088,11 @@
private void checkNextPageToken(String packageName, long nextPageToken)
throws AppSearchException {
+ if (nextPageToken == EMPTY_PAGE_TOKEN) {
+ // Swallow the check for empty page token, token = 0 means there is no more page and it
+ // won't return anything from Icing.
+ return;
+ }
synchronized (mNextPageTokensLocked) {
Set<Long> nextPageTokens = mNextPageTokensLocked.get(packageName);
if (nextPageTokens == null || !nextPageTokens.contains(nextPageToken)) {
@@ -2162,12 +2187,13 @@
* #CHECK_OPTIMIZE_INTERVAL}, {@link IcingSearchEngine#getOptimizeInfo()} will be triggered
* and the counter will be reset.
*/
- public void checkForOptimize(int mutationSize) throws AppSearchException {
+ public void checkForOptimize(int mutationSize, @Nullable OptimizeStats.Builder builder)
+ throws AppSearchException {
mReadWriteLock.writeLock().lock();
try {
mOptimizeIntervalCountLocked += mutationSize;
if (mOptimizeIntervalCountLocked >= CHECK_OPTIMIZE_INTERVAL) {
- checkForOptimize();
+ checkForOptimize(builder);
}
} finally {
mReadWriteLock.writeLock().unlock();
@@ -2183,14 +2209,15 @@
* <p>{@link IcingSearchEngine#optimize()} should be called only if {@link
* OptimizeStrategy#shouldOptimize(GetOptimizeInfoResultProto)} return true.
*/
- public void checkForOptimize() throws AppSearchException {
+ public void checkForOptimize(@Nullable OptimizeStats.Builder builder)
+ throws AppSearchException {
mReadWriteLock.writeLock().lock();
try {
GetOptimizeInfoResultProto optimizeInfo = getOptimizeInfoResultLocked();
checkSuccess(optimizeInfo.getStatus());
mOptimizeIntervalCountLocked = 0;
if (mOptimizeStrategy.shouldOptimize(optimizeInfo)) {
- optimize();
+ optimize(builder);
}
} finally {
mReadWriteLock.writeLock().unlock();
@@ -2201,13 +2228,18 @@
}
/** Triggers {@link IcingSearchEngine#optimize()} directly. */
- public void optimize() throws AppSearchException {
+ public void optimize(@Nullable OptimizeStats.Builder builder) throws AppSearchException {
mReadWriteLock.writeLock().lock();
try {
mLogUtil.piiTrace("optimize, request");
OptimizeResultProto optimizeResultProto = mIcingSearchEngineLocked.optimize();
mLogUtil.piiTrace(
"optimize, response", optimizeResultProto.getStatus(), optimizeResultProto);
+ if (builder != null) {
+ builder.setStatusCode(statusProtoToResultCode(optimizeResultProto.getStatus()));
+ AppSearchLoggerHelper.copyNativeStats(
+ optimizeResultProto.getOptimizeStats(), builder);
+ }
checkSuccess(optimizeResultProto.getStatus());
} finally {
mReadWriteLock.writeLock().unlock();
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLogger.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLogger.java
index d92f4f0..98cedc7 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLogger.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLogger.java
@@ -17,10 +17,10 @@
package com.android.server.appsearch.external.localstorage;
import android.annotation.NonNull;
-import android.app.appsearch.exceptions.AppSearchException;
import com.android.server.appsearch.external.localstorage.stats.CallStats;
import com.android.server.appsearch.external.localstorage.stats.InitializeStats;
+import com.android.server.appsearch.external.localstorage.stats.OptimizeStats;
import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats;
import com.android.server.appsearch.external.localstorage.stats.RemoveStats;
import com.android.server.appsearch.external.localstorage.stats.SearchStats;
@@ -37,19 +37,22 @@
*/
public interface AppSearchLogger {
/** Logs {@link CallStats} */
- void logStats(@NonNull CallStats stats) throws AppSearchException;
+ void logStats(@NonNull CallStats stats);
/** Logs {@link PutDocumentStats} */
- void logStats(@NonNull PutDocumentStats stats) throws AppSearchException;
+ void logStats(@NonNull PutDocumentStats stats);
/** Logs {@link InitializeStats} */
- void logStats(@NonNull InitializeStats stats) throws AppSearchException;
+ void logStats(@NonNull InitializeStats stats);
/** Logs {@link SearchStats} */
- void logStats(@NonNull SearchStats stats) throws AppSearchException;
+ void logStats(@NonNull SearchStats stats);
/** Logs {@link RemoveStats} */
- void logStats(@NonNull RemoveStats stats) throws AppSearchException;
+ void logStats(@NonNull RemoveStats stats);
+
+ /** Logs {@link OptimizeStats} */
+ void logStats(@NonNull OptimizeStats stats);
// TODO(b/173532925) Add remaining logStats once we add all the stats.
}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java
index aa9200a..cd653e5 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java
@@ -19,12 +19,14 @@
import android.annotation.NonNull;
import com.android.server.appsearch.external.localstorage.stats.InitializeStats;
+import com.android.server.appsearch.external.localstorage.stats.OptimizeStats;
import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats;
import com.android.server.appsearch.external.localstorage.stats.RemoveStats;
import com.android.server.appsearch.external.localstorage.stats.SearchStats;
import com.google.android.icing.proto.DeleteStatsProto;
import com.google.android.icing.proto.InitializeStatsProto;
+import com.google.android.icing.proto.OptimizeStatsProto;
import com.google.android.icing.proto.PutDocumentStatsProto;
import com.google.android.icing.proto.QueryStatsProto;
@@ -92,8 +94,8 @@
.setSchemaTypeCount(fromNativeStats.getNumSchemaTypes());
}
- /*
- * Copy native Query stats to buiilder.
+ /**
+ * Copies native Query stats to builder.
*
* @param fromNativeStats Stats copied from.
* @param toStatsBuilder Stats copied to.
@@ -122,8 +124,8 @@
fromNativeStats.getDocumentRetrievalLatencyMs());
}
- /*
- * Copy native Query stats to buiilder.
+ /**
+ * Copies native Delete stats to builder.
*
* @param fromNativeStats Stats copied from.
* @param toStatsBuilder Stats copied to.
@@ -138,4 +140,28 @@
.setDeleteType(fromNativeStats.getDeleteType().getNumber())
.setDeletedDocumentCount(fromNativeStats.getNumDocumentsDeleted());
}
+
+ /**
+ * Copies native {@link OptimizeStatsProto} to builder.
+ *
+ * @param fromNativeStats Stats copied from.
+ * @param toStatsBuilder Stats copied to.
+ */
+ static void copyNativeStats(
+ @NonNull OptimizeStatsProto fromNativeStats,
+ @NonNull OptimizeStats.Builder toStatsBuilder) {
+ Objects.requireNonNull(fromNativeStats);
+ Objects.requireNonNull(toStatsBuilder);
+ toStatsBuilder
+ .setNativeLatencyMillis(fromNativeStats.getLatencyMs())
+ .setDocumentStoreOptimizeLatencyMillis(
+ fromNativeStats.getDocumentStoreOptimizeLatencyMs())
+ .setIndexRestorationLatencyMillis(fromNativeStats.getIndexRestorationLatencyMs())
+ .setOriginalDocumentCount(fromNativeStats.getNumOriginalDocuments())
+ .setDeletedDocumentCount(fromNativeStats.getNumDeletedDocuments())
+ .setExpiredDocumentCount(fromNativeStats.getNumExpiredDocuments())
+ .setStorageSizeBeforeBytes(fromNativeStats.getStorageSizeBefore())
+ .setStorageSizeAfterBytes(fromNativeStats.getStorageSizeAfter())
+ .setTimeSinceLastOptimizeMillis(fromNativeStats.getTimeSinceLastOptimizeMs());
+ }
}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/OptimizeStats.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/OptimizeStats.java
new file mode 100644
index 0000000..83bd50f
--- /dev/null
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/OptimizeStats.java
@@ -0,0 +1,243 @@
+/*
+ * 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 com.android.server.appsearch.external.localstorage.stats;
+
+import android.annotation.NonNull;
+import android.app.appsearch.AppSearchResult;
+
+import java.util.Objects;
+
+/**
+ * Class holds detailed stats for Optimize.
+ *
+ * @hide
+ */
+public final class OptimizeStats {
+ /**
+ * The status code returned by {@link AppSearchResult#getResultCode()} for the call or internal
+ * state.
+ */
+ @AppSearchResult.ResultCode private final int mStatusCode;
+
+ private final int mTotalLatencyMillis;
+ private final int mNativeLatencyMillis;
+
+ // Time used to optimize the document store in millis.
+ private final int mNativeDocumentStoreOptimizeLatencyMillis;
+
+ // Time used to restore the index in millis.
+ private final int mNativeIndexRestorationLatencyMillis;
+
+ // Number of documents before the optimization.
+ private final int mNativeOriginalDocumentCount;
+
+ // Number of documents deleted during the optimization.
+ private final int mNativeDeletedDocumentCount;
+
+ // Number of documents expired during the optimization.
+ private final int mNativeExpiredDocumentCount;
+
+ // Size of storage in bytes before the optimization.
+ private final long mNativeStorageSizeBeforeBytes;
+
+ // Size of storage in bytes after the optimization.
+ private final long mNativeStorageSizeAfterBytes;
+
+ // The amount of time in millis since the last optimization ran calculated using wall clock time
+ private final long mNativeTimeSinceLastOptimizeMillis;
+
+ OptimizeStats(@NonNull Builder builder) {
+ Objects.requireNonNull(builder);
+ mStatusCode = builder.mStatusCode;
+ mTotalLatencyMillis = builder.mTotalLatencyMillis;
+ mNativeLatencyMillis = builder.mNativeLatencyMillis;
+ mNativeDocumentStoreOptimizeLatencyMillis =
+ builder.mNativeDocumentStoreOptimizeLatencyMillis;
+ mNativeIndexRestorationLatencyMillis = builder.mNativeIndexRestorationLatencyMillis;
+ mNativeOriginalDocumentCount = builder.mNativeOriginalDocumentCount;
+ mNativeDeletedDocumentCount = builder.mNativeDeletedDocumentCount;
+ mNativeExpiredDocumentCount = builder.mNativeExpiredDocumentCount;
+ mNativeStorageSizeBeforeBytes = builder.mNativeStorageSizeBeforeBytes;
+ mNativeStorageSizeAfterBytes = builder.mNativeStorageSizeAfterBytes;
+ mNativeTimeSinceLastOptimizeMillis = builder.mNativeTimeSinceLastOptimizeMillis;
+ }
+
+ /** Returns status code for this optimization. */
+ @AppSearchResult.ResultCode
+ public int getStatusCode() {
+ return mStatusCode;
+ }
+
+ /** Returns total latency of this optimization in millis. */
+ public int getTotalLatencyMillis() {
+ return mTotalLatencyMillis;
+ }
+
+ /** Returns how much time in millis spent in the native code. */
+ public int getNativeLatencyMillis() {
+ return mNativeLatencyMillis;
+ }
+
+ /** Returns time used to optimize the document store in millis. */
+ public int getDocumentStoreOptimizeLatencyMillis() {
+ return mNativeDocumentStoreOptimizeLatencyMillis;
+ }
+
+ /** Returns time used to restore the index in millis. */
+ public int getIndexRestorationLatencyMillis() {
+ return mNativeIndexRestorationLatencyMillis;
+ }
+
+ /** Returns number of documents before the optimization. */
+ public int getOriginalDocumentCount() {
+ return mNativeOriginalDocumentCount;
+ }
+
+ /** Returns number of documents deleted during the optimization. */
+ public int getDeletedDocumentCount() {
+ return mNativeDeletedDocumentCount;
+ }
+
+ /** Returns number of documents expired during the optimization. */
+ public int getExpiredDocumentCount() {
+ return mNativeExpiredDocumentCount;
+ }
+
+ /** Returns size of storage in bytes before the optimization. */
+ public long getStorageSizeBeforeBytes() {
+ return mNativeStorageSizeBeforeBytes;
+ }
+
+ /** Returns size of storage in bytes after the optimization. */
+ public long getStorageSizeAfterBytes() {
+ return mNativeStorageSizeAfterBytes;
+ }
+
+ /**
+ * Returns the amount of time in millis since the last optimization ran calculated using wall
+ * clock time.
+ */
+ public long getTimeSinceLastOptimizeMillis() {
+ return mNativeTimeSinceLastOptimizeMillis;
+ }
+
+ /** Builder for {@link RemoveStats}. */
+ public static class Builder {
+ /**
+ * The status code returned by {@link AppSearchResult#getResultCode()} for the call or
+ * internal state.
+ */
+ @AppSearchResult.ResultCode int mStatusCode;
+
+ int mTotalLatencyMillis;
+ int mNativeLatencyMillis;
+ int mNativeDocumentStoreOptimizeLatencyMillis;
+ int mNativeIndexRestorationLatencyMillis;
+ int mNativeOriginalDocumentCount;
+ int mNativeDeletedDocumentCount;
+ int mNativeExpiredDocumentCount;
+ long mNativeStorageSizeBeforeBytes;
+ long mNativeStorageSizeAfterBytes;
+ long mNativeTimeSinceLastOptimizeMillis;
+
+ /** Sets the status code. */
+ @NonNull
+ public Builder setStatusCode(@AppSearchResult.ResultCode int statusCode) {
+ mStatusCode = statusCode;
+ return this;
+ }
+
+ /** Sets total latency in millis. */
+ @NonNull
+ public Builder setTotalLatencyMillis(int totalLatencyMillis) {
+ mTotalLatencyMillis = totalLatencyMillis;
+ return this;
+ }
+
+ /** Sets native latency in millis. */
+ @NonNull
+ public Builder setNativeLatencyMillis(int nativeLatencyMillis) {
+ mNativeLatencyMillis = nativeLatencyMillis;
+ return this;
+ }
+
+ /** Sets time used to optimize the document store. */
+ @NonNull
+ public Builder setDocumentStoreOptimizeLatencyMillis(
+ int documentStoreOptimizeLatencyMillis) {
+ mNativeDocumentStoreOptimizeLatencyMillis = documentStoreOptimizeLatencyMillis;
+ return this;
+ }
+
+ /** Sets time used to restore the index. */
+ @NonNull
+ public Builder setIndexRestorationLatencyMillis(int indexRestorationLatencyMillis) {
+ mNativeIndexRestorationLatencyMillis = indexRestorationLatencyMillis;
+ return this;
+ }
+
+ /** Sets number of documents before the optimization. */
+ @NonNull
+ public Builder setOriginalDocumentCount(int originalDocumentCount) {
+ mNativeOriginalDocumentCount = originalDocumentCount;
+ return this;
+ }
+
+ /** Sets number of documents deleted during the optimization. */
+ @NonNull
+ public Builder setDeletedDocumentCount(int deletedDocumentCount) {
+ mNativeDeletedDocumentCount = deletedDocumentCount;
+ return this;
+ }
+
+ /** Sets number of documents expired during the optimization. */
+ @NonNull
+ public Builder setExpiredDocumentCount(int expiredDocumentCount) {
+ mNativeExpiredDocumentCount = expiredDocumentCount;
+ return this;
+ }
+
+ /** Sets Storage size in bytes before optimization. */
+ @NonNull
+ public Builder setStorageSizeBeforeBytes(long storageSizeBeforeBytes) {
+ mNativeStorageSizeBeforeBytes = storageSizeBeforeBytes;
+ return this;
+ }
+
+ /** Sets storage size in bytes after optimization. */
+ @NonNull
+ public Builder setStorageSizeAfterBytes(long storageSizeAfterBytes) {
+ mNativeStorageSizeAfterBytes = storageSizeAfterBytes;
+ return this;
+ }
+
+ /**
+ * Sets the amount the time since the last optimize ran calculated using wall clock time.
+ */
+ @NonNull
+ public Builder setTimeSinceLastOptimizeMillis(long timeSinceLastOptimizeMillis) {
+ mNativeTimeSinceLastOptimizeMillis = timeSinceLastOptimizeMillis;
+ return this;
+ }
+
+ /** Creates a {@link OptimizeStats}. */
+ @NonNull
+ public OptimizeStats build() {
+ return new OptimizeStats(/* builder= */ this);
+ }
+ }
+}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java b/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java
index 2cbce10..fdf6a00 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java
@@ -32,6 +32,7 @@
import com.android.server.appsearch.external.localstorage.AppSearchLogger;
import com.android.server.appsearch.external.localstorage.stats.CallStats;
import com.android.server.appsearch.external.localstorage.stats.InitializeStats;
+import com.android.server.appsearch.external.localstorage.stats.OptimizeStats;
import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats;
import com.android.server.appsearch.external.localstorage.stats.RemoveStats;
import com.android.server.appsearch.external.localstorage.stats.SearchStats;
@@ -145,7 +146,7 @@
}
@Override
- public void logStats(@NonNull InitializeStats stats) throws AppSearchException {
+ public void logStats(@NonNull InitializeStats stats) {
Objects.requireNonNull(stats);
synchronized (mLock) {
if (shouldLogForTypeLocked(CallStats.CALL_TYPE_INITIALIZE)) {
@@ -155,7 +156,7 @@
}
@Override
- public void logStats(@NonNull SearchStats stats) throws AppSearchException {
+ public void logStats(@NonNull SearchStats stats) {
Objects.requireNonNull(stats);
synchronized (mLock) {
if (shouldLogForTypeLocked(CallStats.CALL_TYPE_SEARCH)) {
@@ -165,10 +166,20 @@
}
@Override
- public void logStats(@NonNull RemoveStats stats) throws AppSearchException {
+ public void logStats(@NonNull RemoveStats stats) {
// TODO(b/173532925): Log stats
}
+ @Override
+ public void logStats(@NonNull OptimizeStats stats) {
+ Objects.requireNonNull(stats);
+ synchronized (mLock) {
+ if (shouldLogForTypeLocked(CallStats.CALL_TYPE_OPTIMIZE)) {
+ logStatsImplLocked(stats);
+ }
+ }
+ }
+
/**
* Removes cached UID for package.
*
@@ -326,6 +337,27 @@
stats.getResetStatusCode());
}
+ @GuardedBy("mLock")
+ private void logStatsImplLocked(@NonNull OptimizeStats stats) {
+ mLastPushTimeMillisLocked = SystemClock.elapsedRealtime();
+ ExtraStats extraStats = createExtraStatsLocked(/*packageName=*/ null,
+ CallStats.CALL_TYPE_OPTIMIZE);
+ AppSearchStatsLog.write(AppSearchStatsLog.APP_SEARCH_OPTIMIZE_STATS_REPORTED,
+ extraStats.mSamplingInterval,
+ extraStats.mSkippedSampleCount,
+ stats.getStatusCode(),
+ stats.getTotalLatencyMillis(),
+ stats.getNativeLatencyMillis(),
+ stats.getDocumentStoreOptimizeLatencyMillis(),
+ stats.getIndexRestorationLatencyMillis(),
+ stats.getOriginalDocumentCount(),
+ stats.getDeletedDocumentCount(),
+ stats.getExpiredDocumentCount(),
+ stats.getStorageSizeBeforeBytes(),
+ stats.getStorageSizeAfterBytes(),
+ stats.getTimeSinceLastOptimizeMillis());
+ }
+
/**
* Calculate the hash code as an integer by returning the last four bytes of its MD5.
*
@@ -464,15 +496,19 @@
return mConfig.getCachedSamplingIntervalForBatchCallStats();
case CallStats.CALL_TYPE_PUT_DOCUMENT:
return mConfig.getCachedSamplingIntervalForPutDocumentStats();
- case CallStats.CALL_TYPE_UNKNOWN:
case CallStats.CALL_TYPE_INITIALIZE:
+ return mConfig.getCachedSamplingIntervalForInitializeStats();
+ case CallStats.CALL_TYPE_SEARCH:
+ return mConfig.getCachedSamplingIntervalForSearchStats();
+ case CallStats.CALL_TYPE_GLOBAL_SEARCH:
+ return mConfig.getCachedSamplingIntervalForGlobalSearchStats();
+ case CallStats.CALL_TYPE_OPTIMIZE:
+ return mConfig.getCachedSamplingIntervalForOptimizeStats();
+ case CallStats.CALL_TYPE_UNKNOWN:
case CallStats.CALL_TYPE_SET_SCHEMA:
case CallStats.CALL_TYPE_GET_DOCUMENT:
case CallStats.CALL_TYPE_REMOVE_DOCUMENT_BY_ID:
- case CallStats.CALL_TYPE_SEARCH:
- case CallStats.CALL_TYPE_OPTIMIZE:
case CallStats.CALL_TYPE_FLUSH:
- case CallStats.CALL_TYPE_GLOBAL_SEARCH:
case CallStats.CALL_TYPE_REMOVE_DOCUMENT_BY_SEARCH:
// TODO(b/173532925) Some of them above will have dedicated sampling ratio config
default:
diff --git a/apex/appsearch/synced_jetpack_changeid.txt b/apex/appsearch/synced_jetpack_changeid.txt
index 6555107..a81d7d80 100644
--- a/apex/appsearch/synced_jetpack_changeid.txt
+++ b/apex/appsearch/synced_jetpack_changeid.txt
@@ -1 +1 @@
-c7387d9b58726a23a0608a9365fb3a1b57b7b8a1
+Ie04f1ecc033faae8085afcb51eb9e40a298998d5
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
index 45588e8..03465fd 100644
--- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
@@ -2150,7 +2150,7 @@
private LocationManager mLocationManager;
Injector(Context ctx) {
- mContext = ctx;
+ mContext = ctx.createAttributionContext(TAG);
}
AlarmManager getAlarmManager() {
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 98e963e..86fa06c 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -2052,10 +2052,11 @@
+ " -- package not allowed to start");
return;
}
+ final int callerProcState = mActivityManagerInternal.getUidProcessState(callingUid);
removeLocked(operation, directReceiver, REMOVE_REASON_UNDEFINED);
incrementAlarmCount(a.uid);
setImplLocked(a);
- MetricsHelper.pushAlarmScheduled(a);
+ MetricsHelper.pushAlarmScheduled(a, callerProcState);
}
/**
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/MetricsHelper.java b/apex/jobscheduler/service/java/com/android/server/alarm/MetricsHelper.java
index 4e7311f..4c2f8d1 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/MetricsHelper.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/MetricsHelper.java
@@ -22,6 +22,7 @@
import static com.android.internal.util.FrameworkStatsLog.ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__PERMISSION;
import static com.android.server.alarm.AlarmManagerService.INDEFINITE_DELAY;
+import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.StatsManager;
import android.content.Context;
@@ -93,7 +94,7 @@
}
}
- static void pushAlarmScheduled(Alarm a) {
+ static void pushAlarmScheduled(Alarm a, int callerProcState) {
FrameworkStatsLog.write(
FrameworkStatsLog.ALARM_SCHEDULED,
a.uid,
@@ -103,7 +104,8 @@
a.alarmClock != null,
a.repeatInterval != 0,
reasonToStatsReason(a.mExactAllowReason),
- AlarmManagerService.isRtc(a.type));
+ AlarmManagerService.isRtc(a.type),
+ ActivityManager.processStateAmToProto(callerProcState));
}
static void pushAlarmBatchDelivered(int numAlarms, int wakeups) {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
index 2ebd1ad..986b2d9 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
@@ -116,6 +116,16 @@
@VisibleForTesting
int mVerb;
private boolean mCancelled;
+ /**
+ * True if the previous job on this context successfully finished (ie. called jobFinished or
+ * dequeueWork with no work left).
+ */
+ private boolean mPreviousJobHadSuccessfulFinish;
+ /**
+ * The last time a job on this context didn't finish successfully, in the elapsed realtime
+ * timebase.
+ */
+ private long mLastUnsuccessfulFinishElapsed;
/**
* All the information maintained about the job currently being executed.
@@ -447,7 +457,9 @@
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- assertCallerLocked(cb);
+ if (!assertCallerLocked(cb)) {
+ return null;
+ }
if (mVerb == VERB_STOPPING || mVerb == VERB_FINISHED) {
// This job is either all done, or on its way out. Either way, it
// should not dispatch any more work. We will pick up any remaining
@@ -473,7 +485,11 @@
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- assertCallerLocked(cb);
+ if (!assertCallerLocked(cb)) {
+ // Return true instead of false here so we don't just kick the
+ // Exception-throwing-can down the road to JobParameters.completeWork >:(
+ return true;
+ }
return mRunningJob.completeWorkLocked(workId);
}
} finally {
@@ -530,18 +546,34 @@
return true;
}
- private void assertCallerLocked(JobCallback cb) {
+ /**
+ * Will throw a {@link SecurityException} if the callback is not for the currently running job,
+ * but may decide not to throw an exception if the call from the previous job appears to be an
+ * accident.
+ *
+ * @return true if the callback is for the current job, false otherwise
+ */
+ private boolean assertCallerLocked(JobCallback cb) {
if (!verifyCallerLocked(cb)) {
+ final long nowElapsed = sElapsedRealtimeClock.millis();
+ if (!mPreviousJobHadSuccessfulFinish
+ && (nowElapsed - mLastUnsuccessfulFinishElapsed) < 15_000L) {
+ // Don't punish apps for race conditions
+ return false;
+ }
+ // It's been long enough that the app should really not be calling into JS for the
+ // stopped job.
StringBuilder sb = new StringBuilder(128);
sb.append("Caller no longer running");
if (cb.mStoppedReason != null) {
sb.append(", last stopped ");
- TimeUtils.formatDuration(sElapsedRealtimeClock.millis() - cb.mStoppedTime, sb);
+ TimeUtils.formatDuration(nowElapsed - cb.mStoppedTime, sb);
sb.append(" because: ");
sb.append(cb.mStoppedReason);
}
throw new SecurityException(sb.toString());
}
+ return true;
}
/**
@@ -887,6 +919,11 @@
applyStoppedReasonLocked(reason);
completedJob = mRunningJob;
final int internalStopReason = mParams.getInternalStopReasonCode();
+ mPreviousJobHadSuccessfulFinish =
+ (internalStopReason == JobParameters.INTERNAL_STOP_REASON_SUCCESSFUL_FINISH);
+ if (!mPreviousJobHadSuccessfulFinish) {
+ mLastUnsuccessfulFinishElapsed = sElapsedRealtimeClock.millis();
+ }
mJobPackageTracker.noteInactive(completedJob, internalStopReason, reason);
FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED,
completedJob.getSourceUid(), null, completedJob.getBatteryName(),
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index fda57f7..76836e4 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -92,7 +92,6 @@
static final int CONSTRAINT_CONTENT_TRIGGER = 1<<26;
static final int CONSTRAINT_DEVICE_NOT_DOZING = 1 << 25; // Implicit constraint
static final int CONSTRAINT_WITHIN_QUOTA = 1 << 24; // Implicit constraint
- static final int CONSTRAINT_WITHIN_EXPEDITED_QUOTA = 1 << 23; // Implicit constraint
static final int CONSTRAINT_BACKGROUND_NOT_RESTRICTED = 1 << 22; // Implicit constraint
// The following set of dynamic constraints are for specific use cases (as explained in their
@@ -148,8 +147,7 @@
| CONSTRAINT_DEADLINE
| CONSTRAINT_IDLE
| CONSTRAINT_TIMING_DELAY
- | CONSTRAINT_WITHIN_QUOTA
- | CONSTRAINT_WITHIN_EXPEDITED_QUOTA;
+ | CONSTRAINT_WITHIN_QUOTA;
// TODO(b/129954980)
private static final boolean STATS_LOG_ENABLED = false;
@@ -393,6 +391,11 @@
private long mTotalNetworkUploadBytes = JobInfo.NETWORK_BYTES_UNKNOWN;
private long mMinimumNetworkChunkBytes = JobInfo.NETWORK_BYTES_UNKNOWN;
+ /**
+ * Whether or not this job is approved to be treated as expedited per quota policy.
+ */
+ private boolean mExpeditedQuotaApproved;
+
/////// Booleans that track if a job is ready to run. They should be updated whenever dependent
/////// states change.
@@ -418,9 +421,6 @@
/** The job is within its quota based on its standby bucket. */
private boolean mReadyWithinQuota;
- /** The job is an expedited job with sufficient quota to run as an expedited job. */
- private boolean mReadyWithinExpeditedQuota;
-
/** The job's dynamic requirements have been satisfied. */
private boolean mReadyDynamicSatisfied;
@@ -1132,7 +1132,7 @@
* treated as an expedited job.
*/
public boolean shouldTreatAsExpeditedJob() {
- return mReadyWithinExpeditedQuota && isRequestedExpeditedJob();
+ return mExpeditedQuotaApproved && isRequestedExpeditedJob();
}
/**
@@ -1230,19 +1230,27 @@
return false;
}
- /** @return true if the constraint was changed, false otherwise. */
- boolean setExpeditedJobQuotaConstraintSatisfied(final long nowElapsed, boolean state) {
- if (setConstraintSatisfied(CONSTRAINT_WITHIN_EXPEDITED_QUOTA, nowElapsed, state)) {
- // The constraint was changed. Update the ready flag.
- mReadyWithinExpeditedQuota = state;
- // DeviceIdleJobsController currently only tracks jobs with the WILL_BE_FOREGROUND flag.
- // Making it also track requested-expedited jobs would add unnecessary hops since the
- // controller would then defer to canRunInDoze. Avoid the hops and just update
- // mReadyNotDozing directly.
- mReadyNotDozing = isConstraintSatisfied(CONSTRAINT_DEVICE_NOT_DOZING) || canRunInDoze();
- return true;
+ /**
+ * Sets whether or not this job is approved to be treated as an expedited job based on quota
+ * policy.
+ *
+ * @return true if the approval bit was changed, false otherwise.
+ */
+ boolean setExpeditedJobQuotaApproved(final long nowElapsed, boolean state) {
+ if (mExpeditedQuotaApproved == state) {
+ return false;
}
- return false;
+ mExpeditedQuotaApproved = state;
+ updateExpeditedDependencies();
+ return true;
+ }
+
+ private void updateExpeditedDependencies() {
+ // DeviceIdleJobsController currently only tracks jobs with the WILL_BE_FOREGROUND flag.
+ // Making it also track requested-expedited jobs would add unnecessary hops since the
+ // controller would then defer to canRunInDoze. Avoid the hops and just update
+ // mReadyNotDozing directly.
+ mReadyNotDozing = isConstraintSatisfied(CONSTRAINT_DEVICE_NOT_DOZING) || canRunInDoze();
}
/** @return true if the state was changed, false otherwise. */
@@ -1346,7 +1354,6 @@
return JobParameters.STOP_REASON_DEVICE_STATE;
case CONSTRAINT_WITHIN_QUOTA:
- case CONSTRAINT_WITHIN_EXPEDITED_QUOTA:
return JobParameters.STOP_REASON_QUOTA;
// These should never be stop reasons since they can never go from true to false.
@@ -1363,6 +1370,10 @@
return (satisfiedConstraints&constraint) != 0;
}
+ boolean isExpeditedQuotaApproved() {
+ return mExpeditedQuotaApproved;
+ }
+
boolean clearTrackingController(int which) {
if ((trackingControllers&which) != 0) {
trackingControllers &= ~which;
@@ -1465,10 +1476,6 @@
oldValue = mReadyWithinQuota;
mReadyWithinQuota = value;
break;
- case CONSTRAINT_WITHIN_EXPEDITED_QUOTA:
- oldValue = mReadyWithinExpeditedQuota;
- mReadyWithinExpeditedQuota = value;
- break;
default:
if (value) {
satisfied |= constraint;
@@ -1496,9 +1503,6 @@
case CONSTRAINT_WITHIN_QUOTA:
mReadyWithinQuota = oldValue;
break;
- case CONSTRAINT_WITHIN_EXPEDITED_QUOTA:
- mReadyWithinExpeditedQuota = oldValue;
- break;
default:
mReadyDynamicSatisfied = mDynamicConstraints != 0
&& mDynamicConstraints == (satisfiedConstraints & mDynamicConstraints);
@@ -1726,9 +1730,6 @@
if ((constraints & CONSTRAINT_WITHIN_QUOTA) != 0) {
pw.print(" WITHIN_QUOTA");
}
- if ((constraints & CONSTRAINT_WITHIN_EXPEDITED_QUOTA) != 0) {
- pw.print(" WITHIN_EXPEDITED_QUOTA");
- }
if (constraints != 0) {
pw.print(" [0x");
pw.print(Integer.toHexString(constraints));
@@ -1801,9 +1802,6 @@
if ((constraints & CONSTRAINT_BACKGROUND_NOT_RESTRICTED) != 0) {
proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_BACKGROUND_NOT_RESTRICTED);
}
- if ((constraints & CONSTRAINT_WITHIN_EXPEDITED_QUOTA) != 0) {
- proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_WITHIN_EXPEDITED_JOB_QUOTA);
- }
}
private void dumpJobWorkItem(IndentingPrintWriter pw, JobWorkItem work, int index) {
@@ -2050,8 +2048,8 @@
pw.print("readyComponentEnabled: ");
pw.println(serviceInfo != null);
if ((getFlags() & JobInfo.FLAG_EXPEDITED) != 0) {
- pw.print("readyWithinExpeditedQuota: ");
- pw.print(mReadyWithinExpeditedQuota);
+ pw.print("expeditedQuotaApproved: ");
+ pw.print(mExpeditedQuotaApproved);
pw.print(" (started as EJ: ");
pw.print(startedAsExpeditedJob);
pw.println(")");
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
index f7181a4..36afac8 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
@@ -634,11 +634,12 @@
jobs.add(jobStatus);
jobStatus.setTrackingController(JobStatus.TRACKING_QUOTA);
final boolean isWithinQuota = isWithinQuotaLocked(jobStatus);
- setConstraintSatisfied(jobStatus, nowElapsed, isWithinQuota);
+ final boolean isWithinEJQuota =
+ jobStatus.isRequestedExpeditedJob() && isWithinEJQuotaLocked(jobStatus);
+ setConstraintSatisfied(jobStatus, nowElapsed, isWithinQuota || isWithinEJQuota);
final boolean outOfEJQuota;
if (jobStatus.isRequestedExpeditedJob()) {
- final boolean isWithinEJQuota = isWithinEJQuotaLocked(jobStatus);
- setExpeditedConstraintSatisfied(jobStatus, nowElapsed, isWithinEJQuota);
+ setExpeditedQuotaApproved(jobStatus, nowElapsed, isWithinEJQuota);
outOfEJQuota = !isWithinEJQuota;
} else {
outOfEJQuota = false;
@@ -1614,6 +1615,8 @@
boolean changed = false;
for (int i = jobs.size() - 1; i >= 0; --i) {
final JobStatus js = jobs.valueAt(i);
+ final boolean isWithinEJQuota =
+ js.isRequestedExpeditedJob() && isWithinEJQuotaLocked(js);
if (isTopStartedJobLocked(js)) {
// Job was started while the app was in the TOP state so we should allow it to
// finish.
@@ -1623,15 +1626,15 @@
// An app in the ACTIVE bucket may be out of quota while the job could be in quota
// for some reason. Therefore, avoid setting the real value here and check each job
// individually.
- changed |= setConstraintSatisfied(js, nowElapsed, realInQuota);
+ changed |= setConstraintSatisfied(js, nowElapsed, isWithinEJQuota || realInQuota);
} else {
// This job is somehow exempted. Need to determine its own quota status.
- changed |= setConstraintSatisfied(js, nowElapsed, isWithinQuotaLocked(js));
+ changed |= setConstraintSatisfied(js, nowElapsed,
+ isWithinEJQuota || isWithinQuotaLocked(js));
}
if (js.isRequestedExpeditedJob()) {
- boolean isWithinEJQuota = isWithinEJQuotaLocked(js);
- changed |= setExpeditedConstraintSatisfied(js, nowElapsed, isWithinEJQuota);
+ changed |= setExpeditedQuotaApproved(js, nowElapsed, isWithinEJQuota);
outOfEJQuota |= !isWithinEJQuota;
}
}
@@ -1659,26 +1662,24 @@
@Override
public void accept(JobStatus jobStatus) {
- if (setConstraintSatisfied(
- jobStatus, mUpdateTimeElapsed, isWithinQuotaLocked(jobStatus))) {
+ final boolean isWithinEJQuota;
+ if (jobStatus.isRequestedExpeditedJob()) {
+ isWithinEJQuota = isWithinEJQuotaLocked(jobStatus);
+ } else {
+ isWithinEJQuota = false;
+ }
+ if (setConstraintSatisfied(jobStatus, mUpdateTimeElapsed,
+ isWithinEJQuota || isWithinQuotaLocked(jobStatus))) {
changedJobs.add(jobStatus);
}
- final boolean outOfEJQuota;
- if (jobStatus.isRequestedExpeditedJob()) {
- final boolean isWithinEJQuota = isWithinEJQuotaLocked(jobStatus);
- if (setExpeditedConstraintSatisfied(
- jobStatus, mUpdateTimeElapsed, isWithinEJQuota)) {
- changedJobs.add(jobStatus);
- }
- outOfEJQuota = !isWithinEJQuota;
- } else {
- outOfEJQuota = false;
+ if (setExpeditedQuotaApproved(jobStatus, mUpdateTimeElapsed, isWithinEJQuota)) {
+ changedJobs.add(jobStatus);
}
final int userId = jobStatus.getSourceUserId();
final String packageName = jobStatus.getSourcePackageName();
final int realStandbyBucket = jobStatus.getStandbyBucket();
- if (isWithinQuotaLocked(userId, packageName, realStandbyBucket) && !outOfEJQuota) {
+ if (isWithinQuotaLocked(userId, packageName, realStandbyBucket) && isWithinEJQuota) {
// TODO(141645789): we probably shouldn't cancel the alarm until we've verified
// that all jobs for the userId-package are within quota.
mInQuotaAlarmListener.removeAlarmLocked(userId, packageName);
@@ -1827,9 +1828,9 @@
* If the satisfaction changes, this will tell connectivity & background jobs controller to
* also re-evaluate their state.
*/
- private boolean setExpeditedConstraintSatisfied(@NonNull JobStatus jobStatus, long nowElapsed,
+ private boolean setExpeditedQuotaApproved(@NonNull JobStatus jobStatus, long nowElapsed,
boolean isWithinQuota) {
- if (jobStatus.setExpeditedJobQuotaConstraintSatisfied(nowElapsed, isWithinQuota)) {
+ if (jobStatus.setExpeditedJobQuotaApproved(nowElapsed, isWithinQuota)) {
mBackgroundJobsController.evaluateStateLocked(jobStatus);
mConnectivityController.evaluateStateLocked(jobStatus);
if (isWithinQuota && jobStatus.isReady()) {
@@ -4330,7 +4331,7 @@
js.isRequestedExpeditedJob());
proto.write(
StateControllerProto.QuotaController.TrackedJob.IS_WITHIN_FG_JOB_QUOTA,
- js.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_EXPEDITED_QUOTA));
+ js.isExpeditedQuotaApproved());
proto.end(jsToken);
}
});
diff --git a/core/api/current.txt b/core/api/current.txt
index 69c9439..a0489d1 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -45993,6 +45993,7 @@
method public boolean contains(Object);
method public boolean containsAll(java.util.Collection<?>);
method public void ensureCapacity(int);
+ method public void forEach(java.util.function.Consumer<? super E>);
method public int indexOf(Object);
method public boolean isEmpty();
method public java.util.Iterator<E> iterator();
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index bedaa3b..7a651c6 100755
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -957,7 +957,7 @@
field public static final String ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE = "android.app.action.PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE";
field @RequiresPermission(android.Manifest.permission.MANAGE_FACTORY_RESET_PROTECTION) public static final String ACTION_RESET_PROTECTION_POLICY_CHANGED = "android.app.action.RESET_PROTECTION_POLICY_CHANGED";
field public static final String ACTION_SET_PROFILE_OWNER = "android.app.action.SET_PROFILE_OWNER";
- field public static final String ACTION_STATE_USER_SETUP_COMPLETE = "android.app.action.STATE_USER_SETUP_COMPLETE";
+ field @Deprecated public static final String ACTION_STATE_USER_SETUP_COMPLETE = "android.app.action.STATE_USER_SETUP_COMPLETE";
field public static final String EXTRA_PROFILE_OWNER_NAME = "android.app.extra.PROFILE_OWNER_NAME";
field @Deprecated public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_ICON_URI = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_ICON_URI";
field @Deprecated public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_LABEL = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_LABEL";
diff --git a/core/java/Android.bp b/core/java/Android.bp
index 89d93ae..3a883d8 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -112,6 +112,8 @@
srcs: [
"android/os/Temperature.aidl",
"android/os/CoolingDevice.aidl",
+ "android/os/IHintManager.aidl",
+ "android/os/IHintSession.aidl",
"android/os/IThermalEventListener.aidl",
"android/os/IThermalStatusListener.aidl",
"android/os/IThermalService.aidl",
diff --git a/core/java/android/accounts/AbstractAccountAuthenticator.java b/core/java/android/accounts/AbstractAccountAuthenticator.java
index 7b57442f..3807b50 100644
--- a/core/java/android/accounts/AbstractAccountAuthenticator.java
+++ b/core/java/android/accounts/AbstractAccountAuthenticator.java
@@ -88,7 +88,8 @@
* {@link AccountManager#KEY_INTENT}.
* <p>
* The activity needs to return the final result when it is complete so the Intent should contain
- * the {@link AccountAuthenticatorResponse} as {@link AccountManager#KEY_ACCOUNT_MANAGER_RESPONSE}.
+ * the {@link AccountAuthenticatorResponse} as
+ * {@link AccountManager#KEY_ACCOUNT_AUTHENTICATOR_RESPONSE}.
* The activity must then call {@link AccountAuthenticatorResponse#onResult} or
* {@link AccountAuthenticatorResponse#onError} when it is complete.
* <li> If the authenticator cannot synchronously process the request and return a result then it
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 79fb863..2bbf280 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -27,6 +27,7 @@
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.UserHandleAware;
+import android.annotation.UserIdInt;
import android.app.Activity;
import android.app.PropertyInvalidatedCache;
import android.compat.annotation.UnsupportedAppUsage;
@@ -349,6 +350,7 @@
private static final class UserIdPackage
{
+ @UserIdInt
public int userId;
public String packageName;
@@ -379,7 +381,8 @@
}
PropertyInvalidatedCache<UserIdPackage, Account[]> mAccountsForUserCache =
- new PropertyInvalidatedCache<UserIdPackage, Account[]>(CACHE_ACCOUNTS_DATA_SIZE, CACHE_KEY_ACCOUNTS_DATA_PROPERTY) {
+ new PropertyInvalidatedCache<UserIdPackage, Account[]>(
+ CACHE_ACCOUNTS_DATA_SIZE, CACHE_KEY_ACCOUNTS_DATA_PROPERTY) {
@Override
protected Account[] recompute(UserIdPackage userAndPackage) {
try {
@@ -389,6 +392,10 @@
}
}
@Override
+ protected boolean bypass(UserIdPackage query) {
+ return query.userId < 0;
+ }
+ @Override
protected boolean debugCompareQueryResults(Account[] l, Account[] r) {
if (l == r) {
return true;
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index db5dcc5..eb913dd 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -61,7 +61,6 @@
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
-import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.media.AudioManager;
@@ -126,11 +125,9 @@
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityEvent;
+import android.view.autofill.AutofillClientController;
import android.view.autofill.AutofillId;
-import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillManager.AutofillClient;
-import android.view.autofill.AutofillPopupWindow;
-import android.view.autofill.IAutofillWindowPresenter;
import android.view.contentcapture.ContentCaptureContext;
import android.view.contentcapture.ContentCaptureManager;
import android.view.contentcapture.ContentCaptureManager.ContentCaptureClient;
@@ -159,7 +156,6 @@
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@@ -740,7 +736,7 @@
Window.Callback, KeyEvent.Callback,
OnCreateContextMenuListener, ComponentCallbacks2,
Window.OnWindowDismissedCallback,
- AutofillManager.AutofillClient, ContentCaptureManager.ContentCaptureClient {
+ ContentCaptureManager.ContentCaptureClient {
private static final String TAG = "Activity";
private static final boolean DEBUG_LIFECYCLE = false;
@@ -766,9 +762,7 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
static final String FRAGMENTS_TAG = "android:fragments";
- private static final String LAST_AUTOFILL_ID = "android:lastAutofillId";
- private static final String AUTOFILL_RESET_NEEDED = "@android:autofillResetNeeded";
private static final String WINDOW_HIERARCHY_TAG = "android:viewHierarchyState";
private static final String SAVED_DIALOG_IDS_KEY = "android:savedDialogIds";
private static final String SAVED_DIALOGS_TAG = "android:savedDialogs";
@@ -778,7 +772,6 @@
"android:hasCurrentPermissionsRequest";
private static final String REQUEST_PERMISSIONS_WHO_PREFIX = "@android:requestPermissions:";
- private static final String AUTO_FILL_AUTH_WHO_PREFIX = "@android:autoFillAuth:";
private static final String KEYBOARD_SHORTCUTS_RECEIVER_PKG_NAME = "com.android.systemui";
private static final int LOG_AM_ON_CREATE_CALLED = 30057;
@@ -851,9 +844,6 @@
private SearchManager mSearchManager;
private MenuInflater mMenuInflater;
- /** The autofill manager. Always access via {@link #getAutofillManager()}. */
- @Nullable private AutofillManager mAutofillManager;
-
/** The content capture manager. Access via {@link #getContentCaptureManager()}. */
@Nullable private ContentCaptureManager mContentCaptureManager;
@@ -953,13 +943,8 @@
private boolean mHasCurrentPermissionsRequest;
- private boolean mAutoFillResetNeeded;
- private boolean mAutoFillIgnoreFirstResumePause;
-
- /** The last autofill id that was returned from {@link #getNextAutofillId()} */
- private int mLastAutofillId = View.LAST_APP_AUTOFILL_ID;
-
- private AutofillPopupWindow mAutofillPopupWindow;
+ /** The autofill client controller. Always access via {@link #getAutofillClientController()}. */
+ private AutofillClientController mAutofillClientController;
/** @hide */
boolean mEnterAnimationComplete;
@@ -1140,19 +1125,6 @@
}
/**
- * (Creates, sets and) returns the autofill manager
- *
- * @return The autofill manager
- */
- @NonNull private AutofillManager getAutofillManager() {
- if (mAutofillManager == null) {
- mAutofillManager = getSystemService(AutofillManager.class);
- }
-
- return mAutofillManager;
- }
-
- /**
* (Creates, sets, and ) returns the content capture manager
*
* @return The content capture manager
@@ -1250,7 +1222,7 @@
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(newBase);
if (newBase != null) {
- newBase.setAutofillClient(this);
+ newBase.setAutofillClient(getAutofillClient());
newBase.setContentCaptureOptions(getContentCaptureOptions());
}
}
@@ -1258,7 +1230,14 @@
/** @hide */
@Override
public final AutofillClient getAutofillClient() {
- return this;
+ return getAutofillClientController();
+ }
+
+ private AutofillClientController getAutofillClientController() {
+ if (mAutofillClientController == null) {
+ mAutofillClientController = new AutofillClientController(this);
+ }
+ return mAutofillClientController;
}
/** @hide */
@@ -1590,14 +1569,9 @@
mActionBar.setDefaultDisplayHomeAsUpEnabled(true);
}
}
- if (savedInstanceState != null) {
- mAutoFillResetNeeded = savedInstanceState.getBoolean(AUTOFILL_RESET_NEEDED, false);
- mLastAutofillId = savedInstanceState.getInt(LAST_AUTOFILL_ID,
- View.LAST_APP_AUTOFILL_ID);
- if (mAutoFillResetNeeded) {
- getAutofillManager().onCreate(savedInstanceState);
- }
+ if (savedInstanceState != null) {
+ getAutofillClientController().onActivityCreated(savedInstanceState);
Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
mFragments.restoreAllState(p, mLastNonConfigurationInstances != null
@@ -1877,9 +1851,7 @@
dispatchActivityStarted();
- if (mAutoFillResetNeeded) {
- getAutofillManager().onVisibleForAutofill();
- }
+ getAutofillClientController().onActivityStarted();
}
/**
@@ -1949,22 +1921,7 @@
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onResume " + this);
dispatchActivityResumed();
mActivityTransitionState.onResume(this);
- enableAutofillCompatibilityIfNeeded();
- if (mAutoFillResetNeeded) {
- if (!mAutoFillIgnoreFirstResumePause) {
- View focus = getCurrentFocus();
- if (focus != null && focus.canNotifyAutofillEnterExitEvent()) {
- // TODO(b/148815880): Bring up keyboard if resumed from inline authentication.
- // TODO: in Activity killed/recreated case, i.e. SessionLifecycleTest#
- // testDatasetVisibleWhileAutofilledAppIsLifecycled: the View's initial
- // window visibility after recreation is INVISIBLE in onResume() and next frame
- // ViewRootImpl.performTraversals() changes window visibility to VISIBLE.
- // So we cannot call View.notifyEnterOrExited() which will do nothing
- // when View.isVisibleToUser() is false.
- getAutofillManager().notifyViewEntered(focus);
- }
- }
- }
+ getAutofillClientController().onActivityResumed();
notifyContentCaptureManagerIfNeeded(CONTENT_CAPTURE_RESUME);
@@ -2045,32 +2002,16 @@
}
/**
- * Gets the next autofill ID.
+ * Returns the next autofill ID that is unique in the activity
*
* <p>All IDs will be bigger than {@link View#LAST_APP_AUTOFILL_ID}. All IDs returned
* will be unique.
*
- * @return A ID that is unique in the activity
- *
* {@hide}
*/
@Override
public int getNextAutofillId() {
- if (mLastAutofillId == Integer.MAX_VALUE - 1) {
- mLastAutofillId = View.LAST_APP_AUTOFILL_ID;
- }
-
- mLastAutofillId++;
-
- return mLastAutofillId;
- }
-
- /**
- * @hide
- */
- @Override
- public AutofillId autofillClientGetNextAutofillId() {
- return new AutofillId(getNextAutofillId());
+ return getAutofillClientController().getNextAutofillId();
}
/**
@@ -2273,15 +2214,11 @@
protected void onSaveInstanceState(@NonNull Bundle outState) {
outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState());
- outState.putInt(LAST_AUTOFILL_ID, mLastAutofillId);
Parcelable p = mFragments.saveAllState();
if (p != null) {
outState.putParcelable(FRAGMENTS_TAG, p);
}
- if (mAutoFillResetNeeded) {
- outState.putBoolean(AUTOFILL_RESET_NEEDED, true);
- getAutofillManager().onSaveInstanceState(outState);
- }
+ getAutofillClientController().onSaveInstanceState(outState);
dispatchActivitySaveInstanceState(outState);
}
@@ -2380,19 +2317,7 @@
protected void onPause() {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onPause " + this);
dispatchActivityPaused();
- if (mAutoFillResetNeeded) {
- if (!mAutoFillIgnoreFirstResumePause) {
- if (DEBUG_LIFECYCLE) Slog.v(TAG, "autofill notifyViewExited " + this);
- View focus = getCurrentFocus();
- if (focus != null && focus.canNotifyAutofillEnterExitEvent()) {
- getAutofillManager().notifyViewExited(focus);
- }
- } else {
- // reset after first pause()
- if (DEBUG_LIFECYCLE) Slog.v(TAG, "autofill got first pause " + this);
- mAutoFillIgnoreFirstResumePause = false;
- }
- }
+ getAutofillClientController().onActivityPaused();
notifyContentCaptureManagerIfNeeded(CONTENT_CAPTURE_PAUSE);
mCalled = true;
@@ -2623,14 +2548,7 @@
mTranslucentCallback = null;
mCalled = true;
- if (mAutoFillResetNeeded) {
- // If stopped without changing the configurations, the response should expire.
- getAutofillManager().onInvisibleForAutofill(!mChangingConfigurations);
- } else if (mIntent != null
- && mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN)
- && mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY)) {
- restoreAutofillSaveUi();
- }
+ getAutofillClientController().onActivityStopped(mIntent, mChangingConfigurations);
mEnterAnimationComplete = false;
}
@@ -2667,9 +2585,7 @@
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onDestroy " + this);
mCalled = true;
- if (isFinishing() && mAutoFillResetNeeded) {
- getAutofillManager().onActivityFinishing();
- }
+ getAutofillClientController().onActivityDestroyed();
// dismiss any dialogs we are managing.
if (mManagedDialogs != null) {
@@ -3908,11 +3824,7 @@
ActivityClient.getInstance().onBackPressedOnTaskRoot(mToken,
new RequestFinishCallback(new WeakReference<>(this)));
- // Activity was launched when user tapped a link in the Autofill Save UI - Save UI must
- // be restored now.
- if (mIntent != null && mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN)) {
- restoreAutofillSaveUi();
- }
+ getAutofillClientController().onActivityBackPressed(mIntent);
}
/**
@@ -5602,6 +5514,18 @@
}
/**
+ * Like {@link #startIntentSenderForResult} but taking {@code who} as an additional identifier.
+ *
+ * @hide
+ */
+ public void startIntentSenderForResult(IntentSender intent, String who, int requestCode,
+ Intent fillInIntent, int flagsMask, int flagsValues, Bundle options)
+ throws IntentSender.SendIntentException {
+ startIntentSenderForResultInner(intent, who, requestCode, fillInIntent, flagsMask,
+ flagsValues, options);
+ }
+
+ /**
* Like {@link #startActivityForResult(Intent, int)}, but allowing you
* to use a IntentSender to describe the activity to be started. If
* the IntentSender is for an activity, that activity will be started
@@ -5643,7 +5567,10 @@
}
}
- private void startIntentSenderForResultInner(IntentSender intent, String who, int requestCode,
+ /**
+ * @hide
+ */
+ public void startIntentSenderForResultInner(IntentSender intent, String who, int requestCode,
Intent fillInIntent, int flagsMask, int flagsValues,
@Nullable Bundle options)
throws IntentSender.SendIntentException {
@@ -5725,21 +5652,7 @@
*/
@Override
public void startActivity(Intent intent, @Nullable Bundle options) {
- if (mIntent != null && mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN)
- && mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY)) {
- if (TextUtils.equals(getPackageName(),
- intent.resolveActivity(getPackageManager()).getPackageName())) {
- // Apply Autofill restore mechanism on the started activity by startActivity()
- final IBinder token =
- mIntent.getIBinderExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN);
- // Remove restore ability from current activity
- mIntent.removeExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN);
- mIntent.removeExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY);
- // Put restore token
- intent.putExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN, token);
- intent.putExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY, true);
- }
- }
+ getAutofillClientController().onStartActivity(intent, mIntent);
if (options != null) {
startActivityForResult(intent, -1, options);
} else {
@@ -6471,24 +6384,7 @@
mParent.finishFromChild(this);
}
- // Activity was launched when user tapped a link in the Autofill Save UI - Save UI must
- // be restored now.
- if (mIntent != null && mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN)) {
- restoreAutofillSaveUi();
- }
- }
-
- /**
- * Restores Autofill Save UI
- */
- private void restoreAutofillSaveUi() {
- final IBinder token =
- mIntent.getIBinderExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN);
- // Make only restore Autofill once
- mIntent.removeExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN);
- mIntent.removeExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY);
- getAutofillManager().onPendingSaveUi(AutofillManager.PENDING_UI_OPERATION_RESTORE,
- token);
+ getAutofillClientController().onActivityFinish(mIntent);
}
/**
@@ -6805,12 +6701,6 @@
/** @hide */
@Override
- public final ComponentName autofillClientGetComponentName() {
- return getComponentName();
- }
-
- /** @hide */
- @Override
public final ComponentName contentCaptureClientGetComponentName() {
return getComponentName();
}
@@ -7134,12 +7024,6 @@
}
}
- /** @hide */
- @Override
- public final void autofillClientRunOnUiThread(Runnable action) {
- runOnUiThread(action);
- }
-
/**
* Standard implementation of
* {@link android.view.LayoutInflater.Factory#onCreateView} used when
@@ -7198,7 +7082,7 @@
// Handle special cases
switch (args[0]) {
case "--autofill":
- dumpAutofillManager(prefix, writer);
+ getAutofillClientController().dumpAutofillManager(prefix, writer);
return;
case "--contentcapture":
dumpContentCaptureManager(prefix, writer);
@@ -7244,24 +7128,13 @@
mHandler.getLooper().dump(new PrintWriterPrinter(writer), prefix);
- dumpAutofillManager(prefix, writer);
+ getAutofillClientController().dumpAutofillManager(prefix, writer);
dumpContentCaptureManager(prefix, writer);
dumpUiTranslation(prefix, writer);
ResourcesManager.getInstance().dump(prefix, writer);
}
- void dumpAutofillManager(String prefix, PrintWriter writer) {
- final AutofillManager afm = getAutofillManager();
- if (afm != null) {
- afm.dump(prefix, writer);
- writer.print(prefix); writer.print("Autofill Compat Mode: ");
- writer.println(isAutofillCompatibilityEnabled());
- } else {
- writer.print(prefix); writer.println("No AutofillManager");
- }
- }
-
void dumpContentCaptureManager(String prefix, PrintWriter writer) {
final ContentCaptureManager cm = getContentCaptureManager();
if (cm != null) {
@@ -7992,19 +7865,10 @@
mWindow.setPreferMinimalPostProcessing(
(info.flags & ActivityInfo.FLAG_PREFER_MINIMAL_POST_PROCESSING) != 0);
- setAutofillOptions(application.getAutofillOptions());
+ getAutofillClientController().onActivityAttached(application);
setContentCaptureOptions(application.getContentCaptureOptions());
}
- private void enableAutofillCompatibilityIfNeeded() {
- if (isAutofillCompatibilityEnabled()) {
- final AutofillManager afm = getSystemService(AutofillManager.class);
- if (afm != null) {
- afm.enableCompatibilityMode();
- }
- }
- }
-
/** @hide */
@UnsupportedAppUsage
public final IBinder getActivityToken() {
@@ -8176,15 +8040,7 @@
mLastNonConfigurationInstances = null;
- if (mAutoFillResetNeeded) {
- // When Activity is destroyed in paused state, and relaunch activity, there will be
- // extra onResume and onPause event, ignore the first onResume and onPause.
- // see ActivityThread.handleRelaunchActivity()
- mAutoFillIgnoreFirstResumePause = followedByPause;
- if (mAutoFillIgnoreFirstResumePause && DEBUG_LIFECYCLE) {
- Slog.v(TAG, "autofill will ignore first pause when relaunching " + this);
- }
- }
+ getAutofillClientController().onActivityPerformResume(followedByPause);
mCalled = false;
// mResumed is set by the instrumentation
@@ -8196,7 +8052,7 @@
" did not call through to super.onResume()");
}
- // invisible activities must be finished before onResume() completes
+ // invisible activities must be finished before onResume) completes
if (!mVisibleFromClient && !mFinished) {
Log.w(TAG, "An activity without a UI must call finish() before onResume() completes");
if (getApplicationInfo().targetSdkVersion
@@ -8400,9 +8256,8 @@
return;
}
}
- } else if (who.startsWith(AUTO_FILL_AUTH_WHO_PREFIX)) {
- Intent resultData = (resultCode == Activity.RESULT_OK) ? data : null;
- getAutofillManager().onAuthenticationResult(requestCode, resultData, getCurrentFocus());
+ } else if (who.startsWith(AutofillClientController.AUTO_FILL_AUTH_WHO_PREFIX)) {
+ getAutofillClientController().onDispatchActivityResult(requestCode, resultCode, data);
} else {
Fragment frag = mFragments.findFragmentByWho(who);
if (frag != null) {
@@ -8539,184 +8394,11 @@
fragment.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
- /** @hide */
- @Override
- public final void autofillClientAuthenticate(int authenticationId, IntentSender intent,
- Intent fillInIntent, boolean authenticateInline) {
- try {
- startIntentSenderForResultInner(intent, AUTO_FILL_AUTH_WHO_PREFIX,
- authenticationId, fillInIntent, 0, 0, null);
- } catch (IntentSender.SendIntentException e) {
- Log.e(TAG, "authenticate() failed for intent:" + intent, e);
- }
- }
-
- /** @hide */
- @Override
- public final void autofillClientResetableStateAvailable() {
- mAutoFillResetNeeded = true;
- }
-
- /** @hide */
- @Override
- public final boolean autofillClientRequestShowFillUi(@NonNull View anchor, int width,
- int height, @Nullable Rect anchorBounds, IAutofillWindowPresenter presenter) {
- final boolean wasShowing;
-
- if (mAutofillPopupWindow == null) {
- wasShowing = false;
- mAutofillPopupWindow = new AutofillPopupWindow(presenter);
- } else {
- wasShowing = mAutofillPopupWindow.isShowing();
- }
- mAutofillPopupWindow.update(anchor, 0, 0, width, height, anchorBounds);
-
- return !wasShowing && mAutofillPopupWindow.isShowing();
- }
-
- /** @hide */
- @Override
- public final void autofillClientDispatchUnhandledKey(@NonNull View anchor,
- @NonNull KeyEvent keyEvent) {
- ViewRootImpl rootImpl = anchor.getViewRootImpl();
- if (rootImpl != null) {
- // dont care if anchorView is current focus, for example a custom view may only receive
- // touchEvent, not focusable but can still trigger autofill window. The Key handling
- // might be inside parent of the custom view.
- rootImpl.dispatchKeyFromAutofill(keyEvent);
- }
- }
-
- /** @hide */
- @Override
- public final boolean autofillClientRequestHideFillUi() {
- if (mAutofillPopupWindow == null) {
- return false;
- }
- mAutofillPopupWindow.dismiss();
- mAutofillPopupWindow = null;
- return true;
- }
-
- /** @hide */
- @Override
- public final boolean autofillClientIsFillUiShowing() {
- return mAutofillPopupWindow != null && mAutofillPopupWindow.isShowing();
- }
-
- /** @hide */
- @Override
- @NonNull
- public final View[] autofillClientFindViewsByAutofillIdTraversal(
- @NonNull AutofillId[] autofillId) {
- final View[] views = new View[autofillId.length];
- final ArrayList<ViewRootImpl> roots =
- WindowManagerGlobal.getInstance().getRootViews(getActivityToken());
-
- for (int rootNum = 0; rootNum < roots.size(); rootNum++) {
- final View rootView = roots.get(rootNum).getView();
-
- if (rootView != null) {
- final int viewCount = autofillId.length;
- for (int viewNum = 0; viewNum < viewCount; viewNum++) {
- if (views[viewNum] == null) {
- views[viewNum] = rootView.findViewByAutofillIdTraversal(
- autofillId[viewNum].getViewId());
- }
- }
- }
- }
-
- return views;
- }
-
- /** @hide */
- @Nullable
- public View findViewByAutofillIdTraversal(@NonNull AutofillId autofillId) {
- final ArrayList<ViewRootImpl> roots =
- WindowManagerGlobal.getInstance().getRootViews(getActivityToken());
- for (int rootNum = 0; rootNum < roots.size(); rootNum++) {
- final View rootView = roots.get(rootNum).getView();
-
- if (rootView != null) {
- final View view = rootView.findViewByAutofillIdTraversal(autofillId.getViewId());
- if (view != null) {
- return view;
- }
- }
- }
- return null;
- }
-
- /** @hide */
- @Override
- @Nullable
- public final View autofillClientFindViewByAutofillIdTraversal(AutofillId autofillId) {
- return findViewByAutofillIdTraversal(autofillId);
- }
-
- /** @hide */
- @Override
- public final @NonNull boolean[] autofillClientGetViewVisibility(
- @NonNull AutofillId[] autofillIds) {
- final int autofillIdCount = autofillIds.length;
- final boolean[] visible = new boolean[autofillIdCount];
- for (int i = 0; i < autofillIdCount; i++) {
- final AutofillId autofillId = autofillIds[i];
- final View view = autofillClientFindViewByAutofillIdTraversal(autofillId);
- if (view != null) {
- if (!autofillId.isVirtualInt()) {
- visible[i] = view.isVisibleToUser();
- } else {
- visible[i] = view.isVisibleToUserForAutofill(autofillId.getVirtualChildIntId());
- }
- }
- }
- if (android.view.autofill.Helper.sVerbose) {
- Log.v(TAG, "autofillClientGetViewVisibility(): " + Arrays.toString(visible));
- }
- return visible;
- }
-
- /** @hide */
- public final @Nullable View autofillClientFindViewByAccessibilityIdTraversal(int viewId,
- int windowId) {
- final ArrayList<ViewRootImpl> roots = WindowManagerGlobal.getInstance()
- .getRootViews(getActivityToken());
- for (int rootNum = 0; rootNum < roots.size(); rootNum++) {
- final View rootView = roots.get(rootNum).getView();
- if (rootView != null && rootView.getAccessibilityWindowId() == windowId) {
- final View view = rootView.findViewByAccessibilityIdTraversal(viewId);
- if (view != null) {
- return view;
- }
- }
- }
- return null;
- }
-
- /** @hide */
- @Override
- public final @Nullable IBinder autofillClientGetActivityToken() {
- return getActivityToken();
- }
-
- /** @hide */
- @Override
- public final boolean autofillClientIsVisibleForAutofill() {
- return !mStopped;
- }
-
- /** @hide */
- @Override
- public final boolean autofillClientIsCompatibilityModeEnabled() {
- return isAutofillCompatibilityEnabled();
- }
-
- /** @hide */
- @Override
- public final boolean isDisablingEnterExitEventForAutofill() {
- return mAutoFillIgnoreFirstResumePause || !mResumed;
+ /**
+ * @hide
+ */
+ public final boolean isStopped() {
+ return mStopped;
}
/**
diff --git a/core/java/android/app/ActivityClient.java b/core/java/android/app/ActivityClient.java
index bd43868..2efdf51 100644
--- a/core/java/android/app/ActivityClient.java
+++ b/core/java/android/app/ActivityClient.java
@@ -16,6 +16,7 @@
package android.app;
+import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Intent;
import android.content.res.Configuration;
@@ -205,6 +206,18 @@
}
}
+ /**
+ * Returns the activity token below in the same task if it belongs to the same process.
+ */
+ @Nullable
+ public IBinder getActivityTokenBelow(IBinder activityToken) {
+ try {
+ return getActivityClientController().getActivityTokenBelow(activityToken);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
ComponentName getCallingActivity(IBinder token) {
try {
return getActivityClientController().getCallingActivity(token);
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index d5f51ad..7145c0f 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -377,7 +377,7 @@
IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras,
String requiredPermission, Bundle bOptions, boolean serialized, boolean sticky,
@UserIdInt int userId, boolean allowBackgroundActivityStarts,
- @Nullable IBinder backgroundActivityStartsToken);
+ @Nullable IBinder backgroundActivityStartsToken, @Nullable int[] broadcastAllowList);
public abstract ComponentName startServiceInPackage(int uid, Intent service,
String resolvedType, boolean fgRequired, String callingPackage,
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index f6bcfd6..e3abe4d 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3552,6 +3552,13 @@
+ ", comp=" + r.intent.getComponent().toShortString()
+ ", dir=" + r.packageInfo.getAppDir());
+ // updatePendingActivityConfiguration() reads from mActivities to update
+ // ActivityClientRecord which runs in a different thread. Protect modifications to
+ // mActivities to avoid race.
+ synchronized (mResourcesManager) {
+ mActivities.put(r.token, r);
+ }
+
if (activity != null) {
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config =
@@ -3613,13 +3620,6 @@
}
r.setState(ON_CREATE);
- // updatePendingActivityConfiguration() reads from mActivities to update
- // ActivityClientRecord which runs in a different thread. Protect modifications to
- // mActivities to avoid race.
- synchronized (mResourcesManager) {
- mActivities.put(r.token, r);
- }
-
} catch (SuperNotCalledException e) {
throw e;
diff --git a/core/java/android/app/AppOpsManagerInternal.java b/core/java/android/app/AppOpsManagerInternal.java
index 363b5a7..4d6e4ae 100644
--- a/core/java/android/app/AppOpsManagerInternal.java
+++ b/core/java/android/app/AppOpsManagerInternal.java
@@ -21,6 +21,7 @@
import android.app.AppOpsManager.AttributionFlags;
import android.content.AttributionSource;
import android.os.IBinder;
+import android.os.UserHandle;
import android.util.SparseArray;
import android.util.SparseIntArray;
@@ -215,4 +216,11 @@
* Sets a global restriction on an op code.
*/
public abstract void setGlobalRestriction(int code, boolean restricted, IBinder token);
+
+ /**
+ * Gets the number of tokens restricting the given appop for a user, package, and
+ * attributionTag.
+ */
+ public abstract int getOpRestrictionCount(int code, UserHandle user, String pkg,
+ String attributionTag);
}
diff --git a/core/java/android/app/Application.java b/core/java/android/app/Application.java
index 618eda8..f58ca6a 100644
--- a/core/java/android/app/Application.java
+++ b/core/java/android/app/Application.java
@@ -613,7 +613,7 @@
if (android.view.autofill.Helper.sVerbose) {
Log.v(TAG, "getAutofillClient(): found activity for " + this + ": " + activity);
}
- return activity;
+ return activity.getAutofillClient();
}
}
if (android.view.autofill.Helper.sVerbose) {
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 2d172c5..b81a8d3 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1014,13 +1014,17 @@
}
}
@Override
+ protected boolean bypass(Integer uid) {
+ return uid < 0;
+ }
+ @Override
public String queryToString(Integer uid) {
return String.format("uid=%d", uid.intValue());
}
};
@Override
- public String[] getPackagesForUid(int uid) {
+ public String[] getPackagesForUid(@UserIdInt int uid) {
return mGetPackagesForUidCache.query(uid).value();
}
@@ -1035,7 +1039,7 @@
}
@Override
- public String getNameForUid(int uid) {
+ public String getNameForUid(@UserIdInt int uid) {
try {
return mPM.getNameForUid(uid);
} catch (RemoteException e) {
@@ -1057,7 +1061,7 @@
throws NameNotFoundException {
try {
int uid = mPM.getUidForSharedUser(sharedUserName);
- if(uid != -1) {
+ if (uid != Process.INVALID_UID) {
return uid;
}
} catch (RemoteException e) {
diff --git a/core/java/android/app/IActivityClientController.aidl b/core/java/android/app/IActivityClientController.aidl
index c664969..aba6eb9 100644
--- a/core/java/android/app/IActivityClientController.aidl
+++ b/core/java/android/app/IActivityClientController.aidl
@@ -70,6 +70,7 @@
boolean willActivityBeVisible(in IBinder token);
int getDisplayId(in IBinder activityToken);
int getTaskForActivity(in IBinder token, in boolean onlyRoot);
+ IBinder getActivityTokenBelow(IBinder token);
ComponentName getCallingActivity(in IBinder token);
String getCallingPackage(in IBinder token);
int getLaunchedFromUid(in IBinder token);
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 871d48b..32ea41b 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -158,7 +158,6 @@
import android.os.IBinder;
import android.os.IDumpstate;
import android.os.IHardwarePropertiesManager;
-import android.os.IHintManager;
import android.os.IPowerManager;
import android.os.IRecoverySystem;
import android.os.ISystemUpdateManager;
@@ -600,10 +599,7 @@
@Override
public PerformanceHintManager createService(ContextImpl ctx)
throws ServiceNotFoundException {
- IBinder hintBinder = ServiceManager.getServiceOrThrow(
- Context.PERFORMANCE_HINT_SERVICE);
- IHintManager hintService = IHintManager.Stub.asInterface(hintBinder);
- return new PerformanceHintManager(hintService);
+ return PerformanceHintManager.create();
}});
registerService(Context.RECOVERY_SERVICE, RecoverySystem.class,
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index dfdeb2d..5eb58bb 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -333,8 +333,12 @@
* {@link android.Manifest.permission#DISPATCH_PROVISIONING_MESSAGE} to be launched.
* Only one {@link ComponentName} in the entire system should be enabled, and the rest of the
* components are not started by this intent.
+ *
+ * @deprecated Starting from Android T, the system no longer launches an intent with this action
+ * when user provisioning completes.
* @hide
*/
+ @Deprecated
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
@SystemApi
public static final String ACTION_STATE_USER_SETUP_COMPLETE =
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 2724166..2ed26a9f 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -3526,22 +3526,22 @@
}
/**
- * Determines whether a String Bluetooth address, such as "00:43:A8:23:10:F0"
+ * Determines whether a String Bluetooth address, such as "F0:43:A8:23:10:00"
* is a RANDOM STATIC address.
*
- * RANDOM STATIC: (addr & 0b11) == 0b11
- * RANDOM RESOLVABLE: (addr & 0b11) == 0b10
- * RANDOM non-RESOLVABLE: (addr & 0b11) == 0b00
+ * RANDOM STATIC: (addr & 0xC0) == 0xC0
+ * RANDOM RESOLVABLE: (addr & 0xC0) == 0x40
+ * RANDOM non-RESOLVABLE: (addr & 0xC0) == 0x00
*
* @param address Bluetooth address as string
- * @return true if the 2 Least Significant Bits of the address equals 0b11.
+ * @return true if the 2 Most Significant Bits of the address equals 0xC0.
*
* @hide
*/
public static boolean isAddressRandomStatic(@NonNull String address) {
requireNonNull(address);
return checkBluetoothAddress(address)
- && (Integer.parseInt(address.split(":")[5], 16) & 0b11) == 0b11;
+ && (Integer.parseInt(address.split(":")[0], 16) & 0xC0) == 0xC0;
}
/** {@hide} */
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index c2f3ef0..7101d1a 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -9085,6 +9085,7 @@
private static final class ApplicationInfoQuery {
final String packageName;
final int flags;
+ @UserIdInt
final int userId;
ApplicationInfoQuery(@Nullable String packageName, int flags, int userId) {
@@ -9146,6 +9147,10 @@
query.packageName, query.flags, query.userId);
}
@Override
+ protected boolean bypass(ApplicationInfoQuery query) {
+ return query.userId < 0;
+ }
+ @Override
protected ApplicationInfo maybeCheckConsistency(
ApplicationInfoQuery query, ApplicationInfo proposedResult) {
// Implementing this debug check for ApplicationInfo would require a
@@ -9156,7 +9161,7 @@
/** @hide */
public static ApplicationInfo getApplicationInfoAsUserCached(
- String packageName, int flags, int userId) {
+ String packageName, int flags, @UserIdInt int userId) {
return sApplicationInfoCache.query(
new ApplicationInfoQuery(packageName, flags, userId));
}
@@ -9188,6 +9193,7 @@
private static final class PackageInfoQuery {
final String packageName;
final int flags;
+ @UserIdInt
final int userId;
PackageInfoQuery(@Nullable String packageName, int flags, int userId) {
@@ -9248,6 +9254,10 @@
query.packageName, query.flags, query.userId);
}
@Override
+ protected boolean bypass(PackageInfoQuery query) {
+ return query.userId < 0;
+ }
+ @Override
protected PackageInfo maybeCheckConsistency(
PackageInfoQuery query, PackageInfo proposedResult) {
// Implementing this debug check for PackageInfo would require a
@@ -9258,7 +9268,7 @@
/** @hide */
public static PackageInfo getPackageInfoAsUserCached(
- String packageName, int flags, int userId) {
+ String packageName, int flags, @UserIdInt int userId) {
return sPackageInfoCache.query(new PackageInfoQuery(packageName, flags, userId));
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 697b72a..bed0383 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -55,7 +55,8 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.overlay.OverlayPaths;
-import android.content.pm.split.SplitAssetLoader;
+import android.content.pm.parsing.result.ParseResult;
+import android.content.pm.parsing.result.ParseTypeImpl;
import android.content.res.ApkAssets;
import android.content.res.AssetManager;
import android.content.res.Configuration;
@@ -1403,20 +1404,26 @@
// must use v2 signing scheme
minSignatureScheme = SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2;
}
- final android.content.pm.SigningDetails verified;
+ final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
+ final ParseResult<android.content.pm.SigningDetails> result;
if (skipVerify) {
// systemDir APKs are already trusted, save time by not verifying; since the signature
// is not verified and some system apps can have their V2+ signatures stripped allow
// pulling the certs from the jar signature.
- verified = ApkSignatureVerifier.unsafeGetCertsWithoutVerification(
- apkPath, SigningDetails.SignatureSchemeVersion.JAR);
+ result = ApkSignatureVerifier.unsafeGetCertsWithoutVerification(
+ input, apkPath, SigningDetails.SignatureSchemeVersion.JAR);
} else {
- verified = ApkSignatureVerifier.verify(apkPath, minSignatureScheme);
+ result = ApkSignatureVerifier.verify(input, apkPath, minSignatureScheme);
+ }
+ if (result.isError()) {
+ throw new PackageParserException(result.getErrorCode(), result.getErrorMessage(),
+ result.getException());
}
// Verify that entries are signed consistently with the first pkg
// we encountered. Note that for splits, certificates may have
// already been populated during an earlier parse of a base APK.
+ final android.content.pm.SigningDetails verified = result.getResult();
if (pkg.mSigningDetails == SigningDetails.UNKNOWN) {
pkg.mSigningDetails = new SigningDetails(verified.getSignatures(),
verified.getSignatureSchemeVersion(),
@@ -8694,6 +8701,22 @@
// clean and move all the legacy code to one place.
/**
+ * Simple interface for loading base Assets and Splits. Used by PackageParser when parsing
+ * split APKs.
+ *
+ * @hide
+ * @deprecated Do not use. New changes should use
+ * {@link android.content.pm.split.SplitAssetLoader} instead.
+ */
+ @Deprecated
+ private interface SplitAssetLoader extends AutoCloseable {
+ AssetManager getBaseAssetManager() throws PackageParserException;
+ AssetManager getSplitAssetManager(int splitIdx) throws PackageParserException;
+
+ ApkAssets getBaseApkAssets();
+ }
+
+ /**
* A helper class that implements the dependency tree traversal for splits. Callbacks
* are implemented by subclasses to notify whether a split has already been constructed
* and is cached, and to actually create the split requested.
diff --git a/core/java/android/content/pm/dex/DexMetadataHelper.java b/core/java/android/content/pm/dex/DexMetadataHelper.java
index 8f9a0d7..e75aa06 100644
--- a/core/java/android/content/pm/dex/DexMetadataHelper.java
+++ b/core/java/android/content/pm/dex/DexMetadataHelper.java
@@ -19,9 +19,10 @@
import static android.content.pm.PackageManager.INSTALL_FAILED_BAD_DEX_METADATA;
import static android.content.pm.parsing.ApkLiteParseUtils.APK_FILE_EXTENSION;
-import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.parsing.ApkLiteParseUtils;
import android.content.pm.parsing.PackageLite;
+import android.content.pm.parsing.result.ParseInput;
+import android.content.pm.parsing.result.ParseResult;
import android.os.SystemProperties;
import android.util.ArrayMap;
import android.util.JsonReader;
@@ -176,18 +177,16 @@
* Validate that the given file is a dex metadata archive.
* This is just a validation that the file is a zip archive that contains a manifest.json
* with the package name and version code.
- *
- * @throws PackageParserException if the file is not a .dm file.
*/
- public static void validateDexMetadataFile(String dmaPath, String packageName, long versionCode)
- throws PackageParserException {
- validateDexMetadataFile(dmaPath, packageName, versionCode,
+ public static ParseResult validateDexMetadataFile(ParseInput input, String dmaPath,
+ String packageName, long versionCode) {
+ return validateDexMetadataFile(input, dmaPath, packageName, versionCode,
SystemProperties.getBoolean(PROPERTY_DM_JSON_MANIFEST_REQUIRED, false));
}
@VisibleForTesting
- public static void validateDexMetadataFile(String dmaPath, String packageName, long versionCode,
- boolean requireManifest) throws PackageParserException {
+ public static ParseResult validateDexMetadataFile(ParseInput input, String dmaPath,
+ String packageName, long versionCode, boolean requireManifest) {
StrictJarFile jarFile = null;
if (DEBUG) {
@@ -197,11 +196,10 @@
try {
jarFile = new StrictJarFile(dmaPath, false, false);
- validateDexMetadataManifest(dmaPath, jarFile, packageName, versionCode,
+ return validateDexMetadataManifest(input, dmaPath, jarFile, packageName, versionCode,
requireManifest);
} catch (IOException e) {
- throw new PackageParserException(INSTALL_FAILED_BAD_DEX_METADATA,
- "Error opening " + dmaPath, e);
+ return input.error(INSTALL_FAILED_BAD_DEX_METADATA, "Error opening " + dmaPath, e);
} finally {
if (jarFile != null) {
try {
@@ -213,21 +211,21 @@
}
/** Ensure that packageName and versionCode match the manifest.json in the .dm file */
- private static void validateDexMetadataManifest(String dmaPath, StrictJarFile jarFile,
- String packageName, long versionCode, boolean requireManifest)
- throws IOException, PackageParserException {
+ private static ParseResult validateDexMetadataManifest(ParseInput input, String dmaPath,
+ StrictJarFile jarFile, String packageName, long versionCode, boolean requireManifest)
+ throws IOException {
if (!requireManifest) {
if (DEBUG) {
Log.v(TAG, "validateDexMetadataManifest: " + dmaPath
+ " manifest.json check skipped");
}
- return;
+ return input.success(null);
}
ZipEntry zipEntry = jarFile.findEntry("manifest.json");
if (zipEntry == null) {
- throw new PackageParserException(INSTALL_FAILED_BAD_DEX_METADATA,
- "Missing manifest.json in " + dmaPath);
+ return input.error(INSTALL_FAILED_BAD_DEX_METADATA,
+ "Missing manifest.json in " + dmaPath);
}
InputStream inputStream = jarFile.getInputStream(zipEntry);
@@ -235,7 +233,7 @@
try {
reader = new JsonReader(new InputStreamReader(inputStream, "UTF-8"));
} catch (UnsupportedEncodingException e) {
- throw new PackageParserException(INSTALL_FAILED_BAD_DEX_METADATA,
+ return input.error(INSTALL_FAILED_BAD_DEX_METADATA,
"Error opening manifest.json in " + dmaPath, e);
}
String jsonPackageName = null;
@@ -255,19 +253,19 @@
reader.endObject();
if (jsonPackageName == null || jsonVersionCode == -1) {
- throw new PackageParserException(INSTALL_FAILED_BAD_DEX_METADATA,
+ return input.error(INSTALL_FAILED_BAD_DEX_METADATA,
"manifest.json in " + dmaPath
+ " is missing 'packageName' and/or 'versionCode'");
}
if (!jsonPackageName.equals(packageName)) {
- throw new PackageParserException(INSTALL_FAILED_BAD_DEX_METADATA,
+ return input.error(INSTALL_FAILED_BAD_DEX_METADATA,
"manifest.json in " + dmaPath + " has invalid packageName: " + jsonPackageName
+ ", expected: " + packageName);
}
if (versionCode != jsonVersionCode) {
- throw new PackageParserException(INSTALL_FAILED_BAD_DEX_METADATA,
+ return input.error(INSTALL_FAILED_BAD_DEX_METADATA,
"manifest.json in " + dmaPath + " has invalid versionCode: " + jsonVersionCode
+ ", expected: " + versionCode);
}
@@ -276,6 +274,7 @@
Log.v(TAG, "validateDexMetadataManifest: " + dmaPath + ", " + packageName +
", " + versionCode + ": successful");
}
+ return input.success(null);
}
/**
diff --git a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
index 12ed0e0..9fee7bb 100644
--- a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
+++ b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
@@ -273,16 +273,16 @@
pi.requestedPermissionsFlags = new int[size];
for (int i = 0; i < size; i++) {
final ParsedUsesPermission usesPermission = usesPermissions.get(i);
- pi.requestedPermissions[i] = usesPermission.name;
+ pi.requestedPermissions[i] = usesPermission.getName();
// The notion of required permissions is deprecated but for compatibility.
pi.requestedPermissionsFlags[i] |=
PackageInfo.REQUESTED_PERMISSION_REQUIRED;
if (grantedPermissions != null
- && grantedPermissions.contains(usesPermission.name)) {
+ && grantedPermissions.contains(usesPermission.getName())) {
pi.requestedPermissionsFlags[i] |=
PackageInfo.REQUESTED_PERMISSION_GRANTED;
}
- if ((usesPermission.usesPermissionFlags
+ if ((usesPermission.getUsesPermissionFlags()
& ParsedUsesPermission.FLAG_NEVER_FOR_LOCATION) != 0) {
pi.requestedPermissionsFlags[i] |=
PackageInfo.REQUESTED_PERMISSION_NEVER_FOR_LOCATION;
@@ -750,7 +750,7 @@
@Nullable
public static Attribution generateAttribution(ParsedAttribution pa) {
if (pa == null) return null;
- return new Attribution(pa.tag, pa.label);
+ return new Attribution(pa.getTag(), pa.getLabel());
}
private static boolean checkUseInstalledOrHidden(int flags, @NonNull PackageUserState state,
diff --git a/core/java/android/content/pm/parsing/ParsingPackageImpl.java b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
index 34a57f3..0db6546 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageImpl.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
@@ -716,7 +716,8 @@
// Continue populating legacy data structures to avoid performance
// issues until all that code can be migrated
- this.requestedPermissions = CollectionUtils.add(this.requestedPermissions, permission.name);
+ this.requestedPermissions = CollectionUtils.add(this.requestedPermissions,
+ permission.getName());
return this;
}
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index 77a5fbf..fc4aa5e 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -18,8 +18,10 @@
import static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_RESOURCES_ARSC_COMPRESSED;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
@@ -46,7 +48,6 @@
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.Property;
import android.content.pm.PackageParser;
-import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.Signature;
import android.content.pm.SigningDetails;
import android.content.pm.parsing.component.ComponentParseUtils;
@@ -274,31 +275,25 @@
manifestArray);
}
});
- try {
- result = parser.parsePackage(input, file, parseFlags);
- if (result.isError()) {
- return result;
- }
- } catch (PackageParser.PackageParserException e) {
- return input.error(PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
- "Error parsing package", e);
+ result = parser.parsePackage(input, file, parseFlags);
+ if (result.isError()) {
+ return input.error(result);
}
- try {
- ParsingPackage pkg = result.getResult();
- if (collectCertificates) {
- pkg.setSigningDetails(
- ParsingPackageUtils.getSigningDetails(pkg, false /* skipVerify */));
+ final ParsingPackage pkg = result.getResult();
+ if (collectCertificates) {
+ final ParseResult<SigningDetails> ret =
+ ParsingPackageUtils.getSigningDetails(input, pkg, false /*skipVerify*/);
+ if (ret.isError()) {
+ return input.error(ret);
}
-
- // Need to call this to finish the parsing stage
- pkg.hideAsParsed();
-
- return input.success(pkg);
- } catch (PackageParser.PackageParserException e) {
- return input.error(PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
- "Error collecting package certificates", e);
+ pkg.setSigningDetails(ret.getResult());
}
+
+ // Need to call this to finish the parsing stage
+ pkg.hideAsParsed();
+
+ return input.success(pkg);
}
private boolean mOnlyCoreApps;
@@ -328,8 +323,8 @@
* requiring identical package name and version codes, a single base APK,
* and unique split names.
* <p>
- * Note that this <em>does not</em> perform signature verification; that
- * must be done separately in {@link #getSigningDetails(ParsingPackageRead, boolean)}.
+ * Note that this <em>does not</em> perform signature verification; that must
+ * be done separately in {@link #getSigningDetails(ParseInput, ParsingPackageRead, boolean)}.
*
* If {@code useCaches} is true, the package parser might return a cached
* result from a previous parse of the same {@code packageFile} with the same
@@ -338,9 +333,7 @@
*
* @see PackageParser#parsePackageLite(File, int)
*/
- public ParseResult<ParsingPackage> parsePackage(ParseInput input, File packageFile,
- int flags)
- throws PackageParserException {
+ public ParseResult<ParsingPackage> parsePackage(ParseInput input, File packageFile, int flags) {
if (packageFile.isDirectory()) {
return parseClusterPackage(input, packageFile, flags);
} else {
@@ -354,8 +347,8 @@
* identical package name and version codes, a single base APK, and unique
* split names.
* <p>
- * Note that this <em>does not</em> perform signature verification; that
- * must be done separately in {@link #getSigningDetails(ParsingPackageRead, boolean)}.
+ * Note that this <em>does not</em> perform signature verification; that must
+ * be done separately in {@link #getSigningDetails(ParseInput, ParsingPackageRead, boolean)}.
*/
private ParseResult<ParsingPackage> parseClusterPackage(ParseInput input, File packageDir,
int flags) {
@@ -405,15 +398,19 @@
for (int i = 0; i < num; i++) {
final AssetManager splitAssets = assetLoader.getSplitAssetManager(i);
- parseSplitApk(input, pkg, i, splitAssets, flags);
+ final ParseResult<ParsingPackage> split =
+ parseSplitApk(input, pkg, i, splitAssets, flags);
+ if (split.isError()) {
+ return input.error(split);
+ }
}
}
pkg.setUse32BitAbi(lite.isUse32bitAbi());
return input.success(pkg);
- } catch (PackageParserException e) {
- return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
- "Failed to load assets: " + lite.getBaseApkPath(), e);
+ } catch (IllegalArgumentException e) {
+ return input.error(e.getCause() instanceof IOException ? INSTALL_FAILED_INVALID_APK
+ : INSTALL_PARSE_FAILED_NOT_APK, e.getMessage(), e);
} finally {
IoUtils.closeQuietly(assetLoader);
}
@@ -422,11 +419,11 @@
/**
* Parse the given APK file, treating it as as a single monolithic package.
* <p>
- * Note that this <em>does not</em> perform signature verification; that
- * must be done separately in {@link #getSigningDetails(ParsingPackageRead, boolean)}.
+ * Note that this <em>does not</em> perform signature verification; that must
+ * be done separately in {@link #getSigningDetails(ParseInput, ParsingPackageRead, boolean)}.
*/
private ParseResult<ParsingPackage> parseMonolithicPackage(ParseInput input, File apkFile,
- int flags) throws PackageParserException {
+ int flags) {
final ParseResult<PackageLite> liteResult =
ApkLiteParseUtils.parseMonolithicPackageLite(input, apkFile, flags);
if (liteResult.isError()) {
@@ -460,8 +457,7 @@
}
private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, File apkFile,
- String codePath, SplitAssetLoader assetLoader, int flags)
- throws PackageParserException {
+ String codePath, SplitAssetLoader assetLoader, int flags) {
final String apkPath = apkFile.getAbsolutePath();
String volumeUuid = null;
@@ -472,7 +468,13 @@
if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath);
- final AssetManager assets = assetLoader.getBaseAssetManager();
+ final AssetManager assets;
+ try {
+ assets = assetLoader.getBaseAssetManager();
+ } catch (IllegalArgumentException e) {
+ return input.error(e.getCause() instanceof IOException ? INSTALL_FAILED_INVALID_APK
+ : INSTALL_PARSE_FAILED_NOT_APK, e.getMessage(), e);
+ }
final int cookie = assets.findCookieForPath(apkPath);
if (cookie == 0) {
return input.error(INSTALL_PARSE_FAILED_BAD_MANIFEST,
@@ -529,7 +531,12 @@
pkg.setVolumeUuid(volumeUuid);
if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) {
- pkg.setSigningDetails(getSigningDetails(pkg, false));
+ final ParseResult<SigningDetails> ret =
+ getSigningDetails(input, pkg, false /*skipVerify*/);
+ if (ret.isError()) {
+ return input.error(ret);
+ }
+ pkg.setSigningDetails(ret.getResult());
} else {
pkg.setSigningDetails(SigningDetails.UNKNOWN);
}
@@ -635,11 +642,13 @@
*/
private ParseResult<ParsingPackage> parseSplitApk(ParseInput input, ParsingPackage pkg,
Resources res, XmlResourceParser parser, int flags, int splitIndex)
- throws XmlPullParserException, IOException, PackageParserException {
- AttributeSet attrs = parser;
-
+ throws XmlPullParserException, IOException {
// We parsed manifest tag earlier; just skip past it
- PackageParser.parsePackageSplitNames(parser, attrs);
+ final ParseResult<Pair<String, String>> packageSplitResult =
+ ApkLiteParseUtils.parsePackageSplitNames(input, parser);
+ if (packageSplitResult.isError()) {
+ return input.error(packageSplitResult);
+ }
int type;
@@ -1298,8 +1307,8 @@
final int size = usesPermissions.size();
for (int i = 0; i < size; i++) {
final ParsedUsesPermission usesPermission = usesPermissions.get(i);
- if (Objects.equals(usesPermission.name, name)) {
- if (usesPermission.usesPermissionFlags != usesPermissionFlags) {
+ if (Objects.equals(usesPermission.getName(), name)) {
+ if (usesPermission.getUsesPermissionFlags() != usesPermissionFlags) {
return input.error("Conflicting uses-permissions flags: "
+ name + " in package: " + pkg.getPackageName() + " at: "
+ parser.getPositionDescription());
@@ -2798,8 +2807,8 @@
if (pkg.getTargetSdkVersion() >= info.sdkVersion) {
break;
}
- if (!pkg.getRequestedPermissions().contains(info.name)) {
- pkg.addImplicitPermission(info.name);
+ if (!pkg.getRequestedPermissions().contains(info.getName())) {
+ pkg.addImplicitPermission(info.getName());
}
}
}
@@ -2961,12 +2970,10 @@
* construct a dummy ParseInput.
*/
@CheckResult
- public static SigningDetails getSigningDetails(ParsingPackageRead pkg, boolean skipVerify)
- throws PackageParserException {
+ public static ParseResult<SigningDetails> getSigningDetails(ParseInput input,
+ ParsingPackageRead pkg, boolean skipVerify) {
SigningDetails signingDetails = SigningDetails.UNKNOWN;
- ParseInput input = ParseTypeImpl.forDefaultParsing().reset();
-
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
try {
ParseResult<SigningDetails> result = getSigningDetails(
@@ -2978,8 +2985,7 @@
pkg.getTargetSdkVersion()
);
if (result.isError()) {
- throw new PackageParser.PackageParserException(result.getErrorCode(),
- result.getErrorMessage(), result.getException());
+ return input.error(result);
}
signingDetails = result.getResult();
@@ -2996,15 +3002,11 @@
pkg.getTargetSdkVersion()
);
if (result.isError()) {
- throw new PackageParser.PackageParserException(result.getErrorCode(),
- result.getErrorMessage(), result.getException());
+ return input.error(result);
}
-
-
- signingDetails = result.getResult();
}
}
- return signingDetails;
+ return result;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
@@ -3020,30 +3022,29 @@
// must use v2 signing scheme
minSignatureScheme = SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2;
}
- SigningDetails verified;
- try {
- if (skipVerify) {
- // systemDir APKs are already trusted, save time by not verifying; since the
- // signature is not verified and some system apps can have their V2+ signatures
- // stripped allow pulling the certs from the jar signature.
- verified = ApkSignatureVerifier.unsafeGetCertsWithoutVerification(
- baseCodePath, SigningDetails.SignatureSchemeVersion.JAR);
- } else {
- verified = ApkSignatureVerifier.verify(baseCodePath, minSignatureScheme);
- }
- } catch (PackageParserException e) {
- return input.error(PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES,
- "Failed collecting certificates for " + baseCodePath, e);
+ final ParseResult<SigningDetails> verified;
+ if (skipVerify) {
+ // systemDir APKs are already trusted, save time by not verifying; since the
+ // signature is not verified and some system apps can have their V2+ signatures
+ // stripped allow pulling the certs from the jar signature.
+ verified = ApkSignatureVerifier.unsafeGetCertsWithoutVerification(input, baseCodePath,
+ SigningDetails.SignatureSchemeVersion.JAR);
+ } else {
+ verified = ApkSignatureVerifier.verify(input, baseCodePath, minSignatureScheme);
+ }
+
+ if (verified.isError()) {
+ return input.error(verified);
}
// Verify that entries are signed consistently with the first pkg
// we encountered. Note that for splits, certificates may have
// already been populated during an earlier parse of a base APK.
if (existingSigningDetails == SigningDetails.UNKNOWN) {
- return input.success(verified);
+ return verified;
} else {
if (!Signature.areExactMatch(existingSigningDetails.getSignatures(),
- verified.getSignatures())) {
+ verified.getResult().getSignatures())) {
return input.error(INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
baseCodePath + " has mismatched certificates");
}
diff --git a/core/java/android/content/pm/parsing/component/ComponentParseUtils.java b/core/java/android/content/pm/parsing/component/ComponentParseUtils.java
index 0403a25..e5d030c 100644
--- a/core/java/android/content/pm/parsing/component/ComponentParseUtils.java
+++ b/core/java/android/content/pm/parsing/component/ComponentParseUtils.java
@@ -152,7 +152,7 @@
@Nullable
public static CharSequence getNonLocalizedLabel(
ParsedComponent component) {
- return component.nonLocalizedLabel;
+ return component.getNonLocalizedLabel();
}
/**
@@ -161,7 +161,7 @@
* This is a method of the utility class to discourage use.
*/
public static int getIcon(ParsedComponent component) {
- return component.icon;
+ return component.getIcon();
}
public static boolean isMatch(PackageUserState state, boolean isSystem,
diff --git a/core/java/android/content/pm/parsing/component/ParsedActivity.java b/core/java/android/content/pm/parsing/component/ParsedActivity.java
index 6f478ac..73ee132 100644
--- a/core/java/android/content/pm/parsing/component/ParsedActivity.java
+++ b/core/java/android/content/pm/parsing/component/ParsedActivity.java
@@ -38,8 +38,8 @@
/** @hide **/
public class ParsedActivity extends ParsedMainComponent {
- int theme;
- int uiOptions;
+ private int theme;
+ private int uiOptions;
@Nullable
@DataClass.ParcelWith(ForInternedString.class)
@@ -49,22 +49,22 @@
@DataClass.ParcelWith(ForInternedString.class)
private String parentActivityName;
@Nullable
- String taskAffinity;
- int privateFlags;
+ private String taskAffinity;
+ private int privateFlags;
@Nullable
@DataClass.ParcelWith(ForInternedString.class)
private String permission;
- int launchMode;
- int documentLaunchMode;
- int maxRecents;
- int configChanges;
- int softInputMode;
- int persistableMode;
- int lockTaskLaunchMode;
+ private int launchMode;
+ private int documentLaunchMode;
+ private int maxRecents;
+ private int configChanges;
+ private int softInputMode;
+ private int persistableMode;
+ private int lockTaskLaunchMode;
- int screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
- int resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
+ private int screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+ private int resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
@Nullable
private Float maxAspectRatio;
@@ -75,12 +75,12 @@
private boolean supportsSizeChanges;
@Nullable
- String requestedVrComponent;
- int rotationAnimation = -1;
- int colorMode;
+ private String requestedVrComponent;
+ private int rotationAnimation = -1;
+ private int colorMode;
@Nullable
- ActivityInfo.WindowLayout windowLayout;
+ private ActivityInfo.WindowLayout windowLayout;
public ParsedActivity(ParsedActivity other) {
super(other);
@@ -188,6 +188,35 @@
// alias.metaData = target.metaData;
}
+ public boolean isSupportsSizeChanges() {
+ return supportsSizeChanges;
+ }
+
+ public ParsedActivity setColorMode(int colorMode) {
+ this.colorMode = colorMode;
+ return this;
+ }
+
+ public ParsedActivity setConfigChanges(int configChanges) {
+ this.configChanges = configChanges;
+ return this;
+ }
+
+ public ParsedActivity setDocumentLaunchMode(int documentLaunchMode) {
+ this.documentLaunchMode = documentLaunchMode;
+ return this;
+ }
+
+ public ParsedActivity setLaunchMode(int launchMode) {
+ this.launchMode = launchMode;
+ return this;
+ }
+
+ public ParsedActivity setLockTaskLaunchMode(int lockTaskLaunchMode) {
+ this.lockTaskLaunchMode = lockTaskLaunchMode;
+ return this;
+ }
+
public ParsedActivity setMaxAspectRatio(int resizeMode, float maxAspectRatio) {
if (resizeMode == ActivityInfo.RESIZE_MODE_RESIZEABLE
|| resizeMode == ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) {
@@ -204,6 +233,16 @@
return this;
}
+ public ParsedActivity setMaxAspectRatio(Float maxAspectRatio) {
+ this.maxAspectRatio = maxAspectRatio;
+ return this;
+ }
+
+ public ParsedActivity setMaxRecents(int maxRecents) {
+ this.maxRecents = maxRecents;
+ return this;
+ }
+
public ParsedActivity setMinAspectRatio(int resizeMode, float minAspectRatio) {
if (resizeMode == RESIZE_MODE_RESIZEABLE
|| resizeMode == RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) {
@@ -220,13 +259,48 @@
return this;
}
- public ParsedActivity setSupportsSizeChanges(boolean supportsSizeChanges) {
- this.supportsSizeChanges = supportsSizeChanges;
+ public ParsedActivity setMinAspectRatio(Float minAspectRatio) {
+ this.minAspectRatio = minAspectRatio;
return this;
}
- public ParsedActivity setFlags(int flags) {
- this.flags = flags;
+ public ParsedActivity setParentActivityName(String parentActivityName) {
+ this.parentActivityName = parentActivityName;
+ return this;
+ }
+
+ public ParsedActivity setPersistableMode(int persistableMode) {
+ this.persistableMode = persistableMode;
+ return this;
+ }
+
+ public ParsedActivity setPrivateFlags(int privateFlags) {
+ this.privateFlags = privateFlags;
+ return this;
+ }
+
+ public ParsedActivity setRequestedVrComponent(String requestedVrComponent) {
+ this.requestedVrComponent = requestedVrComponent;
+ return this;
+ }
+
+ public ParsedActivity setRotationAnimation(int rotationAnimation) {
+ this.rotationAnimation = rotationAnimation;
+ return this;
+ }
+
+ public ParsedActivity setScreenOrientation(int screenOrientation) {
+ this.screenOrientation = screenOrientation;
+ return this;
+ }
+
+ public ParsedActivity setSoftInputMode(int softInputMode) {
+ this.softInputMode = softInputMode;
+ return this;
+ }
+
+ public ParsedActivity setSupportsSizeChanges(boolean supportsSizeChanges) {
+ this.supportsSizeChanges = supportsSizeChanges;
return this;
}
@@ -240,17 +314,32 @@
return this;
}
- public ParsedActivity setParentActivity(String parentActivity) {
- this.parentActivityName = TextUtils.safeIntern(parentActivity);
- return this;
- }
-
public ParsedActivity setPermission(String permission) {
// Empty string must be converted to null
this.permission = TextUtils.isEmpty(permission) ? null : permission.intern();
return this;
}
+ public ParsedActivity setTaskAffinity(String taskAffinity) {
+ this.taskAffinity = taskAffinity;
+ return this;
+ }
+
+ public ParsedActivity setTheme(int theme) {
+ this.theme = theme;
+ return this;
+ }
+
+ public ParsedActivity setUiOptions(int uiOptions) {
+ this.uiOptions = uiOptions;
+ return this;
+ }
+
+ public ParsedActivity setWindowLayout(ActivityInfo.WindowLayout windowLayout) {
+ this.windowLayout = windowLayout;
+ return this;
+ }
+
public String toString() {
StringBuilder sb = new StringBuilder(128);
sb.append("Activity{");
diff --git a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
index 92a90e9..ac6bcd0 100644
--- a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
@@ -120,58 +120,58 @@
// Multi-lining them to fit within the column restriction makes it hard to tell what
// field is assigned where.
// @formatter:off
- activity.theme = sa.getResourceId(R.styleable.AndroidManifestActivity_theme, 0);
- activity.uiOptions = sa.getInt(R.styleable.AndroidManifestActivity_uiOptions, pkg.getUiOptions());
+ activity.setTheme(sa.getResourceId(R.styleable.AndroidManifestActivity_theme, 0))
+ .setUiOptions(sa.getInt(R.styleable.AndroidManifestActivity_uiOptions, pkg.getUiOptions()));
- activity.flags |= flag(ActivityInfo.FLAG_ALLOW_TASK_REPARENTING, R.styleable.AndroidManifestActivity_allowTaskReparenting, pkg.isAllowTaskReparenting(), sa)
- | flag(ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE, R.styleable.AndroidManifestActivity_alwaysRetainTaskState, sa)
- | flag(ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH, R.styleable.AndroidManifestActivity_clearTaskOnLaunch, sa)
- | flag(ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS, R.styleable.AndroidManifestActivity_excludeFromRecents, sa)
- | flag(ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS, R.styleable.AndroidManifestActivity_finishOnCloseSystemDialogs, sa)
- | flag(ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH, R.styleable.AndroidManifestActivity_finishOnTaskLaunch, sa)
- | flag(ActivityInfo.FLAG_IMMERSIVE, R.styleable.AndroidManifestActivity_immersive, sa)
- | flag(ActivityInfo.FLAG_MULTIPROCESS, R.styleable.AndroidManifestActivity_multiprocess, sa)
- | flag(ActivityInfo.FLAG_NO_HISTORY, R.styleable.AndroidManifestActivity_noHistory, sa)
- | flag(ActivityInfo.FLAG_SHOW_FOR_ALL_USERS, R.styleable.AndroidManifestActivity_showForAllUsers, sa)
- | flag(ActivityInfo.FLAG_SHOW_FOR_ALL_USERS, R.styleable.AndroidManifestActivity_showOnLockScreen, sa)
- | flag(ActivityInfo.FLAG_STATE_NOT_NEEDED, R.styleable.AndroidManifestActivity_stateNotNeeded, sa)
- | flag(ActivityInfo.FLAG_SYSTEM_USER_ONLY, R.styleable.AndroidManifestActivity_systemUserOnly, sa);
+ activity.setFlags(activity.getFlags() | (flag(ActivityInfo.FLAG_ALLOW_TASK_REPARENTING, R.styleable.AndroidManifestActivity_allowTaskReparenting, pkg.isAllowTaskReparenting(), sa)
+ | flag(ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE, R.styleable.AndroidManifestActivity_alwaysRetainTaskState, sa)
+ | flag(ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH, R.styleable.AndroidManifestActivity_clearTaskOnLaunch, sa)
+ | flag(ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS, R.styleable.AndroidManifestActivity_excludeFromRecents, sa)
+ | flag(ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS, R.styleable.AndroidManifestActivity_finishOnCloseSystemDialogs, sa)
+ | flag(ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH, R.styleable.AndroidManifestActivity_finishOnTaskLaunch, sa)
+ | flag(ActivityInfo.FLAG_IMMERSIVE, R.styleable.AndroidManifestActivity_immersive, sa)
+ | flag(ActivityInfo.FLAG_MULTIPROCESS, R.styleable.AndroidManifestActivity_multiprocess, sa)
+ | flag(ActivityInfo.FLAG_NO_HISTORY, R.styleable.AndroidManifestActivity_noHistory, sa)
+ | flag(ActivityInfo.FLAG_SHOW_FOR_ALL_USERS, R.styleable.AndroidManifestActivity_showForAllUsers, sa)
+ | flag(ActivityInfo.FLAG_SHOW_FOR_ALL_USERS, R.styleable.AndroidManifestActivity_showOnLockScreen, sa)
+ | flag(ActivityInfo.FLAG_STATE_NOT_NEEDED, R.styleable.AndroidManifestActivity_stateNotNeeded, sa)
+ | flag(ActivityInfo.FLAG_SYSTEM_USER_ONLY, R.styleable.AndroidManifestActivity_systemUserOnly, sa)));
if (!receiver) {
- activity.flags |= flag(ActivityInfo.FLAG_HARDWARE_ACCELERATED, R.styleable.AndroidManifestActivity_hardwareAccelerated, pkg.isBaseHardwareAccelerated(), sa)
- | flag(ActivityInfo.FLAG_ALLOW_EMBEDDED, R.styleable.AndroidManifestActivity_allowEmbedded, sa)
- | flag(ActivityInfo.FLAG_ALWAYS_FOCUSABLE, R.styleable.AndroidManifestActivity_alwaysFocusable, sa)
- | flag(ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS, R.styleable.AndroidManifestActivity_autoRemoveFromRecents, sa)
- | flag(ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY, R.styleable.AndroidManifestActivity_relinquishTaskIdentity, sa)
- | flag(ActivityInfo.FLAG_RESUME_WHILE_PAUSING, R.styleable.AndroidManifestActivity_resumeWhilePausing, sa)
- | flag(ActivityInfo.FLAG_SHOW_WHEN_LOCKED, R.styleable.AndroidManifestActivity_showWhenLocked, sa)
- | flag(ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE, R.styleable.AndroidManifestActivity_supportsPictureInPicture, sa)
- | flag(ActivityInfo.FLAG_TURN_SCREEN_ON, R.styleable.AndroidManifestActivity_turnScreenOn, sa)
- | flag(ActivityInfo.FLAG_PREFER_MINIMAL_POST_PROCESSING, R.styleable.AndroidManifestActivity_preferMinimalPostProcessing, sa);
+ activity.setFlags(activity.getFlags() | (flag(ActivityInfo.FLAG_HARDWARE_ACCELERATED, R.styleable.AndroidManifestActivity_hardwareAccelerated, pkg.isBaseHardwareAccelerated(), sa)
+ | flag(ActivityInfo.FLAG_ALLOW_EMBEDDED, R.styleable.AndroidManifestActivity_allowEmbedded, sa)
+ | flag(ActivityInfo.FLAG_ALWAYS_FOCUSABLE, R.styleable.AndroidManifestActivity_alwaysFocusable, sa)
+ | flag(ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS, R.styleable.AndroidManifestActivity_autoRemoveFromRecents, sa)
+ | flag(ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY, R.styleable.AndroidManifestActivity_relinquishTaskIdentity, sa)
+ | flag(ActivityInfo.FLAG_RESUME_WHILE_PAUSING, R.styleable.AndroidManifestActivity_resumeWhilePausing, sa)
+ | flag(ActivityInfo.FLAG_SHOW_WHEN_LOCKED, R.styleable.AndroidManifestActivity_showWhenLocked, sa)
+ | flag(ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE, R.styleable.AndroidManifestActivity_supportsPictureInPicture, sa)
+ | flag(ActivityInfo.FLAG_TURN_SCREEN_ON, R.styleable.AndroidManifestActivity_turnScreenOn, sa)
+ | flag(ActivityInfo.FLAG_PREFER_MINIMAL_POST_PROCESSING, R.styleable.AndroidManifestActivity_preferMinimalPostProcessing, sa)));
- activity.privateFlags |= flag(ActivityInfo.FLAG_INHERIT_SHOW_WHEN_LOCKED,
- R.styleable.AndroidManifestActivity_inheritShowWhenLocked, sa)
- | flag(ActivityInfo.PRIVATE_FLAG_HOME_TRANSITION_SOUND,
- R.styleable.AndroidManifestActivity_playHomeTransitionSound, true, sa);
+ activity.setPrivateFlags(activity.getPrivateFlags() | (flag(ActivityInfo.FLAG_INHERIT_SHOW_WHEN_LOCKED,
+ R.styleable.AndroidManifestActivity_inheritShowWhenLocked, sa)
+ | flag(ActivityInfo.PRIVATE_FLAG_HOME_TRANSITION_SOUND,
+ R.styleable.AndroidManifestActivity_playHomeTransitionSound, true, sa)));
- activity.colorMode = sa.getInt(R.styleable.AndroidManifestActivity_colorMode, ActivityInfo.COLOR_MODE_DEFAULT);
- activity.documentLaunchMode = sa.getInt(R.styleable.AndroidManifestActivity_documentLaunchMode, ActivityInfo.DOCUMENT_LAUNCH_NONE);
- activity.launchMode = sa.getInt(R.styleable.AndroidManifestActivity_launchMode, ActivityInfo.LAUNCH_MULTIPLE);
- activity.lockTaskLaunchMode = sa.getInt(R.styleable.AndroidManifestActivity_lockTaskMode, 0);
- activity.maxRecents = sa.getInt(R.styleable.AndroidManifestActivity_maxRecents, ActivityTaskManager.getDefaultAppRecentsLimitStatic());
- activity.persistableMode = sa.getInteger(R.styleable.AndroidManifestActivity_persistableMode, ActivityInfo.PERSIST_ROOT_ONLY);
- activity.requestedVrComponent = sa.getString(R.styleable.AndroidManifestActivity_enableVrMode);
- activity.rotationAnimation = sa.getInt(R.styleable.AndroidManifestActivity_rotationAnimation, WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED);
- activity.softInputMode = sa.getInt(R.styleable.AndroidManifestActivity_windowSoftInputMode, 0);
-
- activity.configChanges = getActivityConfigChanges(
- sa.getInt(R.styleable.AndroidManifestActivity_configChanges, 0),
- sa.getInt(R.styleable.AndroidManifestActivity_recreateOnConfigChanges, 0));
+ activity.setColorMode(sa.getInt(R.styleable.AndroidManifestActivity_colorMode, ActivityInfo.COLOR_MODE_DEFAULT))
+ .setDocumentLaunchMode(sa.getInt(R.styleable.AndroidManifestActivity_documentLaunchMode, ActivityInfo.DOCUMENT_LAUNCH_NONE))
+ .setLaunchMode(sa.getInt(R.styleable.AndroidManifestActivity_launchMode, ActivityInfo.LAUNCH_MULTIPLE))
+ .setLockTaskLaunchMode(sa.getInt(R.styleable.AndroidManifestActivity_lockTaskMode, 0))
+ .setMaxRecents(sa.getInt(R.styleable.AndroidManifestActivity_maxRecents, ActivityTaskManager.getDefaultAppRecentsLimitStatic()))
+ .setPersistableMode(sa.getInteger(R.styleable.AndroidManifestActivity_persistableMode, ActivityInfo.PERSIST_ROOT_ONLY))
+ .setRequestedVrComponent(sa.getString(R.styleable.AndroidManifestActivity_enableVrMode))
+ .setRotationAnimation(sa.getInt(R.styleable.AndroidManifestActivity_rotationAnimation, WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED))
+ .setSoftInputMode(sa.getInt(R.styleable.AndroidManifestActivity_windowSoftInputMode, 0))
+ .setConfigChanges(getActivityConfigChanges(
+ sa.getInt(R.styleable.AndroidManifestActivity_configChanges, 0),
+ sa.getInt(R.styleable.AndroidManifestActivity_recreateOnConfigChanges, 0))
+ );
int screenOrientation = sa.getInt(R.styleable.AndroidManifestActivity_screenOrientation, SCREEN_ORIENTATION_UNSPECIFIED);
int resizeMode = getActivityResizeMode(pkg, sa, screenOrientation);
- activity.screenOrientation = screenOrientation;
- activity.resizeMode = resizeMode;
+ activity.setScreenOrientation(screenOrientation)
+ .setResizeMode(resizeMode);
if (sa.hasValue(R.styleable.AndroidManifestActivity_maxAspectRatio)
&& sa.getType(R.styleable.AndroidManifestActivity_maxAspectRatio)
@@ -189,9 +189,9 @@
0 /*default*/));
}
} else {
- activity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
- activity.configChanges = 0;
- activity.flags |= flag(ActivityInfo.FLAG_SINGLE_USER, R.styleable.AndroidManifestActivity_singleUser, sa);
+ activity.setLaunchMode(ActivityInfo.LAUNCH_MULTIPLE)
+ .setConfigChanges(0)
+ .setFlags(activity.getFlags()|flag(ActivityInfo.FLAG_SINGLE_USER, R.styleable.AndroidManifestActivity_singleUser, sa));
}
// @formatter:on
@@ -205,11 +205,11 @@
return input.error(affinityNameResult);
}
- activity.taskAffinity = affinityNameResult.getResult();
+ activity.setTaskAffinity(affinityNameResult.getResult());
boolean visibleToEphemeral = sa.getBoolean(R.styleable.AndroidManifestActivity_visibleToInstantApps, false);
if (visibleToEphemeral) {
- activity.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
+ activity.setFlags(activity.getFlags() | ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP);
pkg.setVisibleToInstantApps(true);
}
@@ -320,7 +320,7 @@
Log.e(TAG, "Activity " + activity.getName()
+ " specified invalid parentActivityName " + parentActivityName);
} else {
- activity.setParentActivity(parentClassName);
+ activity.setParentActivityName(parentClassName);
}
}
@@ -336,7 +336,7 @@
final boolean setExported = array.hasValue(exportedAttr);
if (setExported) {
- activity.exported = array.getBoolean(exportedAttr, false);
+ activity.setExported(array.getBoolean(exportedAttr, false));
}
final int depth = parser.getDepth();
@@ -355,7 +355,7 @@
if (intentResult.isSuccess()) {
ParsedIntentInfo intent = intentResult.getResult();
if (intent != null) {
- activity.order = Math.max(intent.getOrder(), activity.order);
+ activity.setOrder(Math.max(intent.getOrder(), activity.getOrder()));
activity.addIntent(intent);
if (LOG_UNSAFE_BROADCASTS && isReceiver
&& pkg.getTargetSdkVersion() >= Build.VERSION_CODES.O) {
@@ -396,7 +396,7 @@
ParseResult<ActivityInfo.WindowLayout> layoutResult =
parseActivityWindowLayout(resources, parser, input);
if (layoutResult.isSuccess()) {
- activity.windowLayout = layoutResult.getResult();
+ activity.setWindowLayout(layoutResult.getResult());
}
result = layoutResult;
} else {
@@ -408,13 +408,13 @@
}
}
- if (!isAlias && activity.launchMode != LAUNCH_SINGLE_INSTANCE_PER_TASK
- && activity.metaData != null && activity.metaData.containsKey(
+ if (!isAlias && activity.getLaunchMode() != LAUNCH_SINGLE_INSTANCE_PER_TASK
+ && activity.getMetaData() != null && activity.getMetaData().containsKey(
ParsingPackageUtils.METADATA_ACTIVITY_LAUNCH_MODE)) {
- final String launchMode = activity.metaData.getString(
+ final String launchMode = activity.getMetaData().getString(
ParsingPackageUtils.METADATA_ACTIVITY_LAUNCH_MODE);
if (launchMode != null && launchMode.equals("singleInstancePerTask")) {
- activity.launchMode = LAUNCH_SINGLE_INSTANCE_PER_TASK;
+ activity.setLaunchMode(LAUNCH_SINGLE_INSTANCE_PER_TASK);
}
}
@@ -423,7 +423,7 @@
if (layoutResult.isError()) {
return input.error(layoutResult);
}
- activity.windowLayout = layoutResult.getResult();
+ activity.setWindowLayout(layoutResult.getResult());
if (!setExported) {
boolean hasIntentFilters = activity.getIntents().size() > 0;
@@ -437,7 +437,7 @@
return input.error(exportedCheckResult);
}
}
- activity.exported = hasIntentFilters;
+ activity.setExported(hasIntentFilters);
}
return input.success(activity);
@@ -459,10 +459,11 @@
ParsedIntentInfo intent = result.getResult();
if (intent != null) {
if (intent.isVisibleToInstantApp()) {
- activity.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
+ activity.setFlags(activity.getFlags() | ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP);
}
if (intent.isImplicitlyVisibleToInstantApp()) {
- activity.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP;
+ activity.setFlags(
+ activity.getFlags() | ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP);
}
}
@@ -553,19 +554,19 @@
private static ParseResult<ActivityInfo.WindowLayout> resolveActivityWindowLayout(
ParsedActivity activity, ParseInput input) {
// There isn't a metadata for us to fall back. Whatever is in layout is correct.
- if (activity.metaData == null || !activity.metaData.containsKey(
+ if (activity.getMetaData() == null || !activity.getMetaData().containsKey(
ParsingPackageUtils.METADATA_ACTIVITY_WINDOW_LAYOUT_AFFINITY)) {
- return input.success(activity.windowLayout);
+ return input.success(activity.getWindowLayout());
}
// Layout already specifies a value. We should just use that one.
- if (activity.windowLayout != null && activity.windowLayout.windowLayoutAffinity != null) {
- return input.success(activity.windowLayout);
+ if (activity.getWindowLayout() != null && activity.getWindowLayout().windowLayoutAffinity != null) {
+ return input.success(activity.getWindowLayout());
}
- String windowLayoutAffinity = activity.metaData.getString(
+ String windowLayoutAffinity = activity.getMetaData().getString(
ParsingPackageUtils.METADATA_ACTIVITY_WINDOW_LAYOUT_AFFINITY);
- ActivityInfo.WindowLayout layout = activity.windowLayout;
+ ActivityInfo.WindowLayout layout = activity.getWindowLayout();
if (layout == null) {
layout = new ActivityInfo.WindowLayout(-1 /* width */, -1 /* widthFraction */,
-1 /* height */, -1 /* heightFraction */, Gravity.NO_GRAVITY,
diff --git a/core/java/android/content/pm/parsing/component/ParsedAttribution.java b/core/java/android/content/pm/parsing/component/ParsedAttribution.java
index 4ec2e73..db3a1c4 100644
--- a/core/java/android/content/pm/parsing/component/ParsedAttribution.java
+++ b/core/java/android/content/pm/parsing/component/ParsedAttribution.java
@@ -34,7 +34,7 @@
*
* @hide
*/
-@DataClass(genAidl = false)
+@DataClass(genAidl = false, genSetters = true, genBuilder = false)
public class ParsedAttribution implements Parcelable {
/** Maximum length of attribution tag */
public static final int MAX_ATTRIBUTION_TAG_LEN = 50;
@@ -43,13 +43,15 @@
private static final int MAX_NUM_ATTRIBUTIONS = 10000;
/** Tag of the attribution */
- public final @NonNull String tag;
+ private @NonNull String tag;
/** User visible label fo the attribution */
- public final @StringRes int label;
+ private @StringRes int label;
/** Ids of previously declared attributions this attribution inherits from */
- public final @NonNull List<String> inheritFrom;
+ private @NonNull List<String> inheritFrom;
+
+ public ParsedAttribution() {}
/**
* @return Is this set of attributions a valid combination for a single package?
@@ -160,6 +162,63 @@
// onConstructed(); // You can define this method to get a callback
}
+ /**
+ * Tag of the attribution
+ */
+ @DataClass.Generated.Member
+ public @NonNull String getTag() {
+ return tag;
+ }
+
+ /**
+ * User visible label fo the attribution
+ */
+ @DataClass.Generated.Member
+ public @StringRes int getLabel() {
+ return label;
+ }
+
+ /**
+ * Ids of previously declared attributions this attribution inherits from
+ */
+ @DataClass.Generated.Member
+ public @NonNull List<String> getInheritFrom() {
+ return inheritFrom;
+ }
+
+ /**
+ * Tag of the attribution
+ */
+ @DataClass.Generated.Member
+ public @NonNull ParsedAttribution setTag(@NonNull String value) {
+ tag = value;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, tag);
+ return this;
+ }
+
+ /**
+ * User visible label fo the attribution
+ */
+ @DataClass.Generated.Member
+ public @NonNull ParsedAttribution setLabel(@StringRes int value) {
+ label = value;
+ com.android.internal.util.AnnotationValidations.validate(
+ StringRes.class, null, label);
+ return this;
+ }
+
+ /**
+ * Ids of previously declared attributions this attribution inherits from
+ */
+ @DataClass.Generated.Member
+ public @NonNull ParsedAttribution setInheritFrom(@NonNull List<String> value) {
+ inheritFrom = value;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, inheritFrom);
+ return this;
+ }
+
@Override
@DataClass.Generated.Member
public void writeToParcel(@NonNull Parcel dest, int flags) {
@@ -215,10 +274,10 @@
};
@DataClass.Generated(
- time = 1618351459610L,
+ time = 1624050667337L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedAttribution.java",
- inputSignatures = "public static final int MAX_ATTRIBUTION_TAG_LEN\nprivate static final int MAX_NUM_ATTRIBUTIONS\npublic final @android.annotation.NonNull java.lang.String tag\npublic final @android.annotation.StringRes int label\npublic final @android.annotation.NonNull java.util.List<java.lang.String> inheritFrom\npublic static boolean isCombinationValid(java.util.List<android.content.pm.parsing.component.ParsedAttribution>)\nclass ParsedAttribution extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=false)")
+ inputSignatures = "public static final int MAX_ATTRIBUTION_TAG_LEN\nprivate static final int MAX_NUM_ATTRIBUTIONS\nprivate @android.annotation.NonNull java.lang.String tag\nprivate @android.annotation.StringRes int label\nprivate @android.annotation.NonNull java.util.List<java.lang.String> inheritFrom\npublic static boolean isCombinationValid(java.util.List<android.content.pm.parsing.component.ParsedAttribution>)\nclass ParsedAttribution extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=false, genSetters=true, genBuilder=false)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/content/pm/parsing/component/ParsedComponent.java b/core/java/android/content/pm/parsing/component/ParsedComponent.java
index 9d830ec..3c0f097 100644
--- a/core/java/android/content/pm/parsing/component/ParsedComponent.java
+++ b/core/java/android/content/pm/parsing/component/ParsedComponent.java
@@ -48,33 +48,33 @@
@NonNull
@DataClass.ParcelWith(ForInternedString.class)
- private String name;
- int icon;
- int labelRes;
+ protected String name;
+ protected int icon;
+ protected int labelRes;
@Nullable
- CharSequence nonLocalizedLabel;
- int logo;
- int banner;
- int descriptionRes;
+ protected CharSequence nonLocalizedLabel;
+ protected int logo;
+ protected int banner;
+ protected int descriptionRes;
// TODO(b/135203078): Replace flags with individual booleans, scoped by subclass
- int flags;
+ protected int flags;
@NonNull
@DataClass.ParcelWith(ForInternedString.class)
- private String packageName;
+ protected String packageName;
@Nullable
@DataClass.PluralOf("intent")
@DataClass.ParcelWith(ParsedIntentInfo.ListParceler.class)
- private List<ParsedIntentInfo> intents;
+ protected List<ParsedIntentInfo> intents;
- private ComponentName componentName;
+ protected ComponentName componentName;
@Nullable
protected Bundle metaData;
- private Map<String, Property> mProperties = emptyMap();
+ protected Map<String, Property> mProperties = emptyMap();
ParsedComponent() {
@@ -112,11 +112,51 @@
return intents != null ? intents : Collections.emptyList();
}
+ public ParsedComponent setBanner(int banner) {
+ this.banner = banner;
+ return this;
+ }
+
+ public ParsedComponent setDescriptionRes(int descriptionRes) {
+ this.descriptionRes = descriptionRes;
+ return this;
+ }
+
+ public ParsedComponent setFlags(int flags) {
+ this.flags = flags;
+ return this;
+ }
+
+ public ParsedComponent setIcon(int icon) {
+ this.icon = icon;
+ return this;
+ }
+
+ public ParsedComponent setLabelRes(int labelRes) {
+ this.labelRes = labelRes;
+ return this;
+ }
+
+ public ParsedComponent setLogo(int logo) {
+ this.logo = logo;
+ return this;
+ }
+
+ public ParsedComponent setMetaData(Bundle metaData) {
+ this.metaData = metaData;
+ return this;
+ }
+
public ParsedComponent setName(String name) {
this.name = TextUtils.safeIntern(name);
return this;
}
+ public ParsedComponent setNonLocalizedLabel(CharSequence nonLocalizedLabel) {
+ this.nonLocalizedLabel = nonLocalizedLabel;
+ return this;
+ }
+
@CallSuper
public void setPackageName(@NonNull String packageName) {
this.packageName = TextUtils.safeIntern(packageName);
diff --git a/core/java/android/content/pm/parsing/component/ParsedComponentUtils.java b/core/java/android/content/pm/parsing/component/ParsedComponentUtils.java
index 46b9419..ab596d3 100644
--- a/core/java/android/content/pm/parsing/component/ParsedComponentUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedComponentUtils.java
@@ -56,40 +56,40 @@
}
//noinspection ConstantConditions; null check done above with isEmpty
- component.setName(className);
- component.setPackageName(packageName);
+ component.setName(className)
+ .setPackageName(packageName);
int roundIconVal = useRoundIcon ? array.getResourceId(roundIconAttr, 0) : 0;
if (roundIconVal != 0) {
- component.icon = roundIconVal;
- component.nonLocalizedLabel = null;
+ component.setIcon(roundIconVal)
+ .setNonLocalizedLabel(null);
} else {
int iconVal = array.getResourceId(iconAttr, 0);
if (iconVal != 0) {
- component.icon = iconVal;
- component.nonLocalizedLabel = null;
+ component.setIcon(iconVal);
+ component.setNonLocalizedLabel(null);
}
}
int logoVal = array.getResourceId(logoAttr, 0);
if (logoVal != 0) {
- component.logo = logoVal;
+ component.setLogo(logoVal);
}
int bannerVal = array.getResourceId(bannerAttr, 0);
if (bannerVal != 0) {
- component.banner = bannerVal;
+ component.setBanner(bannerVal);
}
if (descriptionAttr != null) {
- component.descriptionRes = array.getResourceId(descriptionAttr, 0);
+ component.setDescriptionRes(array.getResourceId(descriptionAttr, 0));
}
TypedValue v = array.peekValue(labelAttr);
if (v != null) {
- component.labelRes = v.resourceId;
+ component.setLabelRes(v.resourceId);
if (v.resourceId == 0) {
- component.nonLocalizedLabel = v.coerceToString();
+ component.setNonLocalizedLabel(v.coerceToString());
}
}
@@ -105,9 +105,9 @@
}
final Property property = result.getResult();
if (property != null) {
- component.metaData = property.toBundle(component.metaData);
+ component.setMetaData(property.toBundle(component.getMetaData()));
}
- return input.success(component.metaData);
+ return input.success(component.getMetaData());
}
static ParseResult<Property> addProperty(ParsedComponent component, ParsingPackage pkg,
diff --git a/core/java/android/content/pm/parsing/component/ParsedInstrumentation.java b/core/java/android/content/pm/parsing/component/ParsedInstrumentation.java
index aa33e79..65ff472 100644
--- a/core/java/android/content/pm/parsing/component/ParsedInstrumentation.java
+++ b/core/java/android/content/pm/parsing/component/ParsedInstrumentation.java
@@ -36,18 +36,30 @@
@Nullable
@DataClass.ParcelWith(ForInternedString.class)
private String targetProcesses;
- boolean handleProfiling;
- boolean functionalTest;
+ private boolean handleProfiling;
+ private boolean functionalTest;
public ParsedInstrumentation() {
}
- public void setTargetPackage(@Nullable String targetPackage) {
- this.targetPackage = TextUtils.safeIntern(targetPackage);
+ public ParsedInstrumentation setFunctionalTest(boolean functionalTest) {
+ this.functionalTest = functionalTest;
+ return this;
}
- public void setTargetProcesses(@Nullable String targetProcesses) {
+ public ParsedInstrumentation setHandleProfiling(boolean handleProfiling) {
+ this.handleProfiling = handleProfiling;
+ return this;
+ }
+
+ public ParsedInstrumentation setTargetPackage(@Nullable String targetPackage) {
+ this.targetPackage = TextUtils.safeIntern(targetPackage);
+ return this;
+ }
+
+ public ParsedInstrumentation setTargetProcesses(@Nullable String targetProcesses) {
this.targetProcesses = TextUtils.safeIntern(targetProcesses);
+ return this;
}
public String toString() {
diff --git a/core/java/android/content/pm/parsing/component/ParsedInstrumentationUtils.java b/core/java/android/content/pm/parsing/component/ParsedInstrumentationUtils.java
index 89645fc..5977c83 100644
--- a/core/java/android/content/pm/parsing/component/ParsedInstrumentationUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedInstrumentationUtils.java
@@ -59,10 +59,10 @@
// @formatter:off
// Note: don't allow this value to be a reference to a resource
// that may change.
- instrumentation.setTargetPackage(sa.getNonResourceString(R.styleable.AndroidManifestInstrumentation_targetPackage));
- instrumentation.setTargetProcesses(sa.getNonResourceString(R.styleable.AndroidManifestInstrumentation_targetProcesses));
- instrumentation.handleProfiling = sa.getBoolean(R.styleable.AndroidManifestInstrumentation_handleProfiling, false);
- instrumentation.functionalTest = sa.getBoolean(R.styleable.AndroidManifestInstrumentation_functionalTest, false);
+ instrumentation.setTargetPackage(sa.getNonResourceString(R.styleable.AndroidManifestInstrumentation_targetPackage))
+ .setTargetProcesses(sa.getNonResourceString(R.styleable.AndroidManifestInstrumentation_targetProcesses))
+ .setHandleProfiling(sa.getBoolean(R.styleable.AndroidManifestInstrumentation_handleProfiling, false))
+ .setFunctionalTest(sa.getBoolean(R.styleable.AndroidManifestInstrumentation_functionalTest, false));
// @formatter:on
} finally {
sa.recycle();
diff --git a/core/java/android/content/pm/parsing/component/ParsedIntentInfo.java b/core/java/android/content/pm/parsing/component/ParsedIntentInfo.java
index 463a181..01ee0f4 100644
--- a/core/java/android/content/pm/parsing/component/ParsedIntentInfo.java
+++ b/core/java/android/content/pm/parsing/component/ParsedIntentInfo.java
@@ -31,6 +31,26 @@
public static final Parceler PARCELER = new Parceler();
+ public ParsedIntentInfo setHasDefault(boolean hasDefault) {
+ this.hasDefault = hasDefault;
+ return this;
+ }
+
+ public ParsedIntentInfo setIcon(int icon) {
+ this.icon = icon;
+ return this;
+ }
+
+ public ParsedIntentInfo setLabelRes(int labelRes) {
+ this.labelRes = labelRes;
+ return this;
+ }
+
+ public ParsedIntentInfo setNonLocalizedLabel(CharSequence nonLocalizedLabel) {
+ this.nonLocalizedLabel = nonLocalizedLabel;
+ return this;
+ }
+
public static class Parceler implements Parcelling<ParsedIntentInfo> {
@Override
@@ -135,11 +155,11 @@
}
}
- boolean hasDefault;
- int labelRes;
+ private boolean hasDefault;
+ private int labelRes;
@Nullable
- CharSequence nonLocalizedLabel;
- int icon;
+ private CharSequence nonLocalizedLabel;
+ private int icon;
public ParsedIntentInfo() {
}
diff --git a/core/java/android/content/pm/parsing/component/ParsedIntentInfoUtils.java b/core/java/android/content/pm/parsing/component/ParsedIntentInfoUtils.java
index 939e77f..dd71fa4 100644
--- a/core/java/android/content/pm/parsing/component/ParsedIntentInfoUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedIntentInfoUtils.java
@@ -60,19 +60,20 @@
TypedValue v = sa.peekValue(R.styleable.AndroidManifestIntentFilter_label);
if (v != null) {
- intentInfo.labelRes = v.resourceId;
+ intentInfo.setLabelRes(v.resourceId);
if (v.resourceId == 0) {
- intentInfo.nonLocalizedLabel = v.coerceToString();
+ intentInfo.setNonLocalizedLabel(v.coerceToString());
}
}
if (ParsingPackageUtils.sUseRoundIcon) {
- intentInfo.icon = sa.getResourceId(
- R.styleable.AndroidManifestIntentFilter_roundIcon, 0);
+ intentInfo.setIcon(sa.getResourceId(
+ R.styleable.AndroidManifestIntentFilter_roundIcon, 0));
}
- if (intentInfo.icon == 0) {
- intentInfo.icon = sa.getResourceId(R.styleable.AndroidManifestIntentFilter_icon, 0);
+ if (intentInfo.getIcon() == 0) {
+ intentInfo.setIcon(
+ sa.getResourceId(R.styleable.AndroidManifestIntentFilter_icon, 0));
}
if (allowAutoVerify) {
@@ -140,7 +141,7 @@
}
}
- intentInfo.hasDefault = intentInfo.hasCategory(Intent.CATEGORY_DEFAULT);
+ intentInfo.setHasDefault(intentInfo.hasCategory(Intent.CATEGORY_DEFAULT));
if (DEBUG) {
final StringBuilder cats = new StringBuilder("Intent d=");
diff --git a/core/java/android/content/pm/parsing/component/ParsedMainComponent.java b/core/java/android/content/pm/parsing/component/ParsedMainComponent.java
index 033e30f..433bfd3 100644
--- a/core/java/android/content/pm/parsing/component/ParsedMainComponent.java
+++ b/core/java/android/content/pm/parsing/component/ParsedMainComponent.java
@@ -31,16 +31,16 @@
@Nullable
@DataClass.ParcelWith(ForInternedString.class)
- private String processName;
- boolean directBootAware;
- boolean enabled = true;
- boolean exported;
- int order;
+ protected String processName;
+ protected boolean directBootAware;
+ protected boolean enabled = true;
+ protected boolean exported;
+ protected int order;
@Nullable
- String splitName;
+ protected String splitName;
@Nullable
- String[] attributionTags;
+ protected String[] attributionTags;
public ParsedMainComponent() {
}
@@ -56,6 +56,11 @@
this.attributionTags = other.attributionTags;
}
+ public ParsedMainComponent setOrder(int order) {
+ this.order = order;
+ return this;
+ }
+
public ParsedMainComponent setProcessName(String processName) {
this.processName = TextUtils.safeIntern(processName);
return this;
diff --git a/core/java/android/content/pm/parsing/component/ParsedMainComponentUtils.java b/core/java/android/content/pm/parsing/component/ParsedMainComponentUtils.java
index 54bcbdd..7ccca93 100644
--- a/core/java/android/content/pm/parsing/component/ParsedMainComponentUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedMainComponentUtils.java
@@ -58,14 +58,14 @@
}
if (directBootAwareAttr != null) {
- component.directBootAware = array.getBoolean(directBootAwareAttr, false);
+ component.setDirectBootAware(array.getBoolean(directBootAwareAttr, false));
if (component.isDirectBootAware()) {
pkg.setPartiallyDirectBootAware(true);
}
}
if (enabledAttr != null) {
- component.enabled = array.getBoolean(enabledAttr, true);
+ component.setEnabled(array.getBoolean(enabledAttr, true));
}
if (processAttr != null) {
@@ -92,13 +92,13 @@
}
if (splitNameAttr != null) {
- component.splitName = array.getNonConfigurationString(splitNameAttr, 0);
+ component.setSplitName(array.getNonConfigurationString(splitNameAttr, 0));
}
if (attributionTagsAttr != null) {
final String attributionTags = array.getNonConfigurationString(attributionTagsAttr, 0);
if (attributionTags != null) {
- component.attributionTags = attributionTags.split("\\|");
+ component.setAttributionTags(attributionTags.split("\\|"));
}
}
diff --git a/core/java/android/content/pm/parsing/component/ParsedPermission.java b/core/java/android/content/pm/parsing/component/ParsedPermission.java
index 37e0e87..50bc3d9 100644
--- a/core/java/android/content/pm/parsing/component/ParsedPermission.java
+++ b/core/java/android/content/pm/parsing/component/ParsedPermission.java
@@ -38,17 +38,17 @@
private static ForStringSet sForStringSet = Parcelling.Cache.getOrCreate(ForStringSet.class);
@Nullable
- String backgroundPermission;
+ private String backgroundPermission;
@Nullable
@DataClass.ParcelWith(ForInternedString.class)
private String group;
- int requestRes;
- int protectionLevel;
- boolean tree;
+ private int requestRes;
+ private int protectionLevel;
+ private boolean tree;
@Nullable
private ParsedPermissionGroup parsedPermissionGroup;
@Nullable
- Set<String> knownCerts;
+ private Set<String> knownCerts;
@VisibleForTesting
public ParsedPermission() {
@@ -64,13 +64,13 @@
this.parsedPermissionGroup = other.parsedPermissionGroup;
}
- public ParsedPermission setGroup(String group) {
- this.group = TextUtils.safeIntern(group);
+ public ParsedPermission setBackgroundPermission(String backgroundPermission) {
+ this.backgroundPermission = backgroundPermission;
return this;
}
- public ParsedPermission setFlags(int flags) {
- this.flags = flags;
+ public ParsedPermission setGroup(String group) {
+ this.group = TextUtils.safeIntern(group);
return this;
}
@@ -116,6 +116,21 @@
return size;
}
+ public ParsedPermission setKnownCerts(Set<String> knownCerts) {
+ this.knownCerts = knownCerts;
+ return this;
+ }
+
+ public ParsedPermission setRequestRes(int requestRes) {
+ this.requestRes = requestRes;
+ return this;
+ }
+
+ public ParsedPermission setTree(boolean tree) {
+ this.tree = tree;
+ return this;
+ }
+
public String toString() {
return "Permission{"
+ Integer.toHexString(System.identityHashCode(this))
diff --git a/core/java/android/content/pm/parsing/component/ParsedPermissionGroup.java b/core/java/android/content/pm/parsing/component/ParsedPermissionGroup.java
index 741c00c..9fb95c4 100644
--- a/core/java/android/content/pm/parsing/component/ParsedPermissionGroup.java
+++ b/core/java/android/content/pm/parsing/component/ParsedPermissionGroup.java
@@ -22,17 +22,15 @@
import com.android.internal.util.DataClass;
/** @hide */
+@DataClass(genGetters = true, genSetters = true, genBuilder = false, genParcelable = true,
+ genAidl = false)
public class ParsedPermissionGroup extends ParsedComponent {
- int requestDetailResourceId;
- int backgroundRequestResourceId;
- int backgroundRequestDetailResourceId;
- int requestRes;
- int priority;
-
- public void setPriority(int priority) {
- this.priority = priority;
- }
+ private int requestDetailResourceId;
+ private int backgroundRequestResourceId;
+ private int backgroundRequestDetailResourceId;
+ private int requestRes;
+ private int priority;
public String toString() {
return "PermissionGroup{"
@@ -40,63 +38,162 @@
+ " " + getName() + "}";
}
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- super.writeToParcel(dest, flags);
- dest.writeInt(this.requestDetailResourceId);
- dest.writeInt(this.backgroundRequestResourceId);
- dest.writeInt(this.backgroundRequestDetailResourceId);
- dest.writeInt(this.requestRes);
- dest.writeInt(this.priority);
- }
-
public ParsedPermissionGroup() {
}
- protected ParsedPermissionGroup(Parcel in) {
- super(in);
- this.requestDetailResourceId = in.readInt();
- this.backgroundRequestResourceId = in.readInt();
- this.backgroundRequestDetailResourceId = in.readInt();
- this.requestRes = in.readInt();
- this.priority = in.readInt();
+
+
+ // Code below generated by codegen v1.0.23.
+ //
+ // DO NOT MODIFY!
+ // CHECKSTYLE:OFF Generated code
+ //
+ // To regenerate run:
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedPermissionGroup.java
+ //
+ // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+ // Settings > Editor > Code Style > Formatter Control
+ //@formatter:off
+
+
+ @DataClass.Generated.Member
+ public ParsedPermissionGroup(
+ int requestDetailResourceId,
+ int backgroundRequestResourceId,
+ int backgroundRequestDetailResourceId,
+ int requestRes,
+ int priority) {
+ this.requestDetailResourceId = requestDetailResourceId;
+ this.backgroundRequestResourceId = backgroundRequestResourceId;
+ this.backgroundRequestDetailResourceId = backgroundRequestDetailResourceId;
+ this.requestRes = requestRes;
+ this.priority = priority;
+
+ // onConstructed(); // You can define this method to get a callback
}
- public static final Parcelable.Creator<ParsedPermissionGroup> CREATOR =
- new Parcelable.Creator<ParsedPermissionGroup>() {
- @Override
- public ParsedPermissionGroup createFromParcel(Parcel source) {
- return new ParsedPermissionGroup(source);
- }
-
- @Override
- public ParsedPermissionGroup[] newArray(int size) {
- return new ParsedPermissionGroup[size];
- }
- };
-
+ @DataClass.Generated.Member
public int getRequestDetailResourceId() {
return requestDetailResourceId;
}
+ @DataClass.Generated.Member
public int getBackgroundRequestResourceId() {
return backgroundRequestResourceId;
}
+ @DataClass.Generated.Member
public int getBackgroundRequestDetailResourceId() {
return backgroundRequestDetailResourceId;
}
+ @DataClass.Generated.Member
public int getRequestRes() {
return requestRes;
}
+ @DataClass.Generated.Member
public int getPriority() {
return priority;
}
+
+ @DataClass.Generated.Member
+ public @android.annotation.NonNull ParsedPermissionGroup setRequestDetailResourceId( int value) {
+ requestDetailResourceId = value;
+ return this;
+ }
+
+ @DataClass.Generated.Member
+ public @android.annotation.NonNull ParsedPermissionGroup setBackgroundRequestResourceId( int value) {
+ backgroundRequestResourceId = value;
+ return this;
+ }
+
+ @DataClass.Generated.Member
+ public @android.annotation.NonNull ParsedPermissionGroup setBackgroundRequestDetailResourceId( int value) {
+ backgroundRequestDetailResourceId = value;
+ return this;
+ }
+
+ @DataClass.Generated.Member
+ public @android.annotation.NonNull ParsedPermissionGroup setRequestRes( int value) {
+ requestRes = value;
+ return this;
+ }
+
+ @DataClass.Generated.Member
+ public @android.annotation.NonNull ParsedPermissionGroup setPriority( int value) {
+ priority = value;
+ return this;
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public void writeToParcel(@android.annotation.NonNull Parcel dest, int flags) {
+ // You can override field parcelling by defining methods like:
+ // void parcelFieldName(Parcel dest, int flags) { ... }
+
+ super.writeToParcel(dest, flags);
+
+ dest.writeInt(requestDetailResourceId);
+ dest.writeInt(backgroundRequestResourceId);
+ dest.writeInt(backgroundRequestDetailResourceId);
+ dest.writeInt(requestRes);
+ dest.writeInt(priority);
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public int describeContents() { return 0; }
+
+ /** @hide */
+ @SuppressWarnings({"unchecked", "RedundantCast"})
+ @DataClass.Generated.Member
+ protected ParsedPermissionGroup(@android.annotation.NonNull Parcel in) {
+ // You can override field unparcelling by defining methods like:
+ // static FieldType unparcelFieldName(Parcel in) { ... }
+
+ super(in);
+
+ int _requestDetailResourceId = in.readInt();
+ int _backgroundRequestResourceId = in.readInt();
+ int _backgroundRequestDetailResourceId = in.readInt();
+ int _requestRes = in.readInt();
+ int _priority = in.readInt();
+
+ this.requestDetailResourceId = _requestDetailResourceId;
+ this.backgroundRequestResourceId = _backgroundRequestResourceId;
+ this.backgroundRequestDetailResourceId = _backgroundRequestDetailResourceId;
+ this.requestRes = _requestRes;
+ this.priority = _priority;
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @DataClass.Generated.Member
+ public static final @android.annotation.NonNull Parcelable.Creator<ParsedPermissionGroup> CREATOR
+ = new Parcelable.Creator<ParsedPermissionGroup>() {
+ @Override
+ public ParsedPermissionGroup[] newArray(int size) {
+ return new ParsedPermissionGroup[size];
+ }
+
+ @Override
+ public ParsedPermissionGroup createFromParcel(@android.annotation.NonNull Parcel in) {
+ return new ParsedPermissionGroup(in);
+ }
+ };
+
+ @DataClass.Generated(
+ time = 1624052057830L,
+ codegenVersion = "1.0.23",
+ sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedPermissionGroup.java",
+ inputSignatures = "private int requestDetailResourceId\nprivate int backgroundRequestResourceId\nprivate int backgroundRequestDetailResourceId\nprivate int requestRes\nprivate int priority\npublic java.lang.String toString()\nclass ParsedPermissionGroup extends android.content.pm.parsing.component.ParsedComponent implements []\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=true, genAidl=false)")
+ @Deprecated
+ private void __metadata() {}
+
+
+ //@formatter:on
+ // End of generated code
+
}
diff --git a/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java b/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java
index 8afa70e..eec333c 100644
--- a/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java
@@ -66,9 +66,8 @@
if (sa.hasValue(
R.styleable.AndroidManifestPermission_backgroundPermission)) {
if ("android".equals(packageName)) {
- permission.backgroundPermission = sa.getNonResourceString(
- R.styleable
- .AndroidManifestPermission_backgroundPermission);
+ permission.setBackgroundPermission(sa.getNonResourceString(
+ R.styleable.AndroidManifestPermission_backgroundPermission));
} else {
Slog.w(TAG, packageName + " defines a background permission. Only the "
+ "'android' package can do that.");
@@ -78,17 +77,14 @@
// Note: don't allow this value to be a reference to a resource
// that may change.
permission.setGroup(sa.getNonResourceString(
- R.styleable.AndroidManifestPermission_permissionGroup));
-
- permission.requestRes = sa.getResourceId(
- R.styleable.AndroidManifestPermission_request, 0);
-
- permission.protectionLevel = sa.getInt(
- R.styleable.AndroidManifestPermission_protectionLevel,
- PermissionInfo.PROTECTION_NORMAL);
-
- permission.flags = sa.getInt(
- R.styleable.AndroidManifestPermission_permissionFlags, 0);
+ R.styleable.AndroidManifestPermission_permissionGroup))
+ .setRequestRes(sa.getResourceId(
+ R.styleable.AndroidManifestPermission_request, 0))
+ .setProtectionLevel(sa.getInt(
+ R.styleable.AndroidManifestPermission_protectionLevel,
+ PermissionInfo.PROTECTION_NORMAL))
+ .setFlags(sa.getInt(
+ R.styleable.AndroidManifestPermission_permissionFlags, 0));
final int knownCertsResource = sa.getResourceId(
R.styleable.AndroidManifestPermission_knownCerts, 0);
@@ -108,7 +104,7 @@
permission.setKnownCert(knownCert);
}
}
- if (permission.knownCerts == null) {
+ if (permission.getKnownCerts() == null) {
Slog.w(TAG, packageName + " defines a knownSigner permission but"
+ " the provided knownCerts resource is null");
}
@@ -124,12 +120,12 @@
// For now only platform runtime permissions can be restricted
if (!permission.isRuntime() || !"android".equals(permission.getPackageName())) {
- permission.flags &= ~PermissionInfo.FLAG_HARD_RESTRICTED;
- permission.flags &= ~PermissionInfo.FLAG_SOFT_RESTRICTED;
+ permission.setFlags(permission.getFlags() & ~PermissionInfo.FLAG_HARD_RESTRICTED);
+ permission.setFlags(permission.getFlags() & ~PermissionInfo.FLAG_SOFT_RESTRICTED);
} else {
// The platform does not get to specify conflicting permissions
- if ((permission.flags & PermissionInfo.FLAG_HARD_RESTRICTED) != 0
- && (permission.flags & PermissionInfo.FLAG_SOFT_RESTRICTED) != 0) {
+ if ((permission.getFlags() & PermissionInfo.FLAG_HARD_RESTRICTED) != 0
+ && (permission.getFlags() & PermissionInfo.FLAG_SOFT_RESTRICTED) != 0) {
throw new IllegalStateException("Permission cannot be both soft and hard"
+ " restricted: " + permission.getName());
}
@@ -138,7 +134,8 @@
sa.recycle();
}
- permission.protectionLevel = PermissionInfo.fixProtectionLevel(permission.protectionLevel);
+ permission.setProtectionLevel(
+ PermissionInfo.fixProtectionLevel(permission.getProtectionLevel()));
final int otherProtectionFlags = permission.getProtectionFlags()
& ~(PermissionInfo.PROTECTION_FLAG_APPOP | PermissionInfo.PROTECTION_FLAG_INSTANT
@@ -188,8 +185,8 @@
+ permission.getName());
}
- permission.protectionLevel = PermissionInfo.PROTECTION_NORMAL;
- permission.tree = true;
+ permission.setProtectionLevel(PermissionInfo.PROTECTION_NORMAL)
+ .setTree(true);
return ComponentParseUtils.parseAllMetaData(pkg, res, parser, tag, permission,
input);
@@ -219,12 +216,12 @@
}
// @formatter:off
- permissionGroup.requestDetailResourceId = sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_requestDetail, 0);
- permissionGroup.backgroundRequestResourceId = sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_backgroundRequest, 0);
- permissionGroup.backgroundRequestDetailResourceId = sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_backgroundRequestDetail, 0);
- permissionGroup.requestRes = sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_request, 0);
- permissionGroup.flags = sa.getInt(R.styleable.AndroidManifestPermissionGroup_permissionGroupFlags,0);
- permissionGroup.priority = sa.getInt(R.styleable.AndroidManifestPermissionGroup_priority, 0);
+ permissionGroup.setRequestDetailResourceId(sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_requestDetail, 0))
+ .setBackgroundRequestResourceId(sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_backgroundRequest, 0))
+ .setBackgroundRequestDetailResourceId(sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_backgroundRequestDetail, 0))
+ .setRequestRes(sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_request, 0))
+ .setPriority(sa.getInt(R.styleable.AndroidManifestPermissionGroup_priority, 0))
+ .setFlags(sa.getInt(R.styleable.AndroidManifestPermissionGroup_permissionGroupFlags,0));
// @formatter:on
} finally {
sa.recycle();
diff --git a/core/java/android/content/pm/parsing/component/ParsedProcess.java b/core/java/android/content/pm/parsing/component/ParsedProcess.java
index 54a60d3..c39d6b1 100644
--- a/core/java/android/content/pm/parsing/component/ParsedProcess.java
+++ b/core/java/android/content/pm/parsing/component/ParsedProcess.java
@@ -32,22 +32,22 @@
import java.util.Set;
/** @hide */
-@DataClass(genGetters = true, genSetters = false, genParcelable = true, genAidl = false,
+@DataClass(genGetters = true, genSetters = true, genParcelable = true, genAidl = false,
genBuilder = false)
public class ParsedProcess implements Parcelable {
@NonNull
- protected String name;
+ private String name;
@NonNull
@DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringSet.class)
- protected Set<String> deniedPermissions = emptySet();
+ private Set<String> deniedPermissions = emptySet();
@ApplicationInfo.GwpAsanMode
- protected int gwpAsanMode = ApplicationInfo.GWP_ASAN_DEFAULT;
+ private int gwpAsanMode = ApplicationInfo.GWP_ASAN_DEFAULT;
@ApplicationInfo.MemtagMode
- protected int memtagMode = ApplicationInfo.MEMTAG_DEFAULT;
+ private int memtagMode = ApplicationInfo.MEMTAG_DEFAULT;
@ApplicationInfo.NativeHeapZeroInitialized
- protected int nativeHeapZeroInitialized = ApplicationInfo.ZEROINIT_DEFAULT;
+ private int nativeHeapZeroInitialized = ApplicationInfo.ZEROINIT_DEFAULT;
public ParsedProcess() {
}
@@ -63,7 +63,7 @@
- // Code below generated by codegen v1.0.22.
+ // Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -128,6 +128,46 @@
}
@DataClass.Generated.Member
+ public @NonNull ParsedProcess setName(@NonNull String value) {
+ name = value;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, name);
+ return this;
+ }
+
+ @DataClass.Generated.Member
+ public @NonNull ParsedProcess setDeniedPermissions(@NonNull Set<String> value) {
+ deniedPermissions = value;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, deniedPermissions);
+ return this;
+ }
+
+ @DataClass.Generated.Member
+ public @NonNull ParsedProcess setGwpAsanMode(@ApplicationInfo.GwpAsanMode int value) {
+ gwpAsanMode = value;
+ com.android.internal.util.AnnotationValidations.validate(
+ ApplicationInfo.GwpAsanMode.class, null, gwpAsanMode);
+ return this;
+ }
+
+ @DataClass.Generated.Member
+ public @NonNull ParsedProcess setMemtagMode(@ApplicationInfo.MemtagMode int value) {
+ memtagMode = value;
+ com.android.internal.util.AnnotationValidations.validate(
+ ApplicationInfo.MemtagMode.class, null, memtagMode);
+ return this;
+ }
+
+ @DataClass.Generated.Member
+ public @NonNull ParsedProcess setNativeHeapZeroInitialized(@ApplicationInfo.NativeHeapZeroInitialized int value) {
+ nativeHeapZeroInitialized = value;
+ com.android.internal.util.AnnotationValidations.validate(
+ ApplicationInfo.NativeHeapZeroInitialized.class, null, nativeHeapZeroInitialized);
+ return this;
+ }
+
+ @DataClass.Generated.Member
static Parcelling<Set<String>> sParcellingForDeniedPermissions =
Parcelling.Cache.get(
Parcelling.BuiltIn.ForInternedStringSet.class);
@@ -202,10 +242,10 @@
};
@DataClass.Generated(
- time = 1615850515058L,
- codegenVersion = "1.0.22",
+ time = 1623692988845L,
+ codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedProcess.java",
- inputSignatures = "protected @android.annotation.NonNull java.lang.String name\nprotected @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedStringSet.class) java.util.Set<java.lang.String> deniedPermissions\nprotected @android.content.pm.ApplicationInfo.GwpAsanMode int gwpAsanMode\nprotected @android.content.pm.ApplicationInfo.MemtagMode int memtagMode\nprotected @android.content.pm.ApplicationInfo.NativeHeapZeroInitialized int nativeHeapZeroInitialized\npublic void addStateFrom(android.content.pm.parsing.component.ParsedProcess)\nclass ParsedProcess extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=false, genParcelable=true, genAidl=false, genBuilder=false)")
+ inputSignatures = "private @android.annotation.NonNull java.lang.String name\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedStringSet.class) java.util.Set<java.lang.String> deniedPermissions\nprivate @android.content.pm.ApplicationInfo.GwpAsanMode int gwpAsanMode\nprivate @android.content.pm.ApplicationInfo.MemtagMode int memtagMode\nprivate @android.content.pm.ApplicationInfo.NativeHeapZeroInitialized int nativeHeapZeroInitialized\npublic void addStateFrom(android.content.pm.parsing.component.ParsedProcess)\nclass ParsedProcess extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genParcelable=true, genAidl=false, genBuilder=false)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/content/pm/parsing/component/ParsedProcessUtils.java b/core/java/android/content/pm/parsing/component/ParsedProcessUtils.java
index e417e74..d4e19af 100644
--- a/core/java/android/content/pm/parsing/component/ParsedProcessUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedProcessUtils.java
@@ -85,31 +85,26 @@
TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestProcess);
try {
if (perms != null) {
- proc.deniedPermissions = new ArraySet<>(perms);
+ proc.setDeniedPermissions(new ArraySet<>(perms));
}
- proc.name = sa.getNonConfigurationString(
+ String processName = sa.getNonConfigurationString(
R.styleable.AndroidManifestProcess_process, 0);
ParseResult<String> processNameResult = ComponentParseUtils.buildProcessName(
- pkg.getPackageName(), pkg.getPackageName(), proc.name, flags, separateProcesses,
+ pkg.getPackageName(), pkg.getPackageName(), processName, flags, separateProcesses,
input);
if (processNameResult.isError()) {
return input.error(processNameResult);
}
- proc.name = processNameResult.getResult();
-
- if (proc.name == null || proc.name.length() <= 0) {
- return input.error("<process> does not specify android:process");
- }
-
- proc.gwpAsanMode = sa.getInt(R.styleable.AndroidManifestProcess_gwpAsanMode, -1);
- proc.memtagMode = sa.getInt(R.styleable.AndroidManifestProcess_memtagMode, -1);
+ proc.setName(processNameResult.getResult());
+ proc.setGwpAsanMode(sa.getInt(R.styleable.AndroidManifestProcess_gwpAsanMode, -1));
+ proc.setMemtagMode(sa.getInt(R.styleable.AndroidManifestProcess_memtagMode, -1));
if (sa.hasValue(R.styleable.AndroidManifestProcess_nativeHeapZeroInitialized)) {
Boolean v = sa.getBoolean(
R.styleable.AndroidManifestProcess_nativeHeapZeroInitialized, false);
- proc.nativeHeapZeroInitialized =
- v ? ApplicationInfo.ZEROINIT_ENABLED : ApplicationInfo.ZEROINIT_DISABLED;
+ proc.setNativeHeapZeroInitialized(
+ v ? ApplicationInfo.ZEROINIT_ENABLED : ApplicationInfo.ZEROINIT_DISABLED);
}
} finally {
sa.recycle();
@@ -129,18 +124,18 @@
switch (tagName) {
case "deny-permission":
ParseResult<Set<String>> denyResult = parseDenyPermission(
- proc.deniedPermissions, res, parser, input);
+ proc.getDeniedPermissions(), res, parser, input);
result = denyResult;
if (denyResult.isSuccess()) {
- proc.deniedPermissions = denyResult.getResult();
+ proc.setDeniedPermissions(denyResult.getResult());
}
break;
case "allow-permission":
ParseResult<Set<String>> allowResult = parseAllowPermission(
- proc.deniedPermissions, res, parser, input);
+ proc.getDeniedPermissions(), res, parser, input);
result = allowResult;
if (allowResult.isSuccess()) {
- proc.deniedPermissions = allowResult.getResult();
+ proc.setDeniedPermissions(allowResult.getResult());
}
break;
default:
@@ -198,9 +193,9 @@
result = processResult;
if (processResult.isSuccess()) {
ParsedProcess process = processResult.getResult();
- if (processes.put(process.name, process) != null) {
+ if (processes.put(process.getName(), process) != null) {
result = input.error(
- "<process> specified existing name '" + process.name + "'");
+ "<process> specified existing name '" + process.getName() + "'");
}
}
break;
diff --git a/core/java/android/content/pm/parsing/component/ParsedProvider.java b/core/java/android/content/pm/parsing/component/ParsedProvider.java
index fcf6e87..ebf85f7 100644
--- a/core/java/android/content/pm/parsing/component/ParsedProvider.java
+++ b/core/java/android/content/pm/parsing/component/ParsedProvider.java
@@ -36,21 +36,21 @@
@NonNull
@DataClass.ParcelWith(ForInternedString.class)
private String authority;
- boolean syncable;
+ private boolean syncable;
@Nullable
@DataClass.ParcelWith(ForInternedString.class)
private String readPermission;
@Nullable
@DataClass.ParcelWith(ForInternedString.class)
private String writePermission;
- boolean grantUriPermissions;
- boolean forceUriPermissions;
- boolean multiProcess;
- int initOrder;
+ private boolean grantUriPermissions;
+ private boolean forceUriPermissions;
+ private boolean multiProcess;
+ private int initOrder;
@Nullable
- PatternMatcher[] uriPermissionPatterns;
+ private PatternMatcher[] uriPermissionPatterns;
@Nullable
- PathPermission[] pathPermissions;
+ private PathPermission[] pathPermissions;
public ParsedProvider(ParsedProvider other) {
super(other);
@@ -67,24 +67,58 @@
this.pathPermissions = other.pathPermissions;
}
- public void setAuthority(String authority) {
+ public ParsedProvider setAuthority(String authority) {
this.authority = TextUtils.safeIntern(authority);
+ return this;
}
- public void setSyncable(boolean syncable) {
+ public ParsedProvider setForceUriPermissions(boolean forceUriPermissions) {
+ this.forceUriPermissions = forceUriPermissions;
+ return this;
+ }
+
+ public ParsedProvider setGrantUriPermissions(boolean grantUriPermissions) {
+ this.grantUriPermissions = grantUriPermissions;
+ return this;
+ }
+
+ public ParsedProvider setInitOrder(int initOrder) {
+ this.initOrder = initOrder;
+ return this;
+ }
+
+ public ParsedProvider setMultiProcess(boolean multiProcess) {
+ this.multiProcess = multiProcess;
+ return this;
+ }
+
+ public ParsedProvider setPathPermissions(PathPermission[] pathPermissions) {
+ this.pathPermissions = pathPermissions;
+ return this;
+ }
+
+ public ParsedProvider setSyncable(boolean syncable) {
this.syncable = syncable;
+ return this;
}
- public void setReadPermission(String readPermission) {
+ public ParsedProvider setReadPermission(String readPermission) {
// Empty string must be converted to null
this.readPermission = TextUtils.isEmpty(readPermission)
? null : readPermission.intern();
+ return this;
}
- public void setWritePermission(String writePermission) {
+ public ParsedProvider setUriPermissionPatterns(PatternMatcher[] uriPermissionPatterns) {
+ this.uriPermissionPatterns = uriPermissionPatterns;
+ return this;
+ }
+
+ public ParsedProvider setWritePermission(String writePermission) {
// Empty string must be converted to null
this.writePermission = TextUtils.isEmpty(writePermission)
? null : writePermission.intern();
+ return this;
}
public String toString() {
diff --git a/core/java/android/content/pm/parsing/component/ParsedProviderUtils.java b/core/java/android/content/pm/parsing/component/ParsedProviderUtils.java
index 28fd919..0b03567 100644
--- a/core/java/android/content/pm/parsing/component/ParsedProviderUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedProviderUtils.java
@@ -85,10 +85,10 @@
// For compatibility, applications targeting API level 16 or lower
// should have their content providers exported by default, unless they
// specify otherwise.
- provider.exported = sa.getBoolean(R.styleable.AndroidManifestProvider_exported,
- targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1);
-
- provider.syncable = sa.getBoolean(R.styleable.AndroidManifestProvider_syncable, false);
+ provider.setSyncable(sa.getBoolean(
+ R.styleable.AndroidManifestProvider_syncable, false))
+ .setExported(sa.getBoolean(R.styleable.AndroidManifestProvider_exported,
+ targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1));
String permission = sa.getNonConfigurationString(
R.styleable.AndroidManifestProvider_permission, 0);
@@ -113,16 +113,21 @@
provider.setWritePermission(writePermission);
}
- provider.grantUriPermissions = sa.getBoolean(R.styleable.AndroidManifestProvider_grantUriPermissions, false);
- provider.forceUriPermissions = sa.getBoolean(R.styleable.AndroidManifestProvider_forceUriPermissions, false);
- provider.multiProcess = sa.getBoolean(R.styleable.AndroidManifestProvider_multiprocess, false);
- provider.initOrder = sa.getInt(R.styleable.AndroidManifestProvider_initOrder, 0);
+ provider.setGrantUriPermissions(
+ sa.getBoolean(R.styleable.AndroidManifestProvider_grantUriPermissions, false))
+ .setForceUriPermissions(
+ sa.getBoolean(R.styleable.AndroidManifestProvider_forceUriPermissions,
+ false))
+ .setMultiProcess(
+ sa.getBoolean(R.styleable.AndroidManifestProvider_multiprocess, false))
+ .setInitOrder(sa.getInt(R.styleable.AndroidManifestProvider_initOrder, 0))
+ .setFlags(provider.getFlags() | flag(ProviderInfo.FLAG_SINGLE_USER,
+ R.styleable.AndroidManifestProvider_singleUser, sa));
- provider.flags |= flag(ProviderInfo.FLAG_SINGLE_USER, R.styleable.AndroidManifestProvider_singleUser, sa);
-
- visibleToEphemeral = sa.getBoolean(R.styleable.AndroidManifestProvider_visibleToInstantApps, false);
+ visibleToEphemeral = sa.getBoolean(
+ R.styleable.AndroidManifestProvider_visibleToInstantApps, false);
if (visibleToEphemeral) {
- provider.flags |= ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP;
+ provider.setFlags(provider.getFlags() | ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP);
pkg.setVisibleToInstantApps(true);
}
} finally {
@@ -174,7 +179,7 @@
result = intentResult;
if (intentResult.isSuccess()) {
ParsedIntentInfo intent = intentResult.getResult();
- provider.order = Math.max(intent.getOrder(), provider.order);
+ provider.setOrder(Math.max(intent.getOrder(), provider.getOrder()));
provider.addIntent(intent);
}
break;
@@ -245,17 +250,17 @@
}
if (pa != null) {
- if (provider.uriPermissionPatterns == null) {
- provider.uriPermissionPatterns = new PatternMatcher[1];
- provider.uriPermissionPatterns[0] = pa;
+ if (provider.getUriPermissionPatterns() == null) {
+ provider.setUriPermissionPatterns(new PatternMatcher[1]);
+ provider.getUriPermissionPatterns()[0] = pa;
} else {
- final int N = provider.uriPermissionPatterns.length;
+ final int N = provider.getUriPermissionPatterns().length;
PatternMatcher[] newp = new PatternMatcher[N + 1];
- System.arraycopy(provider.uriPermissionPatterns, 0, newp, 0, N);
+ System.arraycopy(provider.getUriPermissionPatterns(), 0, newp, 0, N);
newp[N] = pa;
- provider.uriPermissionPatterns = newp;
+ provider.setUriPermissionPatterns(newp);
}
- provider.grantUriPermissions = true;
+ provider.setGrantUriPermissions(true);
} else {
if (PackageParser.RIGID_PARSER) {
return input.error("No path, pathPrefix, or pathPattern for <path-permission>");
@@ -349,15 +354,15 @@
}
if (pa != null) {
- if (provider.pathPermissions == null) {
- provider.pathPermissions = new PathPermission[1];
- provider.pathPermissions[0] = pa;
+ if (provider.getPathPermissions() == null) {
+ provider.setPathPermissions(new PathPermission[1]);
+ provider.getPathPermissions()[0] = pa;
} else {
- final int N = provider.pathPermissions.length;
+ final int N = provider.getPathPermissions().length;
PathPermission[] newp = new PathPermission[N + 1];
- System.arraycopy(provider.pathPermissions, 0, newp, 0, N);
+ System.arraycopy(provider.getPathPermissions(), 0, newp, 0, N);
newp[N] = pa;
- provider.pathPermissions = newp;
+ provider.setPathPermissions(newp);
}
} else {
if (PackageParser.RIGID_PARSER) {
diff --git a/core/java/android/content/pm/parsing/component/ParsedService.java b/core/java/android/content/pm/parsing/component/ParsedService.java
index 7adb262..471d346 100644
--- a/core/java/android/content/pm/parsing/component/ParsedService.java
+++ b/core/java/android/content/pm/parsing/component/ParsedService.java
@@ -30,7 +30,7 @@
/** @hide **/
public class ParsedService extends ParsedMainComponent {
- int foregroundServiceType;
+ private int foregroundServiceType;
@Nullable
@DataClass.ParcelWith(ForInternedString.class)
private String permission;
@@ -41,6 +41,11 @@
this.permission = other.permission;
}
+ public ParsedService setForegroundServiceType(int foregroundServiceType) {
+ this.foregroundServiceType = foregroundServiceType;
+ return this;
+ }
+
public ParsedMainComponent setPermission(String permission) {
// Empty string must be converted to null
this.permission = TextUtils.isEmpty(permission) ? null : permission.intern();
diff --git a/core/java/android/content/pm/parsing/component/ParsedServiceUtils.java b/core/java/android/content/pm/parsing/component/ParsedServiceUtils.java
index ae107ce..59267f9 100644
--- a/core/java/android/content/pm/parsing/component/ParsedServiceUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedServiceUtils.java
@@ -78,33 +78,32 @@
setExported = sa.hasValue(R.styleable.AndroidManifestService_exported);
if (setExported) {
- service.exported = sa.getBoolean(R.styleable.AndroidManifestService_exported,
- false);
+ service.setExported(sa.getBoolean(R.styleable.AndroidManifestService_exported,
+ false));
}
String permission = sa.getNonConfigurationString(
R.styleable.AndroidManifestService_permission, 0);
service.setPermission(permission != null ? permission : pkg.getPermission());
- service.foregroundServiceType = sa.getInt(
+ service.setForegroundServiceType(sa.getInt(
R.styleable.AndroidManifestService_foregroundServiceType,
- ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE);
-
- service.flags |= flag(ServiceInfo.FLAG_STOP_WITH_TASK,
- R.styleable.AndroidManifestService_stopWithTask, sa)
- | flag(ServiceInfo.FLAG_ISOLATED_PROCESS,
- R.styleable.AndroidManifestService_isolatedProcess, sa)
- | flag(ServiceInfo.FLAG_EXTERNAL_SERVICE,
- R.styleable.AndroidManifestService_externalService, sa)
- | flag(ServiceInfo.FLAG_USE_APP_ZYGOTE,
- R.styleable.AndroidManifestService_useAppZygote, sa)
- | flag(ServiceInfo.FLAG_SINGLE_USER,
- R.styleable.AndroidManifestService_singleUser, sa);
+ ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE))
+ .setFlags(service.getFlags() | (flag(ServiceInfo.FLAG_STOP_WITH_TASK,
+ R.styleable.AndroidManifestService_stopWithTask, sa)
+ | flag(ServiceInfo.FLAG_ISOLATED_PROCESS,
+ R.styleable.AndroidManifestService_isolatedProcess, sa)
+ | flag(ServiceInfo.FLAG_EXTERNAL_SERVICE,
+ R.styleable.AndroidManifestService_externalService, sa)
+ | flag(ServiceInfo.FLAG_USE_APP_ZYGOTE,
+ R.styleable.AndroidManifestService_useAppZygote, sa)
+ | flag(ServiceInfo.FLAG_SINGLE_USER,
+ R.styleable.AndroidManifestService_singleUser, sa)));
visibleToEphemeral = sa.getBoolean(
R.styleable.AndroidManifestService_visibleToInstantApps, false);
if (visibleToEphemeral) {
- service.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
+ service.setFlags(service.getFlags() | ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP);
pkg.setVisibleToInstantApps(true);
}
} finally {
@@ -139,7 +138,7 @@
parseResult = intentResult;
if (intentResult.isSuccess()) {
ParsedIntentInfo intent = intentResult.getResult();
- service.order = Math.max(intent.getOrder(), service.order);
+ service.setOrder(Math.max(intent.getOrder(), service.getOrder()));
service.addIntent(intent);
}
break;
@@ -172,7 +171,7 @@
return input.error(exportedCheckResult);
}
}
- service.exported = hasIntentFilters;
+ service.setExported(hasIntentFilters);
}
return input.success(service);
diff --git a/core/java/android/content/pm/parsing/component/ParsedUsesPermission.java b/core/java/android/content/pm/parsing/component/ParsedUsesPermission.java
index adf8da0..020784d 100644
--- a/core/java/android/content/pm/parsing/component/ParsedUsesPermission.java
+++ b/core/java/android/content/pm/parsing/component/ParsedUsesPermission.java
@@ -24,6 +24,9 @@
import android.os.Parcel;
import android.os.Parcelable;
+import com.android.internal.util.DataClass;
+import com.android.internal.util.Parcelling;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -33,50 +36,135 @@
*
* @hide
*/
+@DataClass(genGetters = true, genSetters = true, genBuilder = false, genParcelable = true,
+ genAidl = false)
public class ParsedUsesPermission implements Parcelable {
- /** Name of the permission requested */
- public @NonNull String name;
- /** Set of flags that should apply to this permission request. */
- public @UsesPermissionFlags int usesPermissionFlags;
+ @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedString.class)
+ @NonNull
+ private String name;
+
+ @UsesPermissionFlags
+ private int usesPermissionFlags;
/**
- * Strong assertion by a developer that they will never use this permission
- * to derive the physical location of the device, regardless of
- * ACCESS_FINE_LOCATION and/or ACCESS_COARSE_LOCATION being granted.
+ * Strong assertion by a developer that they will never use this permission to derive the
+ * physical location of the device, regardless of ACCESS_FINE_LOCATION and/or
+ * ACCESS_COARSE_LOCATION being granted.
*/
public static final int FLAG_NEVER_FOR_LOCATION =
PackageInfo.REQUESTED_PERMISSION_NEVER_FOR_LOCATION;
- /** @hide */
+ /**
+ * @hide
+ */
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag = true, prefix = { "FLAG_" }, value = {
FLAG_NEVER_FOR_LOCATION
})
public @interface UsesPermissionFlags {}
- public ParsedUsesPermission(@NonNull String name,
+
+
+ // Code below generated by codegen v1.0.23.
+ //
+ // DO NOT MODIFY!
+ // CHECKSTYLE:OFF Generated code
+ //
+ // To regenerate run:
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedUsesPermission.java
+ //
+ // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+ // Settings > Editor > Code Style > Formatter Control
+ //@formatter:off
+
+
+ @DataClass.Generated.Member
+ public ParsedUsesPermission(
+ @NonNull String name,
@UsesPermissionFlags int usesPermissionFlags) {
- this.name = name.intern();
+ this.name = name;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, name);
this.usesPermissionFlags = usesPermissionFlags;
+ com.android.internal.util.AnnotationValidations.validate(
+ UsesPermissionFlags.class, null, usesPermissionFlags);
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @DataClass.Generated.Member
+ public @NonNull String getName() {
+ return name;
+ }
+
+ @DataClass.Generated.Member
+ public @UsesPermissionFlags int getUsesPermissionFlags() {
+ return usesPermissionFlags;
+ }
+
+ @DataClass.Generated.Member
+ public @NonNull ParsedUsesPermission setName(@NonNull String value) {
+ name = value;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, name);
+ return this;
+ }
+
+ @DataClass.Generated.Member
+ public @NonNull ParsedUsesPermission setUsesPermissionFlags(@UsesPermissionFlags int value) {
+ usesPermissionFlags = value;
+ com.android.internal.util.AnnotationValidations.validate(
+ UsesPermissionFlags.class, null, usesPermissionFlags);
+ return this;
+ }
+
+ @DataClass.Generated.Member
+ static Parcelling<String> sParcellingForName =
+ Parcelling.Cache.get(
+ Parcelling.BuiltIn.ForInternedString.class);
+ static {
+ if (sParcellingForName == null) {
+ sParcellingForName = Parcelling.Cache.put(
+ new Parcelling.BuiltIn.ForInternedString());
+ }
}
@Override
+ @DataClass.Generated.Member
public void writeToParcel(@NonNull Parcel dest, int flags) {
- sForInternedString.parcel(this.name, dest, flags);
+ // You can override field parcelling by defining methods like:
+ // void parcelFieldName(Parcel dest, int flags) { ... }
+
+ sParcellingForName.parcel(name, dest, flags);
dest.writeInt(usesPermissionFlags);
}
@Override
- public int describeContents() {
- return 0;
- }
+ @DataClass.Generated.Member
+ public int describeContents() { return 0; }
+ /** @hide */
+ @SuppressWarnings({"unchecked", "RedundantCast"})
+ @DataClass.Generated.Member
protected ParsedUsesPermission(@NonNull Parcel in) {
- this.name = sForInternedString.unparcel(in);
- this.usesPermissionFlags = in.readInt();
+ // You can override field unparcelling by defining methods like:
+ // static FieldType unparcelFieldName(Parcel in) { ... }
+
+ String _name = sParcellingForName.unparcel(in);
+ int _usesPermissionFlags = in.readInt();
+
+ this.name = _name;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, name);
+ this.usesPermissionFlags = _usesPermissionFlags;
+ com.android.internal.util.AnnotationValidations.validate(
+ UsesPermissionFlags.class, null, usesPermissionFlags);
+
+ // onConstructed(); // You can define this method to get a callback
}
+ @DataClass.Generated.Member
public static final @NonNull Parcelable.Creator<ParsedUsesPermission> CREATOR
= new Parcelable.Creator<ParsedUsesPermission>() {
@Override
@@ -89,4 +177,17 @@
return new ParsedUsesPermission(in);
}
};
+
+ @DataClass.Generated(
+ time = 1626207990753L,
+ codegenVersion = "1.0.23",
+ sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedUsesPermission.java",
+ inputSignatures = "private @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.NonNull java.lang.String name\nprivate @android.content.pm.parsing.component.ParsedUsesPermission.UsesPermissionFlags int usesPermissionFlags\npublic static final int FLAG_NEVER_FOR_LOCATION\nclass ParsedUsesPermission extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=true, genAidl=false)")
+ @Deprecated
+ private void __metadata() {}
+
+
+ //@formatter:on
+ // End of generated code
+
}
diff --git a/core/java/android/content/pm/split/DefaultSplitAssetLoader.java b/core/java/android/content/pm/split/DefaultSplitAssetLoader.java
index c1a8396..47cf28b 100644
--- a/core/java/android/content/pm/split/DefaultSplitAssetLoader.java
+++ b/core/java/android/content/pm/split/DefaultSplitAssetLoader.java
@@ -15,10 +15,6 @@
*/
package android.content.pm.split;
-import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
-import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
-
-import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.parsing.ApkLiteParseUtils;
import android.content.pm.parsing.PackageLite;
import android.content.pm.parsing.ParsingPackageUtils;
@@ -52,23 +48,21 @@
}
private static ApkAssets loadApkAssets(String path, @ParseFlags int flags)
- throws PackageParserException {
+ throws IllegalArgumentException {
if ((flags & ParsingPackageUtils.PARSE_MUST_BE_APK) != 0
&& !ApkLiteParseUtils.isApkPath(path)) {
- throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
- "Invalid package file: " + path);
+ throw new IllegalArgumentException("Invalid package file: " + path);
}
try {
return ApkAssets.loadFromPath(path);
} catch (IOException e) {
- throw new PackageParserException(INSTALL_FAILED_INVALID_APK,
- "Failed to load APK at path " + path, e);
+ throw new IllegalArgumentException("Failed to load APK at path " + path, e);
}
}
@Override
- public AssetManager getBaseAssetManager() throws PackageParserException {
+ public AssetManager getBaseAssetManager() throws IllegalArgumentException {
if (mCachedAssetManager != null) {
return mCachedAssetManager;
}
@@ -97,7 +91,7 @@
}
@Override
- public AssetManager getSplitAssetManager(int splitIdx) throws PackageParserException {
+ public AssetManager getSplitAssetManager(int splitIdx) throws IllegalArgumentException {
return getBaseAssetManager();
}
diff --git a/core/java/android/content/pm/split/SplitAssetDependencyLoader.java b/core/java/android/content/pm/split/SplitAssetDependencyLoader.java
index e5c2158..2b9a17a 100644
--- a/core/java/android/content/pm/split/SplitAssetDependencyLoader.java
+++ b/core/java/android/content/pm/split/SplitAssetDependencyLoader.java
@@ -15,11 +15,7 @@
*/
package android.content.pm.split;
-import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
-
import android.annotation.NonNull;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.parsing.ApkLiteParseUtils;
import android.content.pm.parsing.PackageLite;
import android.content.pm.parsing.ParsingPackageUtils;
@@ -40,7 +36,7 @@
* is to be used when an application opts-in to isolated split loading.
* @hide
*/
-public class SplitAssetDependencyLoader extends SplitDependencyLoader<PackageParserException>
+public class SplitAssetDependencyLoader extends SplitDependencyLoader<IllegalArgumentException>
implements SplitAssetLoader {
private final String[] mSplitPaths;
private final @ParseFlags int mFlags;
@@ -67,18 +63,16 @@
}
private static ApkAssets loadApkAssets(String path, @ParseFlags int flags)
- throws PackageParserException {
+ throws IllegalArgumentException {
if ((flags & ParsingPackageUtils.PARSE_MUST_BE_APK) != 0
&& !ApkLiteParseUtils.isApkPath(path)) {
- throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
- "Invalid package file: " + path);
+ throw new IllegalArgumentException("Invalid package file: " + path);
}
try {
return ApkAssets.loadFromPath(path);
} catch (IOException e) {
- throw new PackageParserException(PackageManager.INSTALL_FAILED_INVALID_APK,
- "Failed to load APK at path " + path, e);
+ throw new IllegalArgumentException("Failed to load APK at path " + path, e);
}
}
@@ -92,7 +86,7 @@
@Override
protected void constructSplit(int splitIdx, @NonNull int[] configSplitIndices,
- int parentSplitIdx) throws PackageParserException {
+ int parentSplitIdx) throws IllegalArgumentException {
final ArrayList<ApkAssets> assets = new ArrayList<>();
// Include parent ApkAssets.
@@ -114,13 +108,13 @@
}
@Override
- public AssetManager getBaseAssetManager() throws PackageParserException {
+ public AssetManager getBaseAssetManager() throws IllegalArgumentException {
loadDependenciesForSplit(0);
return mCachedAssetManagers[0];
}
@Override
- public AssetManager getSplitAssetManager(int idx) throws PackageParserException {
+ public AssetManager getSplitAssetManager(int idx) throws IllegalArgumentException {
// Since we insert the base at position 0, and PackageParser keeps splits separate from
// the base, we need to adjust the index.
loadDependenciesForSplit(idx + 1);
diff --git a/core/java/android/content/pm/split/SplitAssetLoader.java b/core/java/android/content/pm/split/SplitAssetLoader.java
index 7584e15f..d314e06 100644
--- a/core/java/android/content/pm/split/SplitAssetLoader.java
+++ b/core/java/android/content/pm/split/SplitAssetLoader.java
@@ -15,19 +15,18 @@
*/
package android.content.pm.split;
-import android.content.pm.PackageParser;
import android.content.res.ApkAssets;
import android.content.res.AssetManager;
/**
- * Simple interface for loading base Assets and Splits. Used by PackageParser when parsing
+ * Simple interface for loading base Assets and Splits. Used by ParsingPackageUtils when parsing
* split APKs.
*
* @hide
*/
public interface SplitAssetLoader extends AutoCloseable {
- AssetManager getBaseAssetManager() throws PackageParser.PackageParserException;
- AssetManager getSplitAssetManager(int splitIdx) throws PackageParser.PackageParserException;
+ AssetManager getBaseAssetManager() throws IllegalArgumentException;
+ AssetManager getSplitAssetManager(int splitIdx) throws IllegalArgumentException;
ApkAssets getBaseApkAssets();
}
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 9501994..d9fa56e 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -991,13 +991,27 @@
* camera's crop region is set to maximum size, the FOV of the physical streams for the
* ultrawide lens will be the same as the logical stream, by making the crop region
* smaller than its active array size to compensate for the smaller focal length.</p>
- * <p>Even if the underlying physical cameras have different RAW characteristics (such as
- * size or CFA pattern), a logical camera can still advertise RAW capability. In this
- * case, when the application configures a RAW stream, the camera device will make sure
- * the active physical camera will remain active to ensure consistent RAW output
- * behavior, and not switch to other physical cameras.</p>
+ * <p>There are two ways for the application to capture RAW images from a logical camera
+ * with RAW capability:</p>
+ * <ul>
+ * <li>Because the underlying physical cameras may have different RAW capabilities (such
+ * as resolution or CFA pattern), to maintain backward compatibility, when a RAW stream
+ * is configured, the camera device makes sure the default active physical camera remains
+ * active and does not switch to other physical cameras. (One exception is that, if the
+ * logical camera consists of identical image sensors and advertises multiple focalLength
+ * due to different lenses, the camera device may generate RAW images from different
+ * physical cameras based on the focalLength being set by the application.) This
+ * backward-compatible approach usually results in loss of optical zoom, to telephoto
+ * lens or to ultrawide lens.</li>
+ * <li>Alternatively, to take advantage of the full zoomRatio range of the logical camera,
+ * the application should use {@link android.hardware.camera2.MultiResolutionImageReader }
+ * to capture RAW images from the currently active physical camera. Because different
+ * physical camera may have different RAW characteristics, the application needs to use
+ * the characteristics and result metadata of the active physical camera for the
+ * relevant RAW metadata.</li>
+ * </ul>
* <p>The capture request and result metadata tags required for backward compatible camera
- * functionalities will be solely based on the logical camera capabiltity. On the other
+ * functionalities will be solely based on the logical camera capability. On the other
* hand, the use of manual capture controls (sensor or post-processing) with a
* logical camera may result in unexpected behavior when the HAL decides to switch
* between physical cameras with different characteristics under the hood. For example,
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index 12557f9..c2a2c4c 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -74,7 +74,7 @@
private final IFaceService mService;
private final Context mContext;
- private IBinder mToken = new Binder();
+ private final IBinder mToken = new Binder();
@Nullable private AuthenticationCallback mAuthenticationCallback;
@Nullable private FaceDetectionCallback mFaceDetectionCallback;
@Nullable private EnrollmentCallback mEnrollmentCallback;
@@ -86,7 +86,7 @@
private Face mRemovalFace;
private Handler mHandler;
- private IFaceServiceReceiver mServiceReceiver = new IFaceServiceReceiver.Stub() {
+ private final IFaceServiceReceiver mServiceReceiver = new IFaceServiceReceiver.Stub() {
@Override // binder call
public void onEnrollResult(Face face, int remaining) {
@@ -293,7 +293,7 @@
/**
* Defaults to {@link FaceManager#enroll(int, byte[], CancellationSignal, EnrollmentCallback,
- * int[], Surface)} with {@code surface} set to null.
+ * int[], Surface)} with {@code previewSurface} set to null.
*
* @see FaceManager#enroll(int, byte[], CancellationSignal, EnrollmentCallback, int[], Surface)
* @hide
@@ -301,8 +301,8 @@
@RequiresPermission(MANAGE_BIOMETRIC)
public void enroll(int userId, byte[] hardwareAuthToken, CancellationSignal cancel,
EnrollmentCallback callback, int[] disabledFeatures) {
- enroll(userId, hardwareAuthToken, cancel, callback, disabledFeatures, null /* surface */,
- false /* debugConsent */);
+ enroll(userId, hardwareAuthToken, cancel, callback, disabledFeatures,
+ null /* previewSurface */, false /* debugConsent */);
}
/**
@@ -319,14 +319,14 @@
* @param cancel an object that can be used to cancel enrollment
* @param userId the user to whom this face will belong to
* @param callback an object to receive enrollment events
- * @param surface optional camera preview surface for a single-camera device.
+ * @param previewSurface optional camera preview surface for a single-camera device.
* Must be null if not used.
* @param debugConsent a feature flag that the user has consented to debug.
* @hide
*/
@RequiresPermission(MANAGE_BIOMETRIC)
public void enroll(int userId, byte[] hardwareAuthToken, CancellationSignal cancel,
- EnrollmentCallback callback, int[] disabledFeatures, @Nullable Surface surface,
+ EnrollmentCallback callback, int[] disabledFeatures, @Nullable Surface previewSurface,
boolean debugConsent) {
if (callback == null) {
throw new IllegalArgumentException("Must supply an enrollment callback");
@@ -346,7 +346,8 @@
mEnrollmentCallback = callback;
Trace.beginSection("FaceManager#enroll");
mService.enroll(userId, mToken, hardwareAuthToken, mServiceReceiver,
- mContext.getOpPackageName(), disabledFeatures, surface, debugConsent);
+ mContext.getOpPackageName(), disabledFeatures, previewSurface,
+ debugConsent);
} catch (RemoteException e) {
Slog.w(TAG, "Remote exception in enroll: ", e);
// Though this may not be a hardware issue, it will cause apps to give up or
@@ -853,10 +854,10 @@
* @hide
*/
public static class AuthenticationResult {
- private Face mFace;
- private CryptoObject mCryptoObject;
- private int mUserId;
- private boolean mIsStrongBiometric;
+ private final Face mFace;
+ private final CryptoObject mCryptoObject;
+ private final int mUserId;
+ private final boolean mIsStrongBiometric;
/**
* Authentication result
@@ -1127,7 +1128,7 @@
}
private class OnAuthenticationCancelListener implements OnCancelListener {
- private CryptoObject mCrypto;
+ private final CryptoObject mCrypto;
OnAuthenticationCancelListener(CryptoObject crypto) {
mCrypto = crypto;
diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl
index 270d662..b9a49c6 100644
--- a/core/java/android/hardware/face/IFaceService.aidl
+++ b/core/java/android/hardware/face/IFaceService.aidl
@@ -75,7 +75,7 @@
// Start face enrollment
void enroll(int userId, IBinder token, in byte [] hardwareAuthToken, IFaceServiceReceiver receiver,
- String opPackageName, in int [] disabledFeatures, in Surface surface, boolean debugConsent);
+ String opPackageName, in int [] disabledFeatures, in Surface previewSurface, boolean debugConsent);
// Start remote face enrollment
void enrollRemotely(int userId, IBinder token, in byte [] hardwareAuthToken, IFaceServiceReceiver receiver,
diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java
index 5a25cfc..ae8d010 100644
--- a/core/java/android/net/nsd/NsdManager.java
+++ b/core/java/android/net/nsd/NsdManager.java
@@ -23,6 +23,9 @@
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemService;
+import android.app.compat.CompatChanges;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
import android.content.Context;
import android.os.Handler;
import android.os.HandlerThread;
@@ -126,6 +129,24 @@
private static final boolean DBG = false;
/**
+ * When enabled, apps targeting < Android 12 are considered legacy for
+ * the NSD native daemon.
+ * The platform will only keep the daemon running as long as there are
+ * any legacy apps connected.
+ *
+ * After Android 12, directly communicate with native daemon might not
+ * work since the native damon won't always stay alive.
+ * Use the NSD APIs from NsdManager as the replacement is recommended.
+ * An another alternative could be bundling your own mdns solutions instead of
+ * depending on the system mdns native daemon.
+ *
+ * @hide
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.S)
+ public static final long RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS = 191844585L;
+
+ /**
* Broadcast intent action to indicate whether network service discovery is
* enabled or disabled. An extra {@link #EXTRA_NSD_STATE} provides the state
* information as int.
@@ -203,6 +224,9 @@
public static final int DAEMON_CLEANUP = BASE + 21;
/** @hide */
+ public static final int DAEMON_STARTUP = BASE + 22;
+
+ /** @hide */
public static final int ENABLE = BASE + 24;
/** @hide */
public static final int DISABLE = BASE + 25;
@@ -232,6 +256,8 @@
EVENT_NAMES.put(RESOLVE_SERVICE, "RESOLVE_SERVICE");
EVENT_NAMES.put(RESOLVE_SERVICE_FAILED, "RESOLVE_SERVICE_FAILED");
EVENT_NAMES.put(RESOLVE_SERVICE_SUCCEEDED, "RESOLVE_SERVICE_SUCCEEDED");
+ EVENT_NAMES.put(DAEMON_CLEANUP, "DAEMON_CLEANUP");
+ EVENT_NAMES.put(DAEMON_STARTUP, "DAEMON_STARTUP");
EVENT_NAMES.put(ENABLE, "ENABLE");
EVENT_NAMES.put(DISABLE, "DISABLE");
EVENT_NAMES.put(NATIVE_DAEMON_EVENT, "NATIVE_DAEMON_EVENT");
@@ -494,6 +520,12 @@
} catch (InterruptedException e) {
fatal("Interrupted wait at init");
}
+ if (CompatChanges.isChangeEnabled(RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)) {
+ return;
+ }
+ // Only proactively start the daemon if the target SDK < S, otherwise the internal service
+ // would automatically start/stop the native daemon as needed.
+ mAsyncChannel.sendMessage(DAEMON_STARTUP);
}
private static void fatal(String msg) {
diff --git a/core/java/android/os/DropBoxManager.java b/core/java/android/os/DropBoxManager.java
index 575fc4c..f38271a 100644
--- a/core/java/android/os/DropBoxManager.java
+++ b/core/java/android/os/DropBoxManager.java
@@ -72,7 +72,7 @@
/** Flag value: Content is human-readable UTF-8 text (can be combined with IS_GZIPPED). */
public static final int IS_TEXT = 2;
- /** Flag value: Content can be decompressed with {@link java.util.zip.GZIPOutputStream}. */
+ /** Flag value: Content can be decompressed with java.util.zip.GZIPOutputStream. */
public static final int IS_GZIPPED = 4;
/** Flag value for serialization only: Value is a byte array, not a file descriptor */
diff --git a/core/java/android/os/PerformanceHintManager.java b/core/java/android/os/PerformanceHintManager.java
index 6791844..a75b5ef 100644
--- a/core/java/android/os/PerformanceHintManager.java
+++ b/core/java/android/os/PerformanceHintManager.java
@@ -24,24 +24,23 @@
import com.android.internal.util.Preconditions;
import java.io.Closeable;
-import java.util.ArrayList;
/** The PerformanceHintManager allows apps to send performance hint to system. */
@SystemService(Context.PERFORMANCE_HINT_SERVICE)
public final class PerformanceHintManager {
- private static final String TAG = "PerformanceHintManager";
- private final IHintManager mService;
- // HAL preferred update rate
- private final long mPreferredRate;
+ private final long mNativeManagerPtr;
/** @hide */
- public PerformanceHintManager(IHintManager service) {
- mService = service;
- try {
- mPreferredRate = mService.getHintSessionPreferredRate();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ public static PerformanceHintManager create() throws ServiceManager.ServiceNotFoundException {
+ long nativeManagerPtr = nativeAcquireManager();
+ if (nativeManagerPtr == 0) {
+ throw new ServiceManager.ServiceNotFoundException(Context.PERFORMANCE_HINT_SERVICE);
}
+ return new PerformanceHintManager(nativeManagerPtr);
+ }
+
+ private PerformanceHintManager(long nativeManagerPtr) {
+ mNativeManagerPtr = nativeManagerPtr;
}
/**
@@ -57,16 +56,13 @@
*/
@Nullable
public Session createHintSession(@NonNull int[] tids, long initialTargetWorkDurationNanos) {
- try {
- IBinder token = new Binder();
- IHintSession session = mService.createHintSession(token, tids,
- initialTargetWorkDurationNanos);
- if (session == null) return null;
- return new Session(session, sNanoClock, mPreferredRate,
- initialTargetWorkDurationNanos);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ Preconditions.checkNotNull(tids, "tids cannot be null");
+ Preconditions.checkArgumentPositive(initialTargetWorkDurationNanos,
+ "the hint target duration should be positive.");
+ long nativeSessionPtr = nativeCreateSession(mNativeManagerPtr, tids,
+ initialTargetWorkDurationNanos);
+ if (nativeSessionPtr == 0) return null;
+ return new Session(nativeSessionPtr);
}
/**
@@ -75,7 +71,7 @@
* @return the preferred update rate supported by device software.
*/
public long getPreferredUpdateRateNanos() {
- return mPreferredRate;
+ return nativeGetPreferredUpdateRateNanos(mNativeManagerPtr);
}
/**
@@ -101,28 +97,21 @@
* <p>All timings should be in {@link SystemClock#elapsedRealtimeNanos()}.</p>
*/
public static class Session implements Closeable {
- private final IHintSession mSession;
- private final NanoClock mElapsedRealtimeClock;
- // Target duration for choosing update rate
- private long mTargetDurationInNanos;
- // HAL preferred update rate
- private long mPreferredRate;
- // Last update timestamp
- private long mLastUpdateTimeStamp = -1L;
- // Cached samples
- private final ArrayList<Long> mActualDurationNanos;
- private final ArrayList<Long> mTimeStampNanos;
+ private long mNativeSessionPtr;
/** @hide */
- public Session(IHintSession session, NanoClock elapsedRealtimeClock, long preferredRate,
- long durationNanos) {
- mSession = session;
- mElapsedRealtimeClock = elapsedRealtimeClock;
- mTargetDurationInNanos = durationNanos;
- mPreferredRate = preferredRate;
- mActualDurationNanos = new ArrayList<Long>();
- mTimeStampNanos = new ArrayList<Long>();
- mLastUpdateTimeStamp = mElapsedRealtimeClock.nanos();
+ public Session(long nativeSessionPtr) {
+ mNativeSessionPtr = nativeSessionPtr;
+ }
+
+ /** @hide */
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ close();
+ } finally {
+ super.finalize();
+ }
}
/**
@@ -133,19 +122,7 @@
public void updateTargetWorkDuration(long targetDurationNanos) {
Preconditions.checkArgumentPositive(targetDurationNanos, "the hint target duration"
+ " should be positive.");
- try {
- mSession.updateTargetWorkDuration(targetDurationNanos);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- mTargetDurationInNanos = targetDurationNanos;
- /**
- * Most of the workload is target_duration dependent, so now clear the cached samples
- * as they are most likely obsolete.
- */
- mActualDurationNanos.clear();
- mTimeStampNanos.clear();
- mLastUpdateTimeStamp = mElapsedRealtimeClock.nanos();
+ nativeUpdateTargetWorkDuration(mNativeSessionPtr, targetDurationNanos);
}
/**
@@ -161,38 +138,7 @@
public void reportActualWorkDuration(long actualDurationNanos) {
Preconditions.checkArgumentPositive(actualDurationNanos, "the actual duration should"
+ " be positive.");
- final long now = mElapsedRealtimeClock.nanos();
- mActualDurationNanos.add(actualDurationNanos);
- mTimeStampNanos.add(now);
-
- /**
- * Use current sample to determine the rate limit. We can pick a shorter rate limit
- * if any sample underperformed, however, it could be the lower level system is slow
- * to react. So here we explicitly choose the rate limit with the latest sample.
- */
- long rateLimit =
- actualDurationNanos > mTargetDurationInNanos ? mPreferredRate
- : 10 * mPreferredRate;
-
- if (now - mLastUpdateTimeStamp <= rateLimit) {
- return;
- }
- Preconditions.checkState(mActualDurationNanos.size() == mTimeStampNanos.size());
- final int size = mActualDurationNanos.size();
- long[] actualDurationArray = new long[size];
- long[] timeStampArray = new long[size];
- for (int i = 0; i < size; i++) {
- actualDurationArray[i] = mActualDurationNanos.get(i);
- timeStampArray[i] = mTimeStampNanos.get(i);
- }
- try {
- mSession.reportActualWorkDuration(actualDurationArray, timeStampArray);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- mActualDurationNanos.clear();
- mTimeStampNanos.clear();
- mLastUpdateTimeStamp = now;
+ nativeReportActualWorkDuration(mNativeSessionPtr, actualDurationNanos);
}
/**
@@ -201,26 +147,20 @@
* <p>Once called, you should not call anything else on this object.</p>
*/
public void close() {
- try {
- mSession.close();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ if (mNativeSessionPtr != 0) {
+ nativeCloseSession(mNativeSessionPtr);
+ mNativeSessionPtr = 0;
}
}
}
- /**
- * The interface is to make the FakeClock for testing.
- * @hide
- */
- public interface NanoClock {
- /** Gets the current nanosecond instant of the clock. */
- long nanos();
- }
-
- private static final NanoClock sNanoClock = new NanoClock() {
- public long nanos() {
- return SystemClock.elapsedRealtimeNanos();
- }
- };
+ private static native long nativeAcquireManager();
+ private static native long nativeGetPreferredUpdateRateNanos(long nativeManagerPtr);
+ private static native long nativeCreateSession(long nativeManagerPtr,
+ int[] tids, long initialTargetWorkDurationNanos);
+ private static native void nativeUpdateTargetWorkDuration(long nativeSessionPtr,
+ long targetDurationNanos);
+ private static native void nativeReportActualWorkDuration(long nativeSessionPtr,
+ long actualDurationNanos);
+ private static native void nativeCloseSession(long nativeSessionPtr);
}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 8709f07..09b7aaa 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -2491,6 +2491,10 @@
throw re.rethrowFromSystemServer();
}
}
+ @Override
+ protected boolean bypass(Integer query) {
+ return query < 0;
+ }
};
// Uses IS_USER_UNLOCKED_PROPERTY for invalidation as the APIs have the same dependencies.
@@ -2505,6 +2509,10 @@
throw re.rethrowFromSystemServer();
}
}
+ @Override
+ protected boolean bypass(Integer query) {
+ return query < 0;
+ }
};
/** {@hide} */
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 880d03a..ded598a 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -846,8 +846,8 @@
/**
* Delete a property with the provided name and value in the provided namespace
*
- * @param namespace The namespace containing the property to create or update.
- * @param name The name of the property to create or update.
+ * @param namespace The namespace containing the property to delete.
+ * @param name The name of the property to delete.
* @return True if the property was deleted or it did not exist in the first place.
* False if the storage implementation throws errors.
* @hide
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index d283bd1..7376ac5 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4000,6 +4000,16 @@
public static final int ADVANCED_SETTINGS_DEFAULT = 0;
/**
+ * If the triple press gesture for toggling accessibility is enabled.
+ * Set to 1 for true and 0 for false.
+ *
+ * This setting is used only internally.
+ * @hide
+ */
+ public static final String WEAR_ACCESSIBILITY_GESTURE_ENABLED
+ = "wear_accessibility_gesture_enabled";
+
+ /**
* @deprecated Use {@link android.provider.Settings.Global#AIRPLANE_MODE_ON} instead
*/
@Deprecated
@@ -5261,6 +5271,7 @@
PRIVATE_SETTINGS.add(WIFI_USE_STATIC_IP);
PRIVATE_SETTINGS.add(END_BUTTON_BEHAVIOR);
PRIVATE_SETTINGS.add(ADVANCED_SETTINGS);
+ PRIVATE_SETTINGS.add(WEAR_ACCESSIBILITY_GESTURE_ENABLED);
PRIVATE_SETTINGS.add(SCREEN_AUTO_BRIGHTNESS_ADJ);
PRIVATE_SETTINGS.add(VIBRATE_INPUT_DEVICES);
PRIVATE_SETTINGS.add(VOLUME_MASTER);
@@ -9985,15 +9996,18 @@
/**
* Controls the accessibility button mode. System will force-set the value to {@link
- * #ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU} if {@link #NAVIGATION_MODE} is fully
- * gestural.
+ * #ACCESSIBILITY_BUTTON_MODE_GESTURE} if {@link #NAVIGATION_MODE} is button; force-set the
+ * value to {@link ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR} if {@link #NAVIGATION_MODE} is
+ * gestural; otherwise, remain the option.
* <ul>
* <li> 0 = button in navigation bar </li>
* <li> 1 = button floating on the display </li>
+ * <li> 2 = button using gesture to trigger </li>
* </ul>
*
* @see #ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR
* @see #ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU
+ * @see #ACCESSIBILITY_BUTTON_MODE_GESTURE
* @hide
*/
public static final String ACCESSIBILITY_BUTTON_MODE =
@@ -10016,6 +10030,14 @@
public static final int ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU = 0x1;
/**
+ * Accessibility button mode value that specifying the accessibility service or feature to
+ * be toggled via the gesture.
+ *
+ * @hide
+ */
+ public static final int ACCESSIBILITY_BUTTON_MODE_GESTURE = 0x2;
+
+ /**
* The size of the accessibility floating menu.
* <ul>
* <li> 0 = small size
@@ -16666,6 +16688,12 @@
* @hide
*/
public static final String SETUP_LOCALE = "setup_locale";
+
+ /**
+ * The version of oem setup present.
+ * @hide
+ */
+ public static final String OEM_SETUP_VERSION = "oem_setup_version";
}
}
diff --git a/core/java/android/util/ArraySet.java b/core/java/android/util/ArraySet.java
index f53548a..b5c75b9 100644
--- a/core/java/android/util/ArraySet.java
+++ b/core/java/android/util/ArraySet.java
@@ -28,6 +28,7 @@
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
+import java.util.function.Consumer;
import java.util.function.Predicate;
/**
@@ -747,6 +748,23 @@
return mSize;
}
+ /**
+ * Performs the given action for all elements in the stored order. This implementation overrides
+ * the default implementation to avoid using the {@link #iterator()}.
+ *
+ * @param action The action to be performed for each element
+ */
+ @Override
+ public void forEach(Consumer<? super E> action) {
+ if (action == null) {
+ throw new NullPointerException("action must not be null");
+ }
+
+ for (int i = 0; i < mSize; ++i) {
+ action.accept(valueAt(i));
+ }
+ }
+
@Override
public Object[] toArray() {
Object[] result = new Object[mSize];
diff --git a/core/java/android/util/apk/ApkSignatureVerifier.java b/core/java/android/util/apk/ApkSignatureVerifier.java
index 0c04976..35c602a 100644
--- a/core/java/android/util/apk/ApkSignatureVerifier.java
+++ b/core/java/android/util/apk/ApkSignatureVerifier.java
@@ -23,11 +23,12 @@
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
-import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.Signature;
import android.content.pm.SigningDetails;
import android.content.pm.SigningDetails.SignatureSchemeVersion;
import android.content.pm.parsing.ParsingPackageUtils;
+import android.content.pm.parsing.result.ParseInput;
+import android.content.pm.parsing.result.ParseResult;
import android.os.Build;
import android.os.Trace;
import android.util.jar.StrictJarFile;
@@ -52,7 +53,7 @@
/**
* Facade class that takes care of the details of APK verification on
- * behalf of PackageParser.
+ * behalf of ParsingPackageUtils.
*
* @hide for internal use only.
*/
@@ -62,90 +63,85 @@
/**
* Verifies the provided APK and returns the certificates associated with each signer.
- *
- * @throws PackageParserException if the APK's signature failed to verify.
*/
- public static SigningDetails verify(String apkPath,
- @SignatureSchemeVersion int minSignatureSchemeVersion)
- throws PackageParserException {
- return verifySignatures(apkPath, minSignatureSchemeVersion, true);
+ public static ParseResult<SigningDetails> verify(ParseInput input, String apkPath,
+ @SignatureSchemeVersion int minSignatureSchemeVersion) {
+ return verifySignatures(input, apkPath, minSignatureSchemeVersion, true /* verifyFull */);
}
/**
* Returns the certificates associated with each signer for the given APK without verification.
* This method is dangerous and should not be used, unless the caller is absolutely certain the
* APK is trusted.
- *
- * @throws PackageParserException if there was a problem collecting certificates.
*/
- public static SigningDetails unsafeGetCertsWithoutVerification(
- String apkPath, int minSignatureSchemeVersion)
- throws PackageParserException {
- return verifySignatures(apkPath, minSignatureSchemeVersion, false);
+ public static ParseResult<SigningDetails> unsafeGetCertsWithoutVerification(
+ ParseInput input, String apkPath, int minSignatureSchemeVersion) {
+ return verifySignatures(input, apkPath, minSignatureSchemeVersion, false /* verifyFull */);
}
/**
* Verifies the provided APK using all allowed signing schemas.
* @return the certificates associated with each signer.
* @param verifyFull whether to verify all contents of this APK or just collect certificates.
- * @throws PackageParserException if there was a problem collecting certificates
*/
- private static SigningDetails verifySignatures(String apkPath,
- @SignatureSchemeVersion int minSignatureSchemeVersion, boolean verifyFull)
- throws PackageParserException {
- return verifySignaturesInternal(apkPath, minSignatureSchemeVersion,
- verifyFull).signingDetails;
+ private static ParseResult<SigningDetails> verifySignatures(ParseInput input, String apkPath,
+ @SignatureSchemeVersion int minSignatureSchemeVersion, boolean verifyFull) {
+ final ParseResult<SigningDetailsWithDigests> result =
+ verifySignaturesInternal(input, apkPath, minSignatureSchemeVersion, verifyFull);
+ if (result.isError()) {
+ return input.error(result);
+ }
+ return input.success(result.getResult().signingDetails);
}
/**
* Verifies the provided APK using all allowed signing schemas.
* @return the certificates associated with each signer and content digests.
* @param verifyFull whether to verify all contents of this APK or just collect certificates.
- * @throws PackageParserException if there was a problem collecting certificates
* @hide
*/
- public static SigningDetailsWithDigests verifySignaturesInternal(String apkPath,
- @SignatureSchemeVersion int minSignatureSchemeVersion, boolean verifyFull)
- throws PackageParserException {
+ public static ParseResult<SigningDetailsWithDigests> verifySignaturesInternal(ParseInput input,
+ String apkPath, @SignatureSchemeVersion int minSignatureSchemeVersion,
+ boolean verifyFull) {
if (minSignatureSchemeVersion > SignatureSchemeVersion.SIGNING_BLOCK_V4) {
- // V3 and before are older than the requested minimum signing version
- throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
+ // V4 and before are older than the requested minimum signing version
+ return input.error(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
"No signature found in package of version " + minSignatureSchemeVersion
+ " or newer for package " + apkPath);
}
// first try v4
try {
- return verifyV4Signature(apkPath, minSignatureSchemeVersion, verifyFull);
+ return verifyV4Signature(input, apkPath, minSignatureSchemeVersion, verifyFull);
} catch (SignatureNotFoundException e) {
// not signed with v4, try older if allowed
if (minSignatureSchemeVersion >= SignatureSchemeVersion.SIGNING_BLOCK_V4) {
- throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
+ return input.error(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
"No APK Signature Scheme v4 signature in package " + apkPath, e);
}
}
if (minSignatureSchemeVersion > SignatureSchemeVersion.SIGNING_BLOCK_V3) {
// V3 and before are older than the requested minimum signing version
- throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
+ return input.error(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
"No signature found in package of version " + minSignatureSchemeVersion
+ " or newer for package " + apkPath);
}
- return verifyV3AndBelowSignatures(apkPath, minSignatureSchemeVersion, verifyFull);
+ return verifyV3AndBelowSignatures(input, apkPath, minSignatureSchemeVersion, verifyFull);
}
- private static SigningDetailsWithDigests verifyV3AndBelowSignatures(String apkPath,
- @SignatureSchemeVersion int minSignatureSchemeVersion, boolean verifyFull)
- throws PackageParserException {
+ private static ParseResult<SigningDetailsWithDigests> verifyV3AndBelowSignatures(
+ ParseInput input, String apkPath, @SignatureSchemeVersion int minSignatureSchemeVersion,
+ boolean verifyFull) {
// try v3
try {
- return verifyV3Signature(apkPath, verifyFull);
+ return verifyV3Signature(input, apkPath, verifyFull);
} catch (SignatureNotFoundException e) {
// not signed with v3, try older if allowed
if (minSignatureSchemeVersion >= SignatureSchemeVersion.SIGNING_BLOCK_V3) {
- throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
+ return input.error(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
"No APK Signature Scheme v3 signature in package " + apkPath, e);
}
}
@@ -153,18 +149,18 @@
// redundant, protective version check
if (minSignatureSchemeVersion > SignatureSchemeVersion.SIGNING_BLOCK_V2) {
// V2 and before are older than the requested minimum signing version
- throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
+ return input.error(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
"No signature found in package of version " + minSignatureSchemeVersion
+ " or newer for package " + apkPath);
}
// try v2
try {
- return verifyV2Signature(apkPath, verifyFull);
+ return verifyV2Signature(input, apkPath, verifyFull);
} catch (SignatureNotFoundException e) {
// not signed with v2, try older if allowed
if (minSignatureSchemeVersion >= SignatureSchemeVersion.SIGNING_BLOCK_V2) {
- throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
+ return input.error(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
"No APK Signature Scheme v2 signature in package " + apkPath, e);
}
}
@@ -172,13 +168,13 @@
// redundant, protective version check
if (minSignatureSchemeVersion > SignatureSchemeVersion.JAR) {
// V1 and is older than the requested minimum signing version
- throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
+ return input.error(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
"No signature found in package of version " + minSignatureSchemeVersion
+ " or newer for package " + apkPath);
}
// v2 didn't work, try jarsigner
- return verifyV1Signature(apkPath, verifyFull);
+ return verifyV1Signature(input, apkPath, verifyFull);
}
/**
@@ -187,11 +183,10 @@
* @param verifyFull whether to verify (V4 vs V3) or just collect certificates.
* @return the certificates associated with each signer.
* @throws SignatureNotFoundException if there are no V4 signatures in the APK
- * @throws PackageParserException if there was a problem collecting certificates
*/
- private static SigningDetailsWithDigests verifyV4Signature(String apkPath,
- @SignatureSchemeVersion int minSignatureSchemeVersion, boolean verifyFull)
- throws SignatureNotFoundException, PackageParserException {
+ private static ParseResult<SigningDetailsWithDigests> verifyV4Signature(ParseInput input,
+ String apkPath, @SignatureSchemeVersion int minSignatureSchemeVersion,
+ boolean verifyFull) throws SignatureNotFoundException {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, verifyFull ? "verifyV4" : "certsOnlyV4");
try {
ApkSignatureSchemeV4Verifier.VerifiedSigner vSigner =
@@ -259,14 +254,14 @@
}
}
- return new SigningDetailsWithDigests(new SigningDetails(signerSigs,
+ return input.success(new SigningDetailsWithDigests(new SigningDetails(signerSigs,
SignatureSchemeVersion.SIGNING_BLOCK_V4, pastSignerSigs),
- vSigner.contentDigests);
+ vSigner.contentDigests));
} catch (SignatureNotFoundException e) {
throw e;
} catch (Exception e) {
// APK Signature Scheme v4 signature found but did not verify
- throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
+ return input.error(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
"Failed to collect certificates from " + apkPath
+ " using APK Signature Scheme v4", e);
} finally {
@@ -280,10 +275,9 @@
* @param verifyFull whether to verify all contents of this APK or just collect certificates.
* @return the certificates associated with each signer.
* @throws SignatureNotFoundException if there are no V3 signatures in the APK
- * @throws PackageParserException if there was a problem collecting certificates
*/
- private static SigningDetailsWithDigests verifyV3Signature(String apkPath, boolean verifyFull)
- throws SignatureNotFoundException, PackageParserException {
+ private static ParseResult<SigningDetailsWithDigests> verifyV3Signature(ParseInput input,
+ String apkPath, boolean verifyFull) throws SignatureNotFoundException {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, verifyFull ? "verifyV3" : "certsOnlyV3");
try {
ApkSignatureSchemeV3Verifier.VerifiedSigner vSigner =
@@ -301,14 +295,14 @@
pastSignerSigs[i].setFlags(vSigner.por.flagsList.get(i));
}
}
- return new SigningDetailsWithDigests(new SigningDetails(signerSigs,
+ return input.success(new SigningDetailsWithDigests(new SigningDetails(signerSigs,
SignatureSchemeVersion.SIGNING_BLOCK_V3, pastSignerSigs),
- vSigner.contentDigests);
+ vSigner.contentDigests));
} catch (SignatureNotFoundException e) {
throw e;
} catch (Exception e) {
// APK Signature Scheme v3 signature found but did not verify
- throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
+ return input.error(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
"Failed to collect certificates from " + apkPath
+ " using APK Signature Scheme v3", e);
} finally {
@@ -322,23 +316,22 @@
* @param verifyFull whether to verify all contents of this APK or just collect certificates.
* @return the certificates associated with each signer.
* @throws SignatureNotFoundException if there are no V2 signatures in the APK
- * @throws PackageParserException if there was a problem collecting certificates
*/
- private static SigningDetailsWithDigests verifyV2Signature(String apkPath, boolean verifyFull)
- throws SignatureNotFoundException, PackageParserException {
+ private static ParseResult<SigningDetailsWithDigests> verifyV2Signature(ParseInput input,
+ String apkPath, boolean verifyFull) throws SignatureNotFoundException {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, verifyFull ? "verifyV2" : "certsOnlyV2");
try {
ApkSignatureSchemeV2Verifier.VerifiedSigner vSigner =
ApkSignatureSchemeV2Verifier.verify(apkPath, verifyFull);
Certificate[][] signerCerts = vSigner.certs;
Signature[] signerSigs = convertToSignatures(signerCerts);
- return new SigningDetailsWithDigests(new SigningDetails(signerSigs,
- SignatureSchemeVersion.SIGNING_BLOCK_V2), vSigner.contentDigests);
+ return input.success(new SigningDetailsWithDigests(new SigningDetails(signerSigs,
+ SignatureSchemeVersion.SIGNING_BLOCK_V2), vSigner.contentDigests));
} catch (SignatureNotFoundException e) {
throw e;
} catch (Exception e) {
// APK Signature Scheme v2 signature found but did not verify
- throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
+ return input.error(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
"Failed to collect certificates from " + apkPath
+ " using APK Signature Scheme v2", e);
} finally {
@@ -350,10 +343,9 @@
* Verifies the provided APK using JAR schema.
* @return the certificates associated with each signer.
* @param verifyFull whether to verify all contents of this APK or just collect certificates.
- * @throws PackageParserException if there was a problem collecting certificates
*/
- private static SigningDetailsWithDigests verifyV1Signature(String apkPath, boolean verifyFull)
- throws PackageParserException {
+ private static ParseResult<SigningDetailsWithDigests> verifyV1Signature(ParseInput input,
+ String apkPath, boolean verifyFull) {
StrictJarFile jarFile = null;
try {
@@ -375,12 +367,17 @@
final ZipEntry manifestEntry = jarFile.findEntry(
ParsingPackageUtils.ANDROID_MANIFEST_FILENAME);
if (manifestEntry == null) {
- throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
+ return input.error(INSTALL_PARSE_FAILED_BAD_MANIFEST,
"Package " + apkPath + " has no manifest");
}
- lastCerts = loadCertificates(jarFile, manifestEntry);
+ final ParseResult<Certificate[][]> result =
+ loadCertificates(input, jarFile, manifestEntry);
+ if (result.isError()) {
+ return input.error(result);
+ }
+ lastCerts = result.getResult();
if (ArrayUtils.isEmpty(lastCerts)) {
- throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES, "Package "
+ return input.error(INSTALL_PARSE_FAILED_NO_CERTIFICATES, "Package "
+ apkPath + " has no certificates at entry "
+ ParsingPackageUtils.ANDROID_MANIFEST_FILENAME);
}
@@ -401,9 +398,15 @@
}
for (ZipEntry entry : toVerify) {
- final Certificate[][] entryCerts = loadCertificates(jarFile, entry);
+ final Certificate[][] entryCerts;
+ final ParseResult<Certificate[][]> ret =
+ loadCertificates(input, jarFile, entry);
+ if (ret.isError()) {
+ return input.error(ret);
+ }
+ entryCerts = ret.getResult();
if (ArrayUtils.isEmpty(entryCerts)) {
- throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
+ return input.error(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
"Package " + apkPath + " has no certificates at entry "
+ entry.getName());
}
@@ -411,20 +414,20 @@
// make sure all entries use the same signing certs
final Signature[] entrySigs = convertToSignatures(entryCerts);
if (!Signature.areExactMatch(lastSigs, entrySigs)) {
- throw new PackageParserException(
+ return input.error(
INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
"Package " + apkPath + " has mismatched certificates at entry "
+ entry.getName());
}
}
}
- return new SigningDetailsWithDigests(
- new SigningDetails(lastSigs, SignatureSchemeVersion.JAR), null);
+ return input.success(new SigningDetailsWithDigests(
+ new SigningDetails(lastSigs, SignatureSchemeVersion.JAR), null));
} catch (GeneralSecurityException e) {
- throw new PackageParserException(INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING,
+ return input.error(INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING,
"Failed to collect certificates from " + apkPath, e);
} catch (IOException | RuntimeException e) {
- throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
+ return input.error(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
"Failed to collect certificates from " + apkPath, e);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
@@ -432,17 +435,17 @@
}
}
- private static Certificate[][] loadCertificates(StrictJarFile jarFile, ZipEntry entry)
- throws PackageParserException {
+ private static ParseResult<Certificate[][]> loadCertificates(ParseInput input,
+ StrictJarFile jarFile, ZipEntry entry) {
InputStream is = null;
try {
// We must read the stream for the JarEntry to retrieve
// its certificates.
is = jarFile.getInputStream(entry);
readFullyIgnoringContents(is);
- return jarFile.getCertificateChains(entry);
+ return input.success(jarFile.getCertificateChains(entry));
} catch (IOException | RuntimeException e) {
- throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
+ return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
"Failed reading " + entry.getName() + " in " + jarFile, e);
} finally {
IoUtils.closeQuietly(is);
diff --git a/core/java/android/util/apk/ZipUtils.java b/core/java/android/util/apk/ZipUtils.java
index fa5477e..3ca3fc0 100644
--- a/core/java/android/util/apk/ZipUtils.java
+++ b/core/java/android/util/apk/ZipUtils.java
@@ -63,7 +63,8 @@
// exactly the remaining bytes in the buffer. The search is bounded because the maximum
// size of the comment field is 65535 bytes because the field is an unsigned 16-bit number.
- long fileSize = zip.length();
+ // TODO(b/193592496) RandomAccessFile#length
+ long fileSize = zip.getChannel().size();
if (fileSize < ZIP_EOCD_REC_MIN_SIZE) {
return null;
}
@@ -110,7 +111,8 @@
throw new IllegalArgumentException("maxCommentSize: " + maxCommentSize);
}
- long fileSize = zip.length();
+ // TODO(b/193592496) RandomAccessFile#length
+ long fileSize = zip.getChannel().size();
if (fileSize < ZIP_EOCD_REC_MIN_SIZE) {
// No space for EoCD record in the file.
return null;
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index b300f30..d6186d7 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -148,6 +148,8 @@
float width, float height, float vecX, float vecY,
float maxStretchAmountX, float maxStretchAmountY, float childRelativeLeft,
float childRelativeTop, float childRelativeRight, float childRelativeBottom);
+ private static native void nativeSetTrustedOverlay(long transactionObj, long nativeObject,
+ boolean isTrustedOverlay);
private static native boolean nativeClearContentFrameStats(long nativeObject);
private static native boolean nativeGetContentFrameStats(long nativeObject, WindowContentFrameStats outStats);
@@ -3435,6 +3437,17 @@
return this;
}
+ /**
+ * Sets the trusted overlay state on this SurfaceControl and it is inherited to all the
+ * children. The caller must hold the ACCESS_SURFACE_FLINGER permission.
+ * @hide
+ */
+ public Transaction setTrustedOverlay(SurfaceControl sc, boolean isTrustedOverlay) {
+ checkPreconditions(sc);
+ nativeSetTrustedOverlay(mNativeObject, sc.mNativeObject, isTrustedOverlay);
+ return this;
+ }
+
/**
* Merge the other transaction into this transaction, clearing the
* other transaction as if it had been applied.
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index fc0ec4c..b55ae1e 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -34,8 +34,8 @@
import android.util.Log;
/**
- * <p>A TextureView can be used to display a content stream. Such a content
- * stream can for instance be a video or an OpenGL scene. The content stream
+ * <p>A TextureView can be used to display a content stream, such as that
+ * coming from a camera preview, a video, or an OpenGL scene. The content stream
* can come from the application's process as well as a remote process.</p>
*
* <p>TextureView can only be used in a hardware accelerated window. When
@@ -43,56 +43,81 @@
*
* <p>Unlike {@link SurfaceView}, TextureView does not create a separate
* window but behaves as a regular View. This key difference allows a
- * TextureView to be moved, transformed, animated, etc. For instance, you
- * can make a TextureView semi-translucent by calling
- * <code>myView.setAlpha(0.5f)</code>.</p>
+ * TextureView to have translucency, arbitrary rotations, and complex
+ * clipping. For example, you can make a TextureView semi-translucent by
+ * calling <code>myView.setAlpha(0.5f)</code>.</p>
+ *
+ * <p>One implication of this integration of TextureView into the view
+ * hierarchy is that it may have slower performance than
+ * SurfaceView. TextureView contents must be copied, internally, from the
+ * underlying surface into the view displaying those contents. For
+ * that reason, SurfaceView is recommended as a more general solution
+ * to problems requiring rendering to surfaces.</p>
*
* <p>Using a TextureView is simple: all you need to do is get its
* {@link SurfaceTexture}. The {@link SurfaceTexture} can then be used to
- * render content. The following example demonstrates how to render the
- * camera preview into a TextureView:</p>
+ * render content. The following example demonstrates how to render a video
+ * into a TextureView:</p>
*
* <pre>
- * public class LiveCameraActivity extends Activity implements TextureView.SurfaceTextureListener {
- * private Camera mCamera;
+ * public class MyActivity extends Activity implements TextureView.SurfaceTextureListener {
+ * private MediaPlayer mMediaPlayer;
* private TextureView mTextureView;
*
* protected void onCreate(Bundle savedInstanceState) {
* super.onCreate(savedInstanceState);
*
+ * mMediaPlayer = new MediaPlayer();
+ *
* mTextureView = new TextureView(this);
* mTextureView.setSurfaceTextureListener(this);
- *
* setContentView(mTextureView);
* }
*
- * public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
- * mCamera = Camera.open();
- *
- * try {
- * mCamera.setPreviewTexture(surface);
- * mCamera.startPreview();
- * } catch (IOException ioe) {
- * // Something bad happened
- * }
+ * public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surfaceTexture,
+ * int width, int height) {
+ * AssetFileDescriptor fileDescriptor = // get file descriptor
+ * mMediaPlayer.setDataSource(fileDescriptor);
+ * mMediaPlayer.setSurface(new Surface(surfaceTexture));
+ * mMediaPlayer.prepareAsync();
+ * mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
+ * @Override
+ * public void onPrepared(MediaPlayer mp) {
+ * mMediaPlayer.start();
+ * }
+ * });
+ * } catch (IOException e) {
+ * e.printStackTrace();
+ * }
* }
*
- * public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
- * // Ignored, Camera does all the work for us
- * }
+ * @Override
+ * public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surfaceTexture,
+ * int width, int height) {
+ * // Handle size change depending on media needs
+ * }
*
- * public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
- * mCamera.stopPreview();
- * mCamera.release();
- * return true;
- * }
+ * @Override
+ * public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surfaceTexture) {
+ * // Release unneeded resources
+ * mMediaPlayer.stop();
+ * mMediaPlayer.release();
+ * return true;
+ * }
*
- * public void onSurfaceTextureUpdated(SurfaceTexture surface) {
- * // Invoked every time there's a new Camera preview frame
- * }
+ * @Override
+ * public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surfaceTexture) {
+ * // Invoked every time there's a new video frame
+ * }
+ *
* }
* </pre>
*
+ * <p>Similarly, TextureView can supply the surface needed for GL rendering or
+ * camera previews. Camera2 APIs require the surface created by TextureView,
+ * although developers are recommended to use the CameraX APIs instead, for which
+ * PreviewView creates its own TextureView or SurfaceView internally.</p>
+ *
* <p>A TextureView's SurfaceTexture can be obtained either by invoking
* {@link #getSurfaceTexture()} or by using a {@link SurfaceTextureListener}.
* It is important to know that a SurfaceTexture is available only after the
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index aac09b8..80ef6cf 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -1328,6 +1328,8 @@
private void logTraceClient(
IAccessibilityServiceConnection connection, String method, String params) {
logTrace(connection, method, params, Binder.getCallingUid(),
- Collections.emptyList(), null, FLAGS_ACCESSIBILITY_INTERACTION_CLIENT);
+ Arrays.asList(Thread.currentThread().getStackTrace()),
+ new HashSet<String>(Arrays.asList("getStackTrace", "logTraceClient")),
+ FLAGS_ACCESSIBILITY_INTERACTION_CLIENT);
}
}
diff --git a/core/java/android/view/autofill/AutofillClientController.java b/core/java/android/view/autofill/AutofillClientController.java
new file mode 100644
index 0000000..d4cd968
--- /dev/null
+++ b/core/java/android/view/autofill/AutofillClientController.java
@@ -0,0 +1,483 @@
+/*
+ * 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.view.autofill;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.Activity;
+import android.app.Application;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.IntentSender;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Slog;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewRootImpl;
+import android.view.WindowManagerGlobal;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * A controller to manage the autofill requests for the {@link Activity}.
+ *
+ * @hide
+ */
+public final class AutofillClientController implements AutofillManager.AutofillClient {
+
+ private static final String TAG = "AutofillClientController";
+
+ private static final String LOG_TAG = "autofill_client";
+ public static final boolean DEBUG = Log.isLoggable(LOG_TAG, Log.DEBUG);
+
+ public static final String LAST_AUTOFILL_ID = "android:lastAutofillId";
+ public static final String AUTOFILL_RESET_NEEDED = "@android:autofillResetNeeded";
+ public static final String AUTO_FILL_AUTH_WHO_PREFIX = "@android:autoFillAuth:";
+
+ /** The last autofill id that was returned from {@link #getNextAutofillId()} */
+ public int mLastAutofillId = View.LAST_APP_AUTOFILL_ID;
+
+ @NonNull
+ private final Activity mActivity;
+ /** The autofill manager. Always access via {@link #getAutofillManager()}. */
+ @Nullable
+ private AutofillManager mAutofillManager;
+ /** The autofill dropdown fill ui. */
+ @Nullable
+ private AutofillPopupWindow mAutofillPopupWindow;
+ private boolean mAutoFillResetNeeded;
+ private boolean mAutoFillIgnoreFirstResumePause;
+
+ /**
+ * AutofillClientController constructor.
+ */
+ public AutofillClientController(Activity activity) {
+ mActivity = activity;
+ }
+
+ private AutofillManager getAutofillManager() {
+ if (mAutofillManager == null) {
+ mAutofillManager = mActivity.getSystemService(AutofillManager.class);
+ }
+ return mAutofillManager;
+ }
+
+ // ------------------ Called for Activity events ------------------
+
+ /**
+ * Called when the Activity is attached.
+ */
+ public void onActivityAttached(Application application) {
+ mActivity.setAutofillOptions(application.getAutofillOptions());
+ }
+
+ /**
+ * Called when the {@link Activity#onCreate(Bundle)} is called.
+ */
+ public void onActivityCreated(@NonNull Bundle savedInstanceState) {
+ mAutoFillResetNeeded = savedInstanceState.getBoolean(AUTOFILL_RESET_NEEDED, false);
+ mLastAutofillId = savedInstanceState.getInt(LAST_AUTOFILL_ID, View.LAST_APP_AUTOFILL_ID);
+ if (mAutoFillResetNeeded) {
+ getAutofillManager().onCreate(savedInstanceState);
+ }
+ }
+
+ /**
+ * Called when the {@link Activity#onStart()} is called.
+ */
+ public void onActivityStarted() {
+ if (mAutoFillResetNeeded) {
+ getAutofillManager().onVisibleForAutofill();
+ }
+ }
+
+ /**
+ * Called when the {@link Activity#onResume()} is called.
+ */
+ public void onActivityResumed() {
+ enableAutofillCompatibilityIfNeeded();
+ if (mAutoFillResetNeeded) {
+ if (!mAutoFillIgnoreFirstResumePause) {
+ View focus = mActivity.getCurrentFocus();
+ if (focus != null && focus.canNotifyAutofillEnterExitEvent()) {
+ // TODO(b/148815880): Bring up keyboard if resumed from inline authentication.
+ // TODO: in Activity killed/recreated case, i.e. SessionLifecycleTest#
+ // testDatasetVisibleWhileAutofilledAppIsLifecycled: the View's initial
+ // window visibility after recreation is INVISIBLE in onResume() and next frame
+ // ViewRootImpl.performTraversals() changes window visibility to VISIBLE.
+ // So we cannot call View.notifyEnterOrExited() which will do nothing
+ // when View.isVisibleToUser() is false.
+ getAutofillManager().notifyViewEntered(focus);
+ }
+ }
+ }
+ }
+
+ /**
+ * Called when the Activity is performing resume.
+ */
+ public void onActivityPerformResume(boolean followedByPause) {
+ if (mAutoFillResetNeeded) {
+ // When Activity is destroyed in paused state, and relaunch activity, there will be
+ // extra onResume and onPause event, ignore the first onResume and onPause.
+ // see ActivityThread.handleRelaunchActivity()
+ mAutoFillIgnoreFirstResumePause = followedByPause;
+ if (mAutoFillIgnoreFirstResumePause && DEBUG) {
+ Slog.v(TAG, "autofill will ignore first pause when relaunching " + this);
+ }
+ }
+ }
+
+ /**
+ * Called when the {@link Activity#onPause()} is called.
+ */
+ public void onActivityPaused() {
+ if (mAutoFillResetNeeded) {
+ if (!mAutoFillIgnoreFirstResumePause) {
+ if (DEBUG) Log.v(TAG, "autofill notifyViewExited " + this);
+ View focus = mActivity.getCurrentFocus();
+ if (focus != null && focus.canNotifyAutofillEnterExitEvent()) {
+ getAutofillManager().notifyViewExited(focus);
+ }
+ } else {
+ // reset after first pause()
+ if (DEBUG) Log.v(TAG, "autofill got first pause " + this);
+ mAutoFillIgnoreFirstResumePause = false;
+ }
+ }
+ }
+
+ /**
+ * Called when the {@link Activity#onStop()} is called.
+ */
+ public void onActivityStopped(Intent intent, boolean changingConfigurations) {
+ if (mAutoFillResetNeeded) {
+ // If stopped without changing the configurations, the response should expire.
+ getAutofillManager().onInvisibleForAutofill(!changingConfigurations);
+ } else if (intent != null
+ && intent.hasExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN)
+ && intent.hasExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY)) {
+ restoreAutofillSaveUi(intent);
+ }
+ }
+
+ /**
+ * Called when the {@link Activity#onDestroy()} is called.
+ */
+ public void onActivityDestroyed() {
+ if (mActivity.isFinishing() && mAutoFillResetNeeded) {
+ getAutofillManager().onActivityFinishing();
+ }
+ }
+
+ /**
+ * Called when the {@link Activity#onSaveInstanceState(Bundle)} is called.
+ */
+ public void onSaveInstanceState(Bundle outState) {
+ outState.putInt(LAST_AUTOFILL_ID, mLastAutofillId);
+ if (mAutoFillResetNeeded) {
+ outState.putBoolean(AUTOFILL_RESET_NEEDED, true);
+ getAutofillManager().onSaveInstanceState(outState);
+ }
+ }
+
+ /**
+ * Called when the {@link Activity#finish()} is called.
+ */
+ public void onActivityFinish(Intent intent) {
+ // Activity was launched when user tapped a link in the Autofill Save UI - Save UI must
+ // be restored now.
+ if (intent != null && intent.hasExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN)) {
+ restoreAutofillSaveUi(intent);
+ }
+ }
+
+ /**
+ * Called when the {@link Activity#onBackPressed()} is called.
+ */
+ public void onActivityBackPressed(Intent intent) {
+ // Activity was launched when user tapped a link in the Autofill Save UI - Save UI must
+ // be restored now.
+ if (intent != null && intent.hasExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN)) {
+ restoreAutofillSaveUi(intent);
+ }
+ }
+
+ /**
+ * Called when the Activity is dispatching the result.
+ */
+ public void onDispatchActivityResult(int requestCode, int resultCode, Intent data) {
+ Intent resultData = (resultCode == Activity.RESULT_OK) ? data : null;
+ getAutofillManager().onAuthenticationResult(requestCode, resultData,
+ mActivity.getCurrentFocus());
+ }
+
+ /**
+ * Called when the {@link Activity#startActivity(Intent, Bundle)} is called.
+ */
+ public void onStartActivity(Intent startIntent, Intent cachedIntent) {
+ if (cachedIntent != null
+ && cachedIntent.hasExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN)
+ && cachedIntent.hasExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY)) {
+ if (TextUtils.equals(mActivity.getPackageName(),
+ startIntent.resolveActivity(mActivity.getPackageManager()).getPackageName())) {
+ // Apply Autofill restore mechanism on the started activity by startActivity()
+ final IBinder token =
+ cachedIntent.getIBinderExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN);
+ // Remove restore ability from current activity
+ cachedIntent.removeExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN);
+ cachedIntent.removeExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY);
+ // Put restore token
+ startIntent.putExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN, token);
+ startIntent.putExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY, true);
+ }
+ }
+ }
+
+ /**
+ * Restore the autofill save ui.
+ */
+ public void restoreAutofillSaveUi(Intent intent) {
+ final IBinder token =
+ intent.getIBinderExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN);
+ // Make only restore Autofill once
+ intent.removeExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN);
+ intent.removeExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY);
+ getAutofillManager().onPendingSaveUi(AutofillManager.PENDING_UI_OPERATION_RESTORE,
+ token);
+ }
+
+ /**
+ * Enable autofill compatibility mode for the Activity if the compatibility mode is enabled
+ * for the package.
+ */
+ public void enableAutofillCompatibilityIfNeeded() {
+ if (mActivity.isAutofillCompatibilityEnabled()) {
+ final AutofillManager afm = mActivity.getSystemService(AutofillManager.class);
+ if (afm != null) {
+ afm.enableCompatibilityMode();
+ }
+ }
+ }
+
+ /**
+ * Prints autofill related information for the Activity.
+ */
+ public void dumpAutofillManager(String prefix, PrintWriter writer) {
+ final AutofillManager afm = getAutofillManager();
+ if (afm != null) {
+ afm.dump(prefix, writer);
+ writer.print(prefix); writer.print("Autofill Compat Mode: ");
+ writer.println(mActivity.isAutofillCompatibilityEnabled());
+ } else {
+ writer.print(prefix); writer.println("No AutofillManager");
+ }
+ }
+
+ /**
+ * Returns the next autofill ID that is unique in the activity
+ *
+ * <p>All IDs will be bigger than {@link View#LAST_APP_AUTOFILL_ID}. All IDs returned
+ * will be unique.
+ */
+ public int getNextAutofillId() {
+ if (mLastAutofillId == Integer.MAX_VALUE - 1) {
+ mLastAutofillId = View.LAST_APP_AUTOFILL_ID;
+ }
+
+ mLastAutofillId++;
+
+ return mLastAutofillId;
+ }
+
+ // ------------------ AutofillClient implementation ------------------
+
+ @Override
+ public AutofillId autofillClientGetNextAutofillId() {
+ return new AutofillId(getNextAutofillId());
+ }
+
+ @Override
+ public boolean autofillClientIsCompatibilityModeEnabled() {
+ return mActivity.isAutofillCompatibilityEnabled();
+ }
+
+ @Override
+ public boolean autofillClientIsVisibleForAutofill() {
+ return !mActivity.isStopped();
+ }
+
+ @Override
+ public ComponentName autofillClientGetComponentName() {
+ return mActivity.getComponentName();
+ }
+
+ @Override
+ public IBinder autofillClientGetActivityToken() {
+ return mActivity.getActivityToken();
+ }
+
+ @Override
+ public boolean[] autofillClientGetViewVisibility(AutofillId[] autofillIds) {
+ final int autofillIdCount = autofillIds.length;
+ final boolean[] visible = new boolean[autofillIdCount];
+ for (int i = 0; i < autofillIdCount; i++) {
+ final AutofillId autofillId = autofillIds[i];
+ final View view = autofillClientFindViewByAutofillIdTraversal(autofillId);
+ if (view != null) {
+ if (!autofillId.isVirtualInt()) {
+ visible[i] = view.isVisibleToUser();
+ } else {
+ visible[i] = view.isVisibleToUserForAutofill(autofillId.getVirtualChildIntId());
+ }
+ }
+ }
+ if (android.view.autofill.Helper.sVerbose) {
+ Log.v(TAG, "autofillClientGetViewVisibility(): " + Arrays.toString(visible));
+ }
+ return visible;
+ }
+
+ @Override
+ public View autofillClientFindViewByAccessibilityIdTraversal(int viewId, int windowId) {
+ final ArrayList<ViewRootImpl> roots = WindowManagerGlobal.getInstance()
+ .getRootViews(mActivity.getActivityToken());
+ for (int rootNum = 0; rootNum < roots.size(); rootNum++) {
+ final View rootView = roots.get(rootNum).getView();
+ if (rootView != null && rootView.getAccessibilityWindowId() == windowId) {
+ final View view = rootView.findViewByAccessibilityIdTraversal(viewId);
+ if (view != null) {
+ return view;
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public View autofillClientFindViewByAutofillIdTraversal(AutofillId autofillId) {
+ final ArrayList<ViewRootImpl> roots =
+ WindowManagerGlobal.getInstance().getRootViews(mActivity.getActivityToken());
+ for (int rootNum = 0; rootNum < roots.size(); rootNum++) {
+ final View rootView = roots.get(rootNum).getView();
+
+ if (rootView != null) {
+ final View view = rootView.findViewByAutofillIdTraversal(autofillId.getViewId());
+ if (view != null) {
+ return view;
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public View[] autofillClientFindViewsByAutofillIdTraversal(AutofillId[] autofillIds) {
+ final View[] views = new View[autofillIds.length];
+ final ArrayList<ViewRootImpl> roots =
+ WindowManagerGlobal.getInstance().getRootViews(mActivity.getActivityToken());
+
+ for (int rootNum = 0; rootNum < roots.size(); rootNum++) {
+ final View rootView = roots.get(rootNum).getView();
+
+ if (rootView != null) {
+ final int viewCount = autofillIds.length;
+ for (int viewNum = 0; viewNum < viewCount; viewNum++) {
+ if (views[viewNum] == null) {
+ views[viewNum] = rootView.findViewByAutofillIdTraversal(
+ autofillIds[viewNum].getViewId());
+ }
+ }
+ }
+ }
+ return views;
+ }
+
+ @Override
+ public boolean autofillClientIsFillUiShowing() {
+ return mAutofillPopupWindow != null && mAutofillPopupWindow.isShowing();
+ }
+
+ @Override
+ public boolean autofillClientRequestHideFillUi() {
+ if (mAutofillPopupWindow == null) {
+ return false;
+ }
+ mAutofillPopupWindow.dismiss();
+ mAutofillPopupWindow = null;
+ return true;
+ }
+
+ @Override
+ public boolean autofillClientRequestShowFillUi(@NonNull View anchor, int width,
+ int height, @Nullable Rect anchorBounds, IAutofillWindowPresenter presenter) {
+ final boolean wasShowing;
+
+ if (mAutofillPopupWindow == null) {
+ wasShowing = false;
+ mAutofillPopupWindow = new AutofillPopupWindow(presenter);
+ } else {
+ wasShowing = mAutofillPopupWindow.isShowing();
+ }
+ mAutofillPopupWindow.update(anchor, 0, 0, width, height, anchorBounds);
+
+ return !wasShowing && mAutofillPopupWindow.isShowing();
+ }
+
+ @Override
+ public void autofillClientDispatchUnhandledKey(View anchor, KeyEvent keyEvent) {
+ ViewRootImpl rootImpl = anchor.getViewRootImpl();
+ if (rootImpl != null) {
+ // don't care if anchorView is current focus, for example a custom view may only receive
+ // touchEvent, not focusable but can still trigger autofill window. The Key handling
+ // might be inside parent of the custom view.
+ rootImpl.dispatchKeyFromAutofill(keyEvent);
+ }
+ }
+
+ @Override
+ public boolean isDisablingEnterExitEventForAutofill() {
+ return mAutoFillIgnoreFirstResumePause || !mActivity.isResumed();
+ }
+
+ @Override
+ public void autofillClientResetableStateAvailable() {
+ mAutoFillResetNeeded = true;
+ }
+
+ @Override
+ public void autofillClientRunOnUiThread(Runnable action) {
+ mActivity.runOnUiThread(action);
+ }
+
+ @Override
+ public void autofillClientAuthenticate(int authenticationId, IntentSender intent,
+ Intent fillInIntent, boolean authenticateInline) {
+ try {
+ mActivity.startIntentSenderForResult(intent, AUTO_FILL_AUTH_WHO_PREFIX,
+ authenticationId, fillInIntent, 0, 0, null);
+ } catch (IntentSender.SendIntentException e) {
+ Log.e(TAG, "authenticate() failed for intent:" + intent, e);
+ }
+ }
+}
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 8e0d9bc..e8e5630 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -95,7 +95,6 @@
import com.android.internal.inputmethod.UnbindReason;
import com.android.internal.os.SomeArgs;
import com.android.internal.view.IInputConnectionWrapper;
-import com.android.internal.view.IInputContext;
import com.android.internal.view.IInputMethodClient;
import com.android.internal.view.IInputMethodManager;
import com.android.internal.view.IInputMethodSession;
@@ -366,7 +365,7 @@
final H mH;
// Our generic input connection if the current target does not have its own.
- private final IInputConnectionWrapper mIInputContext;
+ private final IInputConnectionWrapper mFallbackInputConnection;
private final int mDisplayId;
@@ -408,8 +407,7 @@
/**
* The InputConnection that was last retrieved from the served view.
*/
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
- IInputConnectionWrapper mServedInputConnectionWrapper;
+ IInputConnectionWrapper mServedInputConnection;
/**
* The completions that were last provided by the served view.
*/
@@ -698,8 +696,8 @@
*/
@Override
public void finishComposingText() {
- if (mServedInputConnectionWrapper != null) {
- mServedInputConnectionWrapper.finishComposingText();
+ if (mServedInputConnection != null) {
+ mServedInputConnection.finishComposingText();
}
}
@@ -753,9 +751,9 @@
return false;
}
- return mServedInputConnectionWrapper != null
- && mServedInputConnectionWrapper.isActive()
- && mServedInputConnectionWrapper.getServedView() == view;
+ return mServedInputConnection != null
+ && mServedInputConnection.isActive()
+ && mServedInputConnection.getServedView() == view;
}
}
}
@@ -922,7 +920,7 @@
mRestartOnNextWindowFocus = true;
// Note that finishComposingText() is allowed to run
// even when we are not active.
- mIInputContext.finishComposingText();
+ mFallbackInputConnection.finishComposingText();
}
// Check focus again in case that "onWindowFocus" is called before
// handling this message.
@@ -954,9 +952,8 @@
final boolean fullscreen = msg.arg1 != 0;
InputConnection ic = null;
synchronized (mH) {
- if (mFullscreenMode != fullscreen
- && mServedInputConnectionWrapper != null) {
- ic = mServedInputConnectionWrapper.getInputConnection();
+ if (mFullscreenMode != fullscreen && mServedInputConnection != null) {
+ ic = mServedInputConnection.getInputConnection();
mFullscreenMode = fullscreen;
}
}
@@ -1030,8 +1027,6 @@
}
};
- final InputConnection mDummyInputConnection = new BaseInputConnection(this, false);
-
/**
* For layoutlib to clean up static objects inside {@link InputMethodManager}.
*/
@@ -1080,7 +1075,7 @@
// 1) doing so has no effect for A and 2) doing so is sufficient for B.
final long identity = Binder.clearCallingIdentity();
try {
- service.addClient(imm.mClient, imm.mIInputContext, displayId);
+ service.addClient(imm.mClient, imm.mFallbackInputConnection, displayId);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
} finally {
@@ -1125,7 +1120,8 @@
mMainLooper = looper;
mH = new H(looper);
mDisplayId = displayId;
- mIInputContext = new IInputConnectionWrapper(looper, mDummyInputConnection, this, null);
+ mFallbackInputConnection = new IInputConnectionWrapper(looper,
+ new BaseInputConnection(this, false), this, null);
}
/**
@@ -1202,18 +1198,18 @@
}
}
- /** @hide */
- @UnsupportedAppUsage
+ /**
+ * No longer used. Do not use.
+ *
+ * TODO(b/192412909) Remove this method.
+ *
+ * @deprecated Was kept due to {@link UnsupportedAppUsage}. Will be removed soon.
+ * @hide
+ */
public IInputMethodClient getClient() {
return mClient;
}
- /** @hide */
- @UnsupportedAppUsage
- public IInputContext getInputContext() {
- return mIInputContext;
- }
-
/**
* Returns the list of installed input methods.
*
@@ -1397,8 +1393,8 @@
public boolean isAcceptingText() {
checkFocus();
synchronized (mH) {
- return mServedInputConnectionWrapper != null
- && mServedInputConnectionWrapper.getInputConnection() != null;
+ return mServedInputConnection != null
+ && mServedInputConnection.getInputConnection() != null;
}
}
@@ -1452,9 +1448,9 @@
*/
void clearConnectionLocked() {
mCurrentTextBoxAttribute = null;
- if (mServedInputConnectionWrapper != null) {
- mServedInputConnectionWrapper.deactivate();
- mServedInputConnectionWrapper = null;
+ if (mServedInputConnection != null) {
+ mServedInputConnection.deactivate();
+ mServedInputConnection = null;
}
}
@@ -1950,11 +1946,11 @@
mCurrentTextBoxAttribute = tba;
mServedConnecting = false;
- if (mServedInputConnectionWrapper != null) {
- mServedInputConnectionWrapper.deactivate();
- mServedInputConnectionWrapper = null;
+ if (mServedInputConnection != null) {
+ mServedInputConnection.deactivate();
+ mServedInputConnection = null;
}
- IInputConnectionWrapper servedContext;
+ IInputConnectionWrapper servedInputConnection;
final int missingMethodFlags;
if (ic != null) {
mCursorSelStart = tba.initialSelStart;
@@ -1971,14 +1967,14 @@
} else {
icHandler = ic.getHandler();
}
- servedContext = new IInputConnectionWrapper(
+ servedInputConnection = new IInputConnectionWrapper(
icHandler != null ? icHandler.getLooper() : vh.getLooper(), ic, this, view);
} else {
- servedContext = null;
+ servedInputConnection = null;
missingMethodFlags = 0;
icHandler = null;
}
- mServedInputConnectionWrapper = servedContext;
+ mServedInputConnection = servedInputConnection;
if (DEBUG) {
Log.v(TAG, "START INPUT: view=" + dumpViewInfo(view) + " ic="
@@ -1988,7 +1984,7 @@
try {
res = mService.startInputOrWindowGainedFocus(
startInputReason, mClient, windowGainingFocus, startInputFlags,
- softInputMode, windowFlags, tba, servedContext, missingMethodFlags,
+ softInputMode, windowFlags, tba, servedInputConnection, missingMethodFlags,
view.getContext().getApplicationInfo().targetSdkVersion);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -3083,7 +3079,7 @@
p.println(" mService=" + mService);
p.println(" mMainLooper=" + mMainLooper);
- p.println(" mIInputContext=" + mIInputContext);
+ p.println(" mFallbackInputConnection=" + mFallbackInputConnection);
p.println(" mActive=" + mActive
+ " mRestartOnNextWindowFocus=" + mRestartOnNextWindowFocus
+ " mBindSequence=" + mBindSequence
@@ -3104,7 +3100,7 @@
} else {
p.println(" mCurrentTextBoxAttribute: null");
}
- p.println(" mServedInputConnectionWrapper=" + mServedInputConnectionWrapper);
+ p.println(" mServedInputConnection=" + mServedInputConnection);
p.println(" mCompletions=" + Arrays.toString(mCompletions));
p.println(" mCursorRect=" + mCursorRect);
p.println(" mCursorSelStart=" + mCursorSelStart
@@ -3230,8 +3226,8 @@
if (mImeInsetsConsumer != null) {
mImeInsetsConsumer.dumpDebug(proto, IME_INSETS_SOURCE_CONSUMER);
}
- if (mServedInputConnectionWrapper != null) {
- mServedInputConnectionWrapper.dumpDebug(proto, INPUT_CONNECTION);
+ if (mServedInputConnection != null) {
+ mServedInputConnection.dumpDebug(proto, INPUT_CONNECTION);
}
if (icProto != null) {
proto.write(INPUT_CONNECTION_CALL, icProto);
diff --git a/core/java/android/window/StartingWindowInfo.java b/core/java/android/window/StartingWindowInfo.java
index 566f154..8c64474 100644
--- a/core/java/android/window/StartingWindowInfo.java
+++ b/core/java/android/window/StartingWindowInfo.java
@@ -22,6 +22,7 @@
import android.annotation.TestApi;
import android.app.ActivityManager;
import android.app.TaskInfo;
+import android.content.pm.ActivityInfo;
import android.os.Parcel;
import android.os.Parcelable;
import android.view.InsetsState;
@@ -78,6 +79,14 @@
public ActivityManager.RunningTaskInfo taskInfo;
/**
+ * The {@link ActivityInfo} of the target activity which to create the starting window.
+ * It can be null if the info is the same as the top in task info.
+ * @hide
+ */
+ @Nullable
+ public ActivityInfo targetActivityInfo;
+
+ /**
* InsetsState of TopFullscreenOpaqueWindow
* @hide
*/
@@ -174,6 +183,7 @@
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeTypedObject(taskInfo, flags);
+ dest.writeTypedObject(targetActivityInfo, flags);
dest.writeInt(startingWindowTypeParameter);
dest.writeTypedObject(topOpaqueWindowInsetsState, flags);
dest.writeTypedObject(topOpaqueWindowLayoutParams, flags);
@@ -185,6 +195,7 @@
void readFromParcel(@NonNull Parcel source) {
taskInfo = source.readTypedObject(ActivityManager.RunningTaskInfo.CREATOR);
+ targetActivityInfo = source.readTypedObject(ActivityInfo.CREATOR);
startingWindowTypeParameter = source.readInt();
topOpaqueWindowInsetsState = source.readTypedObject(InsetsState.CREATOR);
topOpaqueWindowLayoutParams = source.readTypedObject(
@@ -198,6 +209,7 @@
@Override
public String toString() {
return "StartingWindowInfo{taskId=" + taskInfo.taskId
+ + " targetActivityInfo=" + targetActivityInfo
+ " displayId=" + taskInfo.displayId
+ " topActivityType=" + taskInfo.topActivityType
+ " preferredStartingWindowType="
diff --git a/core/java/android/window/TaskFragmentInfo.java b/core/java/android/window/TaskFragmentInfo.java
index 6d4a2f1..fe25e57 100644
--- a/core/java/android/window/TaskFragmentInfo.java
+++ b/core/java/android/window/TaskFragmentInfo.java
@@ -18,9 +18,12 @@
import static android.app.WindowConfiguration.WindowingMode;
+import static java.util.Objects.requireNonNull;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.res.Configuration;
+import android.graphics.Point;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
@@ -35,8 +38,8 @@
public final class TaskFragmentInfo implements Parcelable {
/**
- * Client assigned unique token in {@link TaskFragmentCreationParams#fragmentToken} to create
- * this TaskFragment with.
+ * Client assigned unique token in {@link TaskFragmentCreationParams#getFragmentToken()} to
+ * create this TaskFragment with.
*/
@NonNull
private final IBinder mFragmentToken;
@@ -47,9 +50,12 @@
@NonNull
private final Configuration mConfiguration = new Configuration();
- /** Whether the TaskFragment contains any child Activity. */
+ /** Whether the TaskFragment contains any child Window Container. */
private final boolean mIsEmpty;
+ /** Whether the TaskFragment contains any running Activity. */
+ private final boolean mHasRunningActivity;
+
/** Whether this TaskFragment is visible on the window hierarchy. */
private final boolean mIsVisible;
@@ -59,19 +65,21 @@
*/
private final List<IBinder> mActivities = new ArrayList<>();
+ /** Relative position of the fragment's top left corner in the parent container. */
+ private final Point mPositionInParent;
+
public TaskFragmentInfo(
@NonNull IBinder fragmentToken, @NonNull WindowContainerToken token,
- @NonNull Configuration configuration, boolean isEmpty, boolean isVisible,
- List<IBinder> activities) {
- if (fragmentToken == null) {
- throw new IllegalArgumentException("Invalid TaskFragmentInfo.");
- }
- mFragmentToken = fragmentToken;
- mToken = token;
+ @NonNull Configuration configuration, boolean isEmpty, boolean hasRunningActivity,
+ boolean isVisible, @NonNull List<IBinder> activities, @NonNull Point positionInParent) {
+ mFragmentToken = requireNonNull(fragmentToken);
+ mToken = requireNonNull(token);
mConfiguration.setTo(configuration);
mIsEmpty = isEmpty;
+ mHasRunningActivity = hasRunningActivity;
mIsVisible = isVisible;
mActivities.addAll(activities);
+ mPositionInParent = requireNonNull(positionInParent);
}
public IBinder getFragmentToken() {
@@ -90,6 +98,10 @@
return mIsEmpty;
}
+ public boolean hasRunningActivity() {
+ return mHasRunningActivity;
+ }
+
public boolean isVisible() {
return mIsVisible;
}
@@ -98,6 +110,12 @@
return mActivities;
}
+ /** Returns the relative position of the fragment's top left corner in the parent container. */
+ @NonNull
+ public Point getPositionInParent() {
+ return mPositionInParent;
+ }
+
@WindowingMode
public int getWindowingMode() {
return mConfiguration.windowConfiguration.getWindowingMode();
@@ -115,9 +133,11 @@
return mFragmentToken.equals(that.mFragmentToken)
&& mToken.equals(that.mToken)
&& mIsEmpty == that.mIsEmpty
+ && mHasRunningActivity == that.mHasRunningActivity
&& mIsVisible == that.mIsVisible
&& getWindowingMode() == that.getWindowingMode()
- && mActivities.equals(that.mActivities);
+ && mActivities.equals(that.mActivities)
+ && mPositionInParent.equals(that.mPositionInParent);
}
private TaskFragmentInfo(Parcel in) {
@@ -125,8 +145,10 @@
mToken = in.readTypedObject(WindowContainerToken.CREATOR);
mConfiguration.readFromParcel(in);
mIsEmpty = in.readBoolean();
+ mHasRunningActivity = in.readBoolean();
mIsVisible = in.readBoolean();
in.readBinderList(mActivities);
+ mPositionInParent = requireNonNull(in.readTypedObject(Point.CREATOR));
}
@Override
@@ -135,8 +157,10 @@
dest.writeTypedObject(mToken, flags);
mConfiguration.writeToParcel(dest, flags);
dest.writeBoolean(mIsEmpty);
+ dest.writeBoolean(mHasRunningActivity);
dest.writeBoolean(mIsVisible);
dest.writeBinderList(mActivities);
+ dest.writeTypedObject(mPositionInParent, flags);
}
@NonNull
@@ -159,7 +183,9 @@
+ " fragmentToken=" + mFragmentToken
+ " token=" + mToken
+ " isEmpty=" + mIsEmpty
+ + " hasRunningActivity=" + mHasRunningActivity
+ " isVisible=" + mIsVisible
+ + " positionInParent=" + mPositionInParent
+ "}";
}
diff --git a/core/java/android/window/TransitionFilter.java b/core/java/android/window/TransitionFilter.java
index 6351b03..607e316 100644
--- a/core/java/android/window/TransitionFilter.java
+++ b/core/java/android/window/TransitionFilter.java
@@ -21,7 +21,9 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityManager;
import android.app.WindowConfiguration;
+import android.content.ComponentName;
import android.os.Parcel;
import android.os.Parcelable;
@@ -140,6 +142,7 @@
public int mActivityType = ACTIVITY_TYPE_UNDEFINED;
public int[] mModes = null;
public @ContainerOrder int mOrder = CONTAINER_ORDER_ANY;
+ public ComponentName mTopActivity;
public Requirement() {
}
@@ -148,6 +151,7 @@
mActivityType = in.readInt();
mModes = in.createIntArray();
mOrder = in.readInt();
+ mTopActivity = in.readTypedObject(ComponentName.CREATOR);
}
/** Go through changes and find if at-least one change matches this filter */
@@ -167,6 +171,7 @@
continue;
}
}
+ if (!matchesTopActivity(change.getTaskInfo())) continue;
if (mModes != null) {
boolean pass = false;
for (int m = 0; m < mModes.length; ++m) {
@@ -182,12 +187,20 @@
return false;
}
+ private boolean matchesTopActivity(ActivityManager.RunningTaskInfo info) {
+ if (mTopActivity == null) return true;
+ if (info == null) return false;
+ final ComponentName component = info.topActivity;
+ return mTopActivity.equals(component);
+ }
+
/** Check if the request matches this filter. It may generate false positives */
boolean matches(@NonNull TransitionRequestInfo request) {
// Can't check modes/order since the transition hasn't been built at this point.
if (mActivityType == ACTIVITY_TYPE_UNDEFINED) return true;
return request.getTriggerTask() != null
- && request.getTriggerTask().getActivityType() == mActivityType;
+ && request.getTriggerTask().getActivityType() == mActivityType
+ && matchesTopActivity(request.getTriggerTask());
}
@Override
@@ -196,6 +209,7 @@
dest.writeInt(mActivityType);
dest.writeIntArray(mModes);
dest.writeInt(mOrder);
+ dest.writeTypedObject(mTopActivity, flags);
}
@NonNull
@@ -230,6 +244,7 @@
}
out.append("]").toString();
out.append(" order=" + containerOrderToString(mOrder));
+ out.append(" topActivity=").append(mTopActivity);
return out.toString();
}
}
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java
index 3c360fb..095be8c 100644
--- a/core/java/android/window/WindowContainerTransaction.java
+++ b/core/java/android/window/WindowContainerTransaction.java
@@ -443,6 +443,7 @@
* Starts an activity in the TaskFragment.
* @param fragmentToken client assigned unique token to create TaskFragment with specified in
* {@link TaskFragmentCreationParams#fragmentToken}.
+ * @param callerToken the activity token that initialized the activity launch.
* @param activityIntent intent to start the activity.
* @param activityOptions ActivityOptions to start the activity with.
* @see android.content.Context#startActivity(Intent, Bundle).
@@ -450,12 +451,13 @@
*/
@NonNull
public WindowContainerTransaction startActivityInTaskFragment(
- @NonNull IBinder fragmentToken, @NonNull Intent activityIntent,
- @Nullable Bundle activityOptions) {
+ @NonNull IBinder fragmentToken, @NonNull IBinder callerToken,
+ @NonNull Intent activityIntent, @Nullable Bundle activityOptions) {
final HierarchyOp hierarchyOp =
new HierarchyOp.Builder(
HierarchyOp.HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT)
.setContainer(fragmentToken)
+ .setReparentContainer(callerToken)
.setActivityIntent(activityIntent)
.setLaunchOptions(activityOptions)
.build();
@@ -1060,6 +1062,11 @@
return mReparent;
}
+ @NonNull
+ public IBinder getCallingActivity() {
+ return mReparent;
+ }
+
public boolean getToTop() {
return mToTop;
}
diff --git a/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java b/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java
index c57afbc..179ac8b 100644
--- a/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java
+++ b/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java
@@ -17,6 +17,7 @@
package com.android.internal.accessibility.util;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
+import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_GESTURE;
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL;
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW;
@@ -30,6 +31,7 @@
import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_BUTTON;
import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_BUTTON_LONG_PRESS;
import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_FLOATING_MENU;
+import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_GESTURE;
import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__TRIPLE_TAP;
import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__UNKNOWN_TYPE;
import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__VOLUME_KEY;
@@ -152,19 +154,29 @@
convertToLoggingMagnificationMode(mode));
}
- private static boolean isFloatingMenuEnabled(Context context) {
+ private static boolean isAccessibilityFloatingMenuEnabled(Context context) {
return Settings.Secure.getInt(context.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_MODE, /* def= */ -1)
== ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
}
+ private static boolean isAccessibilityGestureEnabled(Context context) {
+ return Settings.Secure.getInt(context.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_BUTTON_MODE, /* def= */ -1)
+ == ACCESSIBILITY_BUTTON_MODE_GESTURE;
+ }
+
private static int convertToLoggingShortcutType(Context context,
@ShortcutType int shortcutType) {
switch (shortcutType) {
case ACCESSIBILITY_BUTTON:
- return isFloatingMenuEnabled(context)
- ? ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_FLOATING_MENU
- : ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_BUTTON;
+ if (isAccessibilityFloatingMenuEnabled(context)) {
+ return ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_FLOATING_MENU;
+ } else if (isAccessibilityGestureEnabled(context)) {
+ return ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_GESTURE;
+ } else {
+ return ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_BUTTON;
+ }
case ACCESSIBILITY_SHORTCUT_KEY:
return ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__VOLUME_KEY;
}
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index eeceafa..93d0d02 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -1269,7 +1269,8 @@
SELECTION_TYPE_NEARBY,
"",
-1);
- safelyStartActivity(ti);
+ // Action bar is user-independent, always start as primary
+ safelyStartActivityAsUser(ti, getPersonalProfileUserHandle());
finish();
}
);
@@ -1290,7 +1291,8 @@
SELECTION_TYPE_EDIT,
"",
-1);
- safelyStartActivity(ti);
+ // Action bar is user-independent, always start as primary
+ safelyStartActivityAsUser(ti, getPersonalProfileUserHandle());
finish();
}
);
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 6f9da6f..d08f21c 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -1257,13 +1257,32 @@
// don't kill ourselves.
StrictMode.disableDeathOnFileUriExposure();
try {
- safelyStartActivityInternal(cti);
+ UserHandle currentUserHandle = mMultiProfilePagerAdapter.getCurrentUserHandle();
+ safelyStartActivityInternal(cti, currentUserHandle);
} finally {
StrictMode.enableDeathOnFileUriExposure();
}
}
- private void safelyStartActivityInternal(TargetInfo cti) {
+ /**
+ * Start activity as a fixed user handle.
+ * @param cti TargetInfo to be launched.
+ * @param user User to launch this activity as.
+ */
+ @VisibleForTesting
+ public void safelyStartActivityAsUser(TargetInfo cti, UserHandle user) {
+ // We're dispatching intents that might be coming from legacy apps, so
+ // don't kill ourselves.
+ StrictMode.disableDeathOnFileUriExposure();
+ try {
+ safelyStartActivityInternal(cti, user);
+ } finally {
+ StrictMode.enableDeathOnFileUriExposure();
+ }
+ }
+
+
+ private void safelyStartActivityInternal(TargetInfo cti, UserHandle user) {
// If the target is suspended, the activity will not be successfully launched.
// Do not unregister from package manager updates in this case
if (!cti.isSuspended() && mRegistered) {
@@ -1280,18 +1299,17 @@
if (mProfileSwitchMessageId != -1) {
Toast.makeText(this, getString(mProfileSwitchMessageId), Toast.LENGTH_LONG).show();
}
- UserHandle currentUserHandle = mMultiProfilePagerAdapter.getCurrentUserHandle();
if (!mSafeForwardingMode) {
- if (cti.startAsUser(this, null, currentUserHandle)) {
+ if (cti.startAsUser(this, null, user)) {
onActivityStarted(cti);
- maybeLogCrossProfileTargetLaunch(cti, currentUserHandle);
+ maybeLogCrossProfileTargetLaunch(cti, user);
}
return;
}
try {
- if (cti.startAsCaller(this, null, currentUserHandle.getIdentifier())) {
+ if (cti.startAsCaller(this, null, user.getIdentifier())) {
onActivityStarted(cti);
- maybeLogCrossProfileTargetLaunch(cti, currentUserHandle);
+ maybeLogCrossProfileTargetLaunch(cti, user);
}
} catch (RuntimeException e) {
Slog.wtf(TAG, "Unable to launch as uid " + mLaunchedFromUid
diff --git a/core/java/com/android/internal/inputmethod/CallbackUtils.java b/core/java/com/android/internal/inputmethod/CallbackUtils.java
index 1933c54..2b9556d 100644
--- a/core/java/com/android/internal/inputmethod/CallbackUtils.java
+++ b/core/java/com/android/internal/inputmethod/CallbackUtils.java
@@ -17,7 +17,11 @@
package com.android.internal.inputmethod;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.os.RemoteException;
+import android.util.Log;
+import android.view.inputmethod.ExtractedText;
+import android.view.inputmethod.SurroundingText;
import java.util.function.BooleanSupplier;
import java.util.function.IntSupplier;
@@ -112,13 +116,13 @@
}
/**
- * A utility method using given {@link IIInputContentUriTokenResultCallback} to callback the
+ * A utility method using given {@link IInputContentUriTokenResultCallback} to callback the
* result.
*
- * @param callback {@link IIInputContentUriTokenResultCallback} to be called back.
+ * @param callback {@link IInputContentUriTokenResultCallback} to be called back.
* @param resultSupplier the supplier from which the result is provided.
*/
- public static void onResult(@NonNull IIInputContentUriTokenResultCallback callback,
+ public static void onResult(@NonNull IInputContentUriTokenResultCallback callback,
@NonNull Supplier<IInputContentUriToken> resultSupplier) {
IInputContentUriToken result = null;
Throwable exception = null;
@@ -137,4 +141,143 @@
callback.onResult(result);
} catch (RemoteException ignored) { }
}
+
+ /**
+ * A utility method to reply associated with {@link InputConnectionCommand}.
+ *
+ * @param command {@link InputConnectionCommand} to be replied.
+ * @param result a {@link String} value to be replied.
+ * @param tag tag name to be used for debug output when the invocation fails.
+ */
+ public static void onResult(@NonNull InputConnectionCommand command, boolean result,
+ @Nullable String tag) {
+ if (command.mResultCallbackType != InputConnectionCommand.ResultCallbackType.BOOLEAN) {
+ if (tag != null) {
+ Log.e(tag, InputMethodDebug.inputConnectionCommandTypeToString(command.mCommandType)
+ + ": Failed to return result=" + result + " due to callback type mismatch."
+ + " expected=String actual=" + command.mResultCallbackType);
+ }
+ return;
+ }
+ try {
+ IBooleanResultCallback.Stub.asInterface(command.mResultCallback).onResult(result);
+ } catch (Throwable e) {
+ if (tag != null) {
+ Log.e(tag, InputMethodDebug.inputConnectionCommandTypeToString(command.mCommandType)
+ + ": Failed to return result=" + result, e);
+ }
+ }
+ }
+
+ /**
+ * A utility method to reply associated with {@link InputConnectionCommand}.
+ *
+ * @param command {@link InputConnectionCommand} to be replied.
+ * @param result an int result value to be replied.
+ * @param tag tag name to be used for debug output when the invocation fails.
+ */
+ public static void onResult(@NonNull InputConnectionCommand command, int result,
+ @Nullable String tag) {
+ if (command.mResultCallbackType != InputConnectionCommand.ResultCallbackType.INT) {
+ if (tag != null) {
+ Log.e(tag, InputMethodDebug.inputConnectionCommandTypeToString(command.mCommandType)
+ + ": Failed to return result=" + result + " due to callback type mismatch."
+ + " expected=int actual=" + command.mResultCallbackType);
+ }
+ return;
+ }
+ try {
+ IIntResultCallback.Stub.asInterface(command.mResultCallback).onResult(result);
+ } catch (Throwable e) {
+ if (tag != null) {
+ Log.e(tag, InputMethodDebug.inputConnectionCommandTypeToString(command.mCommandType)
+ + ": Failed to return result=" + result, e);
+ }
+ }
+ }
+
+ /**
+ * A utility method to reply associated with {@link InputConnectionCommand}.
+ *
+ * @param command {@link InputConnectionCommand} to be replied.
+ * @param result a {@link CharSequence} result value to be replied.
+ * @param tag tag name to be used for debug output when the invocation fails.
+ */
+ public static void onResult(@NonNull InputConnectionCommand command,
+ @Nullable CharSequence result, @Nullable String tag) {
+ if (command.mResultCallbackType
+ != InputConnectionCommand.ResultCallbackType.CHAR_SEQUENCE) {
+ if (tag != null) {
+ Log.e(tag, InputMethodDebug.inputConnectionCommandTypeToString(command.mCommandType)
+ + ": Failed to return result=" + result + " due to callback type mismatch."
+ + " expected=CharSequence actual=" + command.mResultCallbackType);
+ }
+ return;
+ }
+ try {
+ ICharSequenceResultCallback.Stub.asInterface(command.mResultCallback).onResult(result);
+ } catch (Throwable e) {
+ if (tag != null) {
+ Log.e(tag, InputMethodDebug.inputConnectionCommandTypeToString(command.mCommandType)
+ + ": Failed to return result=" + result, e);
+ }
+ }
+ }
+
+ /**
+ * A utility method to reply associated with {@link InputConnectionCommand}.
+ *
+ * @param command {@link InputConnectionCommand} to be replied.
+ * @param result a {@link ExtractedText} result value to be replied.
+ * @param tag tag name to be used for debug output when the invocation fails.
+ */
+ public static void onResult(@NonNull InputConnectionCommand command,
+ @Nullable ExtractedText result, @Nullable String tag) {
+ if (command.mResultCallbackType
+ != InputConnectionCommand.ResultCallbackType.EXTRACTED_TEXT) {
+ if (tag != null) {
+ Log.e(tag, InputMethodDebug.inputConnectionCommandTypeToString(command.mCommandType)
+ + ": Failed to return result=" + result + " due to callback type mismatch."
+ + " expected=ExtractedText actual=" + command.mResultCallbackType);
+ }
+ return;
+ }
+ try {
+ IExtractedTextResultCallback.Stub.asInterface(command.mResultCallback).onResult(result);
+ } catch (Throwable e) {
+ if (tag != null) {
+ Log.e(tag, InputMethodDebug.inputConnectionCommandTypeToString(command.mCommandType)
+ + ": Failed to return result=" + result, e);
+ }
+ }
+ }
+
+ /**
+ * A utility method to reply associated with {@link InputConnectionCommand}.
+ *
+ * @param command {@link InputConnectionCommand} to be replied.
+ * @param result a {@link SurroundingText} result value to be replied.
+ * @param tag tag name to be used for debug output when the invocation fails.
+ */
+ public static void onResult(@NonNull InputConnectionCommand command,
+ @Nullable SurroundingText result, @Nullable String tag) {
+ if (command.mResultCallbackType
+ != InputConnectionCommand.ResultCallbackType.SURROUNDING_TEXT) {
+ if (tag != null) {
+ Log.e(tag, InputMethodDebug.inputConnectionCommandTypeToString(command.mCommandType)
+ + ": Failed to return result=" + result + " due to callback type mismatch."
+ + " expected=SurroundingText actual=" + command.mResultCallbackType);
+ }
+ return;
+ }
+ try {
+ ISurroundingTextResultCallback.Stub.asInterface(command.mResultCallback)
+ .onResult(result);
+ } catch (Throwable e) {
+ if (tag != null) {
+ Log.e(tag, InputMethodDebug.inputConnectionCommandTypeToString(command.mCommandType)
+ + ": Failed to return result=" + result, e);
+ }
+ }
+ }
}
diff --git a/core/java/com/android/internal/inputmethod/Completable.java b/core/java/com/android/internal/inputmethod/Completable.java
index b419e26..132272c 100644
--- a/core/java/com/android/internal/inputmethod/Completable.java
+++ b/core/java/com/android/internal/inputmethod/Completable.java
@@ -23,12 +23,10 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.util.Log;
-import android.view.inputmethod.InputMethodSubtype;
import com.android.internal.annotations.GuardedBy;
import java.lang.annotation.Retention;
-import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -416,34 +414,6 @@
}
/**
- * @return an instance of {@link Completable.InputBindResult}.
- */
- public static Completable.InputBindResult createInputBindResult() {
- return new Completable.InputBindResult();
- }
-
- /**
- * @return an instance of {@link Completable.InputMethodSubtype}.
- */
- public static Completable.InputMethodSubtype createInputMethodSubtype() {
- return new Completable.InputMethodSubtype();
- }
-
- /**
- * @return an instance of {@link Completable.InputMethodSubtypeList}.
- */
- public static Completable.InputMethodSubtypeList createInputMethodSubtypeList() {
- return new Completable.InputMethodSubtypeList();
- }
-
- /**
- * @return an instance of {@link Completable.InputMethodInfoList}.
- */
- public static Completable.InputMethodInfoList createInputMethodInfoList() {
- return new Completable.InputMethodInfoList();
- }
-
- /**
* @return an instance of {@link Completable.IInputContentUriToken}.
*/
public static Completable.IInputContentUriToken createIInputContentUriToken() {
@@ -480,30 +450,6 @@
extends Values<android.view.inputmethod.SurroundingText> { }
/**
- * Completable object of {@link com.android.internal.view.InputBindResult}.
- */
- public static final class InputBindResult
- extends Values<com.android.internal.view.InputBindResult> { }
-
- /**
- * Completable object of {@link android.view.inputmethod.InputMethodSubtype}.
- */
- public static final class InputMethodSubtype
- extends Values<android.view.inputmethod.InputMethodSubtype> { }
-
- /**
- * Completable object of {@link List<android.view.inputmethod.InputMethodSubtype>}.
- */
- public static final class InputMethodSubtypeList
- extends Values<List<android.view.inputmethod.InputMethodSubtype>> { }
-
- /**
- * Completable object of {@link List<android.view.inputmethod.InputMethodInfo>}.
- */
- public static final class InputMethodInfoList
- extends Values<List<android.view.inputmethod.InputMethodInfo>> { }
-
- /**
* Completable object of {@link IInputContentUriToken>}.
*/
public static final class IInputContentUriToken
diff --git a/core/java/com/android/internal/inputmethod/IIInputContentUriTokenResultCallback.aidl b/core/java/com/android/internal/inputmethod/IInputContentUriTokenResultCallback.aidl
similarity index 94%
rename from core/java/com/android/internal/inputmethod/IIInputContentUriTokenResultCallback.aidl
rename to core/java/com/android/internal/inputmethod/IInputContentUriTokenResultCallback.aidl
index 2e6d224..779acb5 100644
--- a/core/java/com/android/internal/inputmethod/IIInputContentUriTokenResultCallback.aidl
+++ b/core/java/com/android/internal/inputmethod/IInputContentUriTokenResultCallback.aidl
@@ -19,7 +19,7 @@
import com.android.internal.inputmethod.IInputContentUriToken;
import com.android.internal.inputmethod.ThrowableHolder;
-oneway interface IIInputContentUriTokenResultCallback {
+oneway interface IInputContentUriTokenResultCallback {
void onResult(in IInputContentUriToken result);
void onError(in ThrowableHolder exception);
}
\ No newline at end of file
diff --git a/core/java/com/android/internal/inputmethod/IInputContextInvoker.java b/core/java/com/android/internal/inputmethod/IInputContextInvoker.java
index 977f9a5..7a43a55 100644
--- a/core/java/com/android/internal/inputmethod/IInputContextInvoker.java
+++ b/core/java/com/android/internal/inputmethod/IInputContextInvoker.java
@@ -18,6 +18,7 @@
import android.annotation.AnyThread;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.os.Bundle;
import android.os.RemoteException;
import android.view.KeyEvent;
@@ -32,7 +33,7 @@
/**
* A stateless wrapper of {@link com.android.internal.view.IInputContext} to encapsulate boilerplate
- * code around {@link Completable} and {@link RemoteException}.
+ * code around {@link InputConnectionCommand}, {@link Completable} and {@link RemoteException}.
*/
public final class IInputContextInvoker {
@@ -55,8 +56,7 @@
}
/**
- * Invokes {@link IInputContext#getTextAfterCursor(int, int,
- * com.android.internal.inputmethod.ICharSequenceResultCallback)}.
+ * Implements {@link android.view.inputmethod.InputConnection#getTextAfterCursor(int, int)}.
*
* @param length {@code length} parameter to be passed.
* @param flags {@code flags} parameter to be passed.
@@ -67,8 +67,9 @@
@NonNull
public Completable.CharSequence getTextAfterCursor(int length, int flags) {
final Completable.CharSequence value = Completable.createCharSequence();
+ final InputConnectionCommand command = Commands.getTextAfterCursor(length, flags, value);
try {
- mIInputContext.getTextAfterCursor(length, flags, ResultCallbacks.of(value));
+ mIInputContext.doEdit(command);
} catch (RemoteException e) {
value.onError(ThrowableHolder.of(e));
}
@@ -76,7 +77,7 @@
}
/**
- * Invokes {@link IInputContext#getTextBeforeCursor(int, int, ICharSequenceResultCallback)}.
+ * Implements {@link android.view.inputmethod.InputConnection#getTextBeforeCursor(int, int)}.
*
* @param length {@code length} parameter to be passed.
* @param flags {@code flags} parameter to be passed.
@@ -87,8 +88,9 @@
@NonNull
public Completable.CharSequence getTextBeforeCursor(int length, int flags) {
final Completable.CharSequence value = Completable.createCharSequence();
+ final InputConnectionCommand command = Commands.getTextBeforeCursor(length, flags, value);
try {
- mIInputContext.getTextBeforeCursor(length, flags, ResultCallbacks.of(value));
+ mIInputContext.doEdit(command);
} catch (RemoteException e) {
value.onError(ThrowableHolder.of(e));
}
@@ -96,7 +98,7 @@
}
/**
- * Invokes {@link IInputContext#getSelectedText(int, ICharSequenceResultCallback)}.
+ * Implements {@link android.view.inputmethod.InputConnection#getSelectedText(int)}.
*
* @param flags {@code flags} parameter to be passed.
* @return {@link Completable.CharSequence} that can be used to retrieve the invocation result.
@@ -106,8 +108,9 @@
@NonNull
public Completable.CharSequence getSelectedText(int flags) {
final Completable.CharSequence value = Completable.createCharSequence();
+ final InputConnectionCommand command = Commands.getSelectedText(flags, value);
try {
- mIInputContext.getSelectedText(flags, ResultCallbacks.of(value));
+ mIInputContext.doEdit(command);
} catch (RemoteException e) {
value.onError(ThrowableHolder.of(e));
}
@@ -115,8 +118,8 @@
}
/**
- * Invokes
- * {@link IInputContext#getSurroundingText(int, int, int, ISurroundingTextResultCallback)}.
+ * Implements
+ * {@link android.view.inputmethod.InputConnection#getSurroundingText(int, int, int)}.
*
* @param beforeLength {@code beforeLength} parameter to be passed.
* @param afterLength {@code afterLength} parameter to be passed.
@@ -129,9 +132,10 @@
public Completable.SurroundingText getSurroundingText(int beforeLength, int afterLength,
int flags) {
final Completable.SurroundingText value = Completable.createSurroundingText();
+ final InputConnectionCommand command =
+ Commands.getSurroundingText(beforeLength, afterLength, flags, value);
try {
- mIInputContext.getSurroundingText(beforeLength, afterLength, flags,
- ResultCallbacks.of(value));
+ mIInputContext.doEdit(command);
} catch (RemoteException e) {
value.onError(ThrowableHolder.of(e));
}
@@ -139,7 +143,7 @@
}
/**
- * Invokes {@link IInputContext#getCursorCapsMode(int, IIntResultCallback)}.
+ * Implements {@link android.view.inputmethod.InputConnection#getCursorCapsMode(int)}.
*
* @param reqModes {@code reqModes} parameter to be passed.
* @return {@link Completable.Int} that can be used to retrieve the invocation result.
@@ -149,8 +153,9 @@
@NonNull
public Completable.Int getCursorCapsMode(int reqModes) {
final Completable.Int value = Completable.createInt();
+ final InputConnectionCommand command = Commands.getCursorCapsMode(reqModes, value);
try {
- mIInputContext.getCursorCapsMode(reqModes, ResultCallbacks.of(value));
+ mIInputContext.doEdit(command);
} catch (RemoteException e) {
value.onError(ThrowableHolder.of(e));
}
@@ -158,8 +163,8 @@
}
/**
- * Invokes {@link IInputContext#getExtractedText(ExtractedTextRequest, int,
- * IExtractedTextResultCallback)}.
+ * Implements
+ * {@link android.view.inputmethod.InputConnection#getExtractedText(ExtractedTextRequest, int)}.
*
* @param request {@code request} parameter to be passed.
* @param flags {@code flags} parameter to be passed.
@@ -170,8 +175,9 @@
@NonNull
public Completable.ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
final Completable.ExtractedText value = Completable.createExtractedText();
+ final InputConnectionCommand command = Commands.getExtractedText(request, flags, value);
try {
- mIInputContext.getExtractedText(request, flags, ResultCallbacks.of(value));
+ mIInputContext.doEdit(command);
} catch (RemoteException e) {
value.onError(ThrowableHolder.of(e));
}
@@ -179,7 +185,7 @@
}
/**
- * Invokes {@link IInputContext#commitText(CharSequence, int)}.
+ * Implements {@link android.view.inputmethod.InputConnection#commitText(CharSequence, int)}.
*
* @param text {@code text} parameter to be passed.
* @param newCursorPosition {@code newCursorPosition} parameter to be passed.
@@ -188,8 +194,9 @@
*/
@AnyThread
public boolean commitText(CharSequence text, int newCursorPosition) {
+ final InputConnectionCommand command = Commands.commitText(text, newCursorPosition);
try {
- mIInputContext.commitText(text, newCursorPosition);
+ mIInputContext.doEdit(command);
return true;
} catch (RemoteException e) {
return false;
@@ -197,7 +204,7 @@
}
/**
- * Invokes {@link IInputContext#commitCompletion(CompletionInfo)}.
+ * Implements {@link android.view.inputmethod.InputConnection#commitCompletion(CompletionInfo)}.
*
* @param text {@code text} parameter to be passed.
* @return {@code true} if the invocation is completed without {@link RemoteException}.
@@ -205,8 +212,9 @@
*/
@AnyThread
public boolean commitCompletion(CompletionInfo text) {
+ final InputConnectionCommand command = Commands.commitCompletion(text);
try {
- mIInputContext.commitCompletion(text);
+ mIInputContext.doEdit(command);
return true;
} catch (RemoteException e) {
return false;
@@ -214,7 +222,7 @@
}
/**
- * Invokes {@link IInputContext#commitCorrection(CorrectionInfo)}.
+ * Implements {@link android.view.inputmethod.InputConnection#commitCorrection(CorrectionInfo)}.
*
* @param correctionInfo {@code correctionInfo} parameter to be passed.
* @return {@code true} if the invocation is completed without {@link RemoteException}.
@@ -222,8 +230,9 @@
*/
@AnyThread
public boolean commitCorrection(CorrectionInfo correctionInfo) {
+ final InputConnectionCommand command = Commands.commitCorrection(correctionInfo);
try {
- mIInputContext.commitCorrection(correctionInfo);
+ mIInputContext.doEdit(command);
return true;
} catch (RemoteException e) {
return false;
@@ -231,7 +240,7 @@
}
/**
- * Invokes {@link IInputContext#setSelection(int, int)}.
+ * Implements {@link android.view.inputmethod.InputConnection#setSelection(int, int)}.
*
* @param start {@code start} parameter to be passed.
* @param end {@code start} parameter to be passed.
@@ -240,8 +249,9 @@
*/
@AnyThread
public boolean setSelection(int start, int end) {
+ final InputConnectionCommand command = Commands.setSelection(start, end);
try {
- mIInputContext.setSelection(start, end);
+ mIInputContext.doEdit(command);
return true;
} catch (RemoteException e) {
return false;
@@ -249,7 +259,7 @@
}
/**
- * Invokes {@link IInputContext#performEditorAction(int)}.
+ * Implements {@link android.view.inputmethod.InputConnection#performEditorAction(int)}.
*
* @param actionCode {@code start} parameter to be passed.
* @return {@code true} if the invocation is completed without {@link RemoteException}.
@@ -257,8 +267,9 @@
*/
@AnyThread
public boolean performEditorAction(int actionCode) {
+ final InputConnectionCommand command = Commands.performEditorAction(actionCode);
try {
- mIInputContext.performEditorAction(actionCode);
+ mIInputContext.doEdit(command);
return true;
} catch (RemoteException e) {
return false;
@@ -266,7 +277,7 @@
}
/**
- * Invokes {@link IInputContext#performContextMenuAction(id)}.
+ * Implements {@link android.view.inputmethod.InputConnection#performContextMenuAction(int)}.
*
* @param id {@code id} parameter to be passed.
* @return {@code true} if the invocation is completed without {@link RemoteException}.
@@ -274,8 +285,9 @@
*/
@AnyThread
public boolean performContextMenuAction(int id) {
+ final InputConnectionCommand command = Commands.performContextMenuAction(id);
try {
- mIInputContext.performContextMenuAction(id);
+ mIInputContext.doEdit(command);
return true;
} catch (RemoteException e) {
return false;
@@ -283,7 +295,7 @@
}
/**
- * Invokes {@link IInputContext#setComposingRegion(int, int)}.
+ * Implements {@link android.view.inputmethod.InputConnection#setComposingRegion(int, int)}.
*
* @param start {@code id} parameter to be passed.
* @param end {@code id} parameter to be passed.
@@ -292,8 +304,9 @@
*/
@AnyThread
public boolean setComposingRegion(int start, int end) {
+ final InputConnectionCommand command = Commands.setComposingRegion(start, end);
try {
- mIInputContext.setComposingRegion(start, end);
+ mIInputContext.doEdit(command);
return true;
} catch (RemoteException e) {
return false;
@@ -301,7 +314,8 @@
}
/**
- * Invokes {@link IInputContext#setComposingText(CharSequence, int)}.
+ * Implements
+ * {@link android.view.inputmethod.InputConnection#setComposingText(CharSequence, int)}.
*
* @param text {@code text} parameter to be passed.
* @param newCursorPosition {@code newCursorPosition} parameter to be passed.
@@ -310,8 +324,9 @@
*/
@AnyThread
public boolean setComposingText(CharSequence text, int newCursorPosition) {
+ final InputConnectionCommand command = Commands.setComposingText(text, newCursorPosition);
try {
- mIInputContext.setComposingText(text, newCursorPosition);
+ mIInputContext.doEdit(command);
return true;
} catch (RemoteException e) {
return false;
@@ -319,15 +334,16 @@
}
/**
- * Invokes {@link IInputContext#finishComposingText()}.
+ * Implements {@link android.view.inputmethod.InputConnection#finishComposingText()}.
*
* @return {@code true} if the invocation is completed without {@link RemoteException}.
* {@code false} otherwise.
*/
@AnyThread
public boolean finishComposingText() {
+ final InputConnectionCommand command = Commands.finishComposingText();
try {
- mIInputContext.finishComposingText();
+ mIInputContext.doEdit(command);
return true;
} catch (RemoteException e) {
return false;
@@ -335,15 +351,16 @@
}
/**
- * Invokes {@link IInputContext#beginBatchEdit()}.
+ * Implements {@link android.view.inputmethod.InputConnection#beginBatchEdit()}.
*
* @return {@code true} if the invocation is completed without {@link RemoteException}.
* {@code false} otherwise.
*/
@AnyThread
public boolean beginBatchEdit() {
+ final InputConnectionCommand command = Commands.beginBatchEdit();
try {
- mIInputContext.beginBatchEdit();
+ mIInputContext.doEdit(command);
return true;
} catch (RemoteException e) {
return false;
@@ -351,15 +368,16 @@
}
/**
- * Invokes {@link IInputContext#endBatchEdit()}.
+ * Implements {@link android.view.inputmethod.InputConnection#endBatchEdit()}.
*
* @return {@code true} if the invocation is completed without {@link RemoteException}.
* {@code false} otherwise.
*/
@AnyThread
public boolean endBatchEdit() {
+ final InputConnectionCommand command = Commands.endBatchEdit();
try {
- mIInputContext.endBatchEdit();
+ mIInputContext.doEdit(command);
return true;
} catch (RemoteException e) {
return false;
@@ -367,7 +385,7 @@
}
/**
- * Invokes {@link IInputContext#sendKeyEvent(KeyEvent)}.
+ * Implements {@link android.view.inputmethod.InputConnection#sendKeyEvent(KeyEvent)}.
*
* @param event {@code event} parameter to be passed.
* @return {@code true} if the invocation is completed without {@link RemoteException}.
@@ -375,8 +393,9 @@
*/
@AnyThread
public boolean sendKeyEvent(KeyEvent event) {
+ final InputConnectionCommand command = Commands.sendKeyEvent(event);
try {
- mIInputContext.sendKeyEvent(event);
+ mIInputContext.doEdit(command);
return true;
} catch (RemoteException e) {
return false;
@@ -384,7 +403,7 @@
}
/**
- * Invokes {@link IInputContext#clearMetaKeyStates(int)}.
+ * Implements {@link android.view.inputmethod.InputConnection#clearMetaKeyStates(int)}.
*
* @param states {@code states} parameter to be passed.
* @return {@code true} if the invocation is completed without {@link RemoteException}.
@@ -392,8 +411,9 @@
*/
@AnyThread
public boolean clearMetaKeyStates(int states) {
+ final InputConnectionCommand command = Commands.clearMetaKeyStates(states);
try {
- mIInputContext.clearMetaKeyStates(states);
+ mIInputContext.doEdit(command);
return true;
} catch (RemoteException e) {
return false;
@@ -401,7 +421,7 @@
}
/**
- * Invokes {@link IInputContext#deleteSurroundingText(int, int)}.
+ * Implements {@link android.view.inputmethod.InputConnection#deleteSurroundingText(int, int)}.
*
* @param beforeLength {@code beforeLength} parameter to be passed.
* @param afterLength {@code afterLength} parameter to be passed.
@@ -410,8 +430,10 @@
*/
@AnyThread
public boolean deleteSurroundingText(int beforeLength, int afterLength) {
+ final InputConnectionCommand command =
+ Commands.deleteSurroundingText(beforeLength, afterLength);
try {
- mIInputContext.deleteSurroundingText(beforeLength, afterLength);
+ mIInputContext.doEdit(command);
return true;
} catch (RemoteException e) {
return false;
@@ -419,7 +441,8 @@
}
/**
- * Invokes {@link IInputContext#deleteSurroundingTextInCodePoints(int, int)}.
+ * Implements
+ * {@link android.view.inputmethod.InputConnection#deleteSurroundingTextInCodePoints(int, int)}.
*
* @param beforeLength {@code beforeLength} parameter to be passed.
* @param afterLength {@code afterLength} parameter to be passed.
@@ -428,8 +451,10 @@
*/
@AnyThread
public boolean deleteSurroundingTextInCodePoints(int beforeLength, int afterLength) {
+ final InputConnectionCommand command =
+ Commands.deleteSurroundingTextInCodePoints(beforeLength, afterLength);
try {
- mIInputContext.deleteSurroundingTextInCodePoints(beforeLength, afterLength);
+ mIInputContext.doEdit(command);
return true;
} catch (RemoteException e) {
return false;
@@ -437,15 +462,16 @@
}
/**
- * Invokes {@link IInputContext#performSpellCheck()}.
+ * Implements {@link android.view.inputmethod.InputConnection#performSpellCheck()}.
*
* @return {@code true} if the invocation is completed without {@link RemoteException}.
* {@code false} otherwise.
*/
@AnyThread
public boolean performSpellCheck() {
+ final InputConnectionCommand command = Commands.performSpellCheck();
try {
- mIInputContext.performSpellCheck();
+ mIInputContext.doEdit(command);
return true;
} catch (RemoteException e) {
return false;
@@ -453,7 +479,8 @@
}
/**
- * Invokes {@link IInputContext#performPrivateCommand(String, Bundle)}.
+ * Implements
+ * {@link android.view.inputmethod.InputConnection#performPrivateCommand(String, Bundle)}.
*
* @param action {@code action} parameter to be passed.
* @param data {@code data} parameter to be passed.
@@ -462,8 +489,9 @@
*/
@AnyThread
public boolean performPrivateCommand(String action, Bundle data) {
+ final InputConnectionCommand command = Commands.performPrivateCommand(action, data);
try {
- mIInputContext.performPrivateCommand(action, data);
+ mIInputContext.doEdit(command);
return true;
} catch (RemoteException e) {
return false;
@@ -471,7 +499,7 @@
}
/**
- * Invokes {@link IInputContext#requestCursorUpdates(int, IIntResultCallback)}.
+ * Implements {@link android.view.inputmethod.InputConnection#requestCursorUpdates(int)}.
*
* @param cursorUpdateMode {@code cursorUpdateMode} parameter to be passed.
* @return {@link Completable.Boolean} that can be used to retrieve the invocation result.
@@ -481,8 +509,10 @@
@NonNull
public Completable.Boolean requestCursorUpdates(int cursorUpdateMode) {
final Completable.Boolean value = Completable.createBoolean();
+ final InputConnectionCommand command =
+ Commands.requestCursorUpdates(cursorUpdateMode, value);
try {
- mIInputContext.requestCursorUpdates(cursorUpdateMode, ResultCallbacks.of(value));
+ mIInputContext.doEdit(command);
} catch (RemoteException e) {
value.onError(ThrowableHolder.of(e));
}
@@ -490,8 +520,8 @@
}
/**
- * Invokes
- * {@link IInputContext#commitContent(InputContentInfo, int, Bundle, IIntResultCallback)}.
+ * Implements {@link android.view.inputmethod.InputConnection#commitContent(InputContentInfo,
+ * int, Bundle)}.
*
* @param inputContentInfo {@code inputContentInfo} parameter to be passed.
* @param flags {@code flags} parameter to be passed.
@@ -504,8 +534,10 @@
public Completable.Boolean commitContent(InputContentInfo inputContentInfo, int flags,
Bundle opts) {
final Completable.Boolean value = Completable.createBoolean();
+ final InputConnectionCommand command =
+ Commands.commitContent(inputContentInfo, flags, opts, value);
try {
- mIInputContext.commitContent(inputContentInfo, flags, opts, ResultCallbacks.of(value));
+ mIInputContext.doEdit(command);
} catch (RemoteException e) {
value.onError(ThrowableHolder.of(e));
}
@@ -513,7 +545,7 @@
}
/**
- * Invokes {@link IInputContext#setImeConsumesInput(boolean)}.
+ * Implements {@link android.view.inputmethod.InputConnection#setImeConsumesInput(boolean)}.
*
* @param imeConsumesInput {@code imeConsumesInput} parameter to be passed.
* @return {@code true} if the invocation is completed without {@link RemoteException}.
@@ -521,11 +553,341 @@
*/
@AnyThread
public boolean setImeConsumesInput(boolean imeConsumesInput) {
+ final InputConnectionCommand command = Commands.setImeConsumesInput(imeConsumesInput);
try {
- mIInputContext.setImeConsumesInput(imeConsumesInput);
+ mIInputContext.doEdit(command);
return true;
} catch (RemoteException e) {
return false;
}
}
+
+ /**
+ * Defines the data packing rules from {@link android.view.inputmethod.InputConnection} API
+ * params into {@link InputConnectionCommand} fields.
+ *
+ * Rules need to be in sync with {@link com.android.internal.view.IInputConnectionWrapper} and
+ * {@link InputMethodDebug#dumpInputConnectionCommand(InputConnectionCommand)}.
+ */
+ private static final class Commands {
+ /**
+ * Not intended to be instantiated.
+ */
+ private Commands() { }
+
+ @AnyThread
+ @NonNull
+ static InputConnectionCommand getTextAfterCursor(int n, int flags,
+ @NonNull Completable.CharSequence returnValue) {
+ return InputConnectionCommand.create(
+ InputConnectionCommandType.GET_TEXT_AFTER_CURSOR,
+ n,
+ 0,
+ flags,
+ null,
+ null,
+ null,
+ InputConnectionCommand.ParcelableType.NULL,
+ null,
+ returnValue);
+ }
+
+ @AnyThread
+ @NonNull
+ static InputConnectionCommand getTextBeforeCursor(int n, int flags,
+ @NonNull Completable.CharSequence returnValue) {
+ return InputConnectionCommand.create(
+ InputConnectionCommandType.GET_TEXT_BEFORE_CURSOR,
+ n,
+ 0,
+ flags,
+ null,
+ null,
+ null,
+ InputConnectionCommand.ParcelableType.NULL,
+ null,
+ returnValue);
+ }
+
+ @AnyThread
+ @NonNull
+ static InputConnectionCommand getSelectedText(int flags,
+ @NonNull Completable.CharSequence returnValue) {
+ return InputConnectionCommand.create(
+ InputConnectionCommandType.GET_SELECTED_TEXT,
+ 0,
+ 0,
+ flags,
+ null,
+ null,
+ null,
+ InputConnectionCommand.ParcelableType.NULL,
+ null,
+ returnValue);
+ }
+
+ @AnyThread
+ @NonNull
+ static InputConnectionCommand getSurroundingText(int beforeLength, int afterLength,
+ int flags, @NonNull Completable.SurroundingText returnValue) {
+ return InputConnectionCommand.create(
+ InputConnectionCommandType.GET_SURROUNDING_TEXT,
+ beforeLength,
+ afterLength,
+ flags,
+ null,
+ null,
+ null,
+ InputConnectionCommand.ParcelableType.NULL,
+ null,
+ returnValue);
+ }
+
+ @AnyThread
+ @NonNull
+ static InputConnectionCommand getCursorCapsMode(int reqModes,
+ @NonNull Completable.Int returnValue) {
+ return InputConnectionCommand.create(
+ InputConnectionCommandType.GET_CURSOR_CAPS_MODE,
+ reqModes,
+ 0,
+ 0,
+ null,
+ null,
+ null,
+ InputConnectionCommand.ParcelableType.NULL,
+ null,
+ returnValue);
+ }
+
+ @AnyThread
+ @NonNull
+ static InputConnectionCommand getExtractedText(@Nullable ExtractedTextRequest request,
+ int flags, @NonNull Completable.ExtractedText returnValue) {
+ return InputConnectionCommand.create(
+ InputConnectionCommandType.GET_EXTRACTED_TEXT,
+ 0,
+ 0,
+ flags,
+ null,
+ null,
+ null,
+ InputConnectionCommand.ParcelableType.EXTRACTED_TEXT_REQUEST,
+ request,
+ returnValue);
+ }
+
+ @AnyThread
+ @NonNull
+ static InputConnectionCommand commitText(@Nullable CharSequence text,
+ int newCursorPosition) {
+ return InputConnectionCommand.create(
+ InputConnectionCommandType.COMMIT_TEXT,
+ newCursorPosition,
+ 0,
+ 0,
+ text);
+ }
+
+ @AnyThread
+ @NonNull
+ static InputConnectionCommand commitCompletion(@Nullable CompletionInfo text) {
+ return InputConnectionCommand.create(
+ InputConnectionCommandType.COMMIT_COMPLETION,
+ 0,
+ 0,
+ 0,
+ null,
+ null,
+ null,
+ InputConnectionCommand.ParcelableType.COMPLETION_INFO,
+ text);
+ }
+
+ @AnyThread
+ @NonNull
+ static InputConnectionCommand commitCorrection(@Nullable CorrectionInfo correctionInfo) {
+ return InputConnectionCommand.create(
+ InputConnectionCommandType.COMMIT_CORRECTION,
+ 0,
+ 0,
+ 0,
+ null,
+ null,
+ null,
+ InputConnectionCommand.ParcelableType.CORRECTION_INFO,
+ correctionInfo);
+ }
+
+ @AnyThread
+ @NonNull
+ static InputConnectionCommand setSelection(int start, int end) {
+ return InputConnectionCommand.create(
+ InputConnectionCommandType.SET_SELECTION,
+ start,
+ end);
+ }
+
+ @AnyThread
+ @NonNull
+ static InputConnectionCommand performEditorAction(int actionCode) {
+ return InputConnectionCommand.create(
+ InputConnectionCommandType.PERFORM_EDITOR_ACTION,
+ actionCode);
+ }
+
+ @AnyThread
+ @NonNull
+ static InputConnectionCommand performContextMenuAction(int id) {
+ return InputConnectionCommand.create(
+ InputConnectionCommandType.PERFORM_CONTEXT_MENU_ACTION,
+ id);
+ }
+
+ @AnyThread
+ @NonNull
+ static InputConnectionCommand setComposingRegion(int start, int end) {
+ return InputConnectionCommand.create(
+ InputConnectionCommandType.SET_COMPOSING_REGION,
+ start,
+ end);
+ }
+
+ @AnyThread
+ @NonNull
+ static InputConnectionCommand setComposingText(@Nullable CharSequence text,
+ int newCursorPosition) {
+ return InputConnectionCommand.create(
+ InputConnectionCommandType.SET_COMPOSING_TEXT,
+ newCursorPosition,
+ 0,
+ 0,
+ text);
+ }
+
+ @AnyThread
+ @NonNull
+ static InputConnectionCommand finishComposingText() {
+ return InputConnectionCommand.create(
+ InputConnectionCommandType.FINISH_COMPOSING_TEXT);
+ }
+
+ @AnyThread
+ @NonNull
+ static InputConnectionCommand beginBatchEdit() {
+ return InputConnectionCommand.create(
+ InputConnectionCommandType.BEGIN_BATCH_EDIT);
+ }
+
+ @AnyThread
+ @NonNull
+ static InputConnectionCommand endBatchEdit() {
+ return InputConnectionCommand.create(
+ InputConnectionCommandType.END_BATCH_EDIT);
+ }
+
+ @AnyThread
+ @NonNull
+ static InputConnectionCommand sendKeyEvent(@Nullable KeyEvent event) {
+ return InputConnectionCommand.create(
+ InputConnectionCommandType.SEND_KEY_EVENT,
+ 0,
+ 0,
+ 0,
+ null,
+ null,
+ null,
+ InputConnectionCommand.ParcelableType.KEY_EVENT,
+ event);
+ }
+
+ @AnyThread
+ @NonNull
+ static InputConnectionCommand clearMetaKeyStates(int states) {
+ return InputConnectionCommand.create(
+ InputConnectionCommandType.CLEAR_META_KEY_STATES,
+ states);
+ }
+
+ @AnyThread
+ @NonNull
+ static InputConnectionCommand deleteSurroundingText(int beforeLength, int afterLength) {
+ return InputConnectionCommand.create(
+ InputConnectionCommandType.DELETE_SURROUNDING_TEXT,
+ beforeLength,
+ afterLength);
+ }
+
+ @AnyThread
+ @NonNull
+ static InputConnectionCommand deleteSurroundingTextInCodePoints(int beforeLength,
+ int afterLength) {
+ return InputConnectionCommand.create(
+ InputConnectionCommandType.DELETE_SURROUNDING_TEXT_IN_CODE_POINTS,
+ beforeLength,
+ afterLength);
+ }
+
+ @AnyThread
+ @NonNull
+ static InputConnectionCommand performSpellCheck() {
+ return InputConnectionCommand.create(InputConnectionCommandType.PERFORM_SPELL_CHECK);
+ }
+
+ @AnyThread
+ @NonNull
+ static InputConnectionCommand performPrivateCommand(@Nullable String action,
+ @Nullable Bundle data) {
+ return InputConnectionCommand.create(
+ InputConnectionCommandType.PERFORM_PRIVATE_COMMAND,
+ 0,
+ 0,
+ 0,
+ null,
+ action,
+ data);
+ }
+
+ @AnyThread
+ @NonNull
+ static InputConnectionCommand requestCursorUpdates(int cursorUpdateMode,
+ @NonNull Completable.Boolean returnValue) {
+ return InputConnectionCommand.create(
+ InputConnectionCommandType.REQUEST_CURSOR_UPDATES,
+ cursorUpdateMode,
+ 0,
+ 0,
+ null,
+ null,
+ null,
+ InputConnectionCommand.ParcelableType.NULL,
+ null,
+ returnValue);
+ }
+
+ @AnyThread
+ @NonNull
+ static InputConnectionCommand commitContent(@Nullable InputContentInfo inputContentInfo,
+ int flags, @Nullable Bundle opts, @NonNull Completable.Boolean returnValue) {
+ return InputConnectionCommand.create(
+ InputConnectionCommandType.COMMIT_CONTENT,
+ 0,
+ 0,
+ flags,
+ null,
+ null,
+ opts,
+ InputConnectionCommand.ParcelableType.INPUT_CONTENT_INFO,
+ inputContentInfo,
+ returnValue);
+ }
+
+ @AnyThread
+ @NonNull
+ static InputConnectionCommand setImeConsumesInput(boolean imeConsumesInput) {
+ return InputConnectionCommand.create(
+ InputConnectionCommandType.SET_IME_CONSUMES_INPUT,
+ imeConsumesInput ? 1 : 0);
+ }
+ }
}
diff --git a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
index 11df5a8..36943e3 100644
--- a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
+++ b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
@@ -21,7 +21,7 @@
import com.android.internal.inputmethod.IBooleanResultCallback;
import com.android.internal.inputmethod.IInputContentUriToken;
-import com.android.internal.inputmethod.IIInputContentUriTokenResultCallback;
+import com.android.internal.inputmethod.IInputContentUriTokenResultCallback;
import com.android.internal.inputmethod.IVoidResultCallback;
/**
@@ -32,7 +32,7 @@
void setImeWindowStatusAsync(int vis, int backDisposition);
void reportStartInputAsync(in IBinder startInputToken);
void createInputContentUriToken(in Uri contentUri, in String packageName,
- in IIInputContentUriTokenResultCallback resultCallback);
+ in IInputContentUriTokenResultCallback resultCallback);
void reportFullscreenModeAsync(boolean fullscreen);
void setInputMethod(String id, in IVoidResultCallback resultCallback);
void setInputMethodAndSubtype(String id, in InputMethodSubtype subtype,
diff --git a/core/java/com/android/internal/inputmethod/IIInputContentUriTokenResultCallback.aidl b/core/java/com/android/internal/inputmethod/InputConnectionCommand.aidl
similarity index 64%
copy from core/java/com/android/internal/inputmethod/IIInputContentUriTokenResultCallback.aidl
copy to core/java/com/android/internal/inputmethod/InputConnectionCommand.aidl
index 2e6d224..c7c2ad8 100644
--- a/core/java/com/android/internal/inputmethod/IIInputContentUriTokenResultCallback.aidl
+++ b/core/java/com/android/internal/inputmethod/InputConnectionCommand.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -16,10 +16,4 @@
package com.android.internal.inputmethod;
-import com.android.internal.inputmethod.IInputContentUriToken;
-import com.android.internal.inputmethod.ThrowableHolder;
-
-oneway interface IIInputContentUriTokenResultCallback {
- void onResult(in IInputContentUriToken result);
- void onError(in ThrowableHolder exception);
-}
\ No newline at end of file
+parcelable InputConnectionCommand;
diff --git a/core/java/com/android/internal/inputmethod/InputConnectionCommand.java b/core/java/com/android/internal/inputmethod/InputConnectionCommand.java
new file mode 100644
index 0000000..4116b02
--- /dev/null
+++ b/core/java/com/android/internal/inputmethod/InputConnectionCommand.java
@@ -0,0 +1,460 @@
+/*
+ * 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.inputmethod;
+
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.AnyThread;
+import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.inputmethod.CompletionInfo;
+import android.view.inputmethod.CorrectionInfo;
+import android.view.inputmethod.ExtractedTextRequest;
+import android.view.inputmethod.InputContentInfo;
+
+import java.lang.annotation.Retention;
+
+/**
+ * Defines the command message to be used for IMEs to remotely invoke
+ * {@link android.view.inputmethod.InputConnection} APIs in the IME client process then receive
+ * results.
+ */
+public final class InputConnectionCommand implements Parcelable {
+ private static final String TAG = "InputConnectionCommand";
+
+ @Retention(SOURCE)
+ @IntDef(value = {
+ ResultCallbackType.NULL,
+ ResultCallbackType.BOOLEAN,
+ ResultCallbackType.INT,
+ ResultCallbackType.CHAR_SEQUENCE,
+ ResultCallbackType.EXTRACTED_TEXT,
+ ResultCallbackType.SURROUNDING_TEXT,
+ })
+ @interface ResultCallbackType {
+ int NULL = 0;
+ int BOOLEAN = 1;
+ int INT = 2;
+ int CHAR_SEQUENCE = 3;
+ int EXTRACTED_TEXT = 4;
+ int SURROUNDING_TEXT = 5;
+ }
+
+ @Retention(SOURCE)
+ @IntDef(value = {
+ ParcelableType.NULL,
+ ParcelableType.EXTRACTED_TEXT_REQUEST,
+ ParcelableType.COMPLETION_INFO,
+ ParcelableType.CORRECTION_INFO,
+ ParcelableType.KEY_EVENT,
+ ParcelableType.INPUT_CONTENT_INFO,
+ })
+ @interface ParcelableType {
+ int NULL = 0;
+ int EXTRACTED_TEXT_REQUEST = 1;
+ int COMPLETION_INFO = 2;
+ int CORRECTION_INFO = 3;
+ int KEY_EVENT = 4;
+ int INPUT_CONTENT_INFO = 5;
+ }
+
+ @Retention(SOURCE)
+ @IntDef(flag = true, value = {
+ FieldMask.INT_ARG0,
+ FieldMask.INT_ARG1,
+ FieldMask.FLAGS,
+ FieldMask.CHAR_SEQUENCE,
+ FieldMask.STRING,
+ FieldMask.BUNDLE,
+ FieldMask.PARCELABLE,
+ FieldMask.CALLBACK,
+ })
+ @interface FieldMask {
+ int INT_ARG0 = 1 << 0;
+ int INT_ARG1 = 1 << 1;
+ int FLAGS = 1 << 2;
+ int CHAR_SEQUENCE = 1 << 3;
+ int STRING = 1 << 4;
+ int BUNDLE = 1 << 5;
+ int PARCELABLE = 1 << 6;
+ int CALLBACK = 1 << 7;
+ }
+
+ @IntRange(from = InputConnectionCommandType.FIRST_COMMAND,
+ to = InputConnectionCommandType.LAST_COMMAND)
+ @InputConnectionCommandType
+ public final int mCommandType;
+ public final int mIntArg0;
+ public final int mIntArg1;
+ public final int mFlags;
+ public final CharSequence mCharSequence;
+ public final String mString;
+ public final Bundle mBundle;
+ @ParcelableType
+ public final int mParcelableType;
+ public final Parcelable mParcelable;
+ @ResultCallbackType
+ public final int mResultCallbackType;
+ public final IBinder mResultCallback;
+
+ private InputConnectionCommand(
+ @IntRange(
+ from = InputConnectionCommandType.FIRST_COMMAND,
+ to = InputConnectionCommandType.LAST_COMMAND)
+ @InputConnectionCommandType int type, int intArg0, int intArg1, int flags,
+ @Nullable CharSequence charSequence, @Nullable String string, @Nullable Bundle bundle,
+ @ParcelableType int parcelableType, @Nullable Parcelable parcelable,
+ @ResultCallbackType int resultCallbackType, @Nullable IBinder resultCallback) {
+ if (type < InputConnectionCommandType.FIRST_COMMAND
+ || InputConnectionCommandType.LAST_COMMAND < type) {
+ throw new IllegalArgumentException("Unknown type=" + type);
+ }
+ mCommandType = type;
+ mIntArg0 = intArg0;
+ mIntArg1 = intArg1;
+ mFlags = flags;
+ mCharSequence = charSequence;
+ mString = string;
+ mBundle = bundle;
+ mParcelableType = parcelableType;
+ mParcelable = parcelable;
+ mResultCallbackType = resultCallbackType;
+ mResultCallback = resultCallback;
+ }
+
+ /**
+ * Creates {@link InputConnectionCommand} with the given {@link InputConnectionCommandType}.
+ *
+ * @param type {@link InputConnectionCommandType} to be set.
+ * @return An {@link InputConnectionCommand} that is initialized with {@code type}.
+ */
+ @NonNull
+ public static InputConnectionCommand create(
+ @IntRange(
+ from = InputConnectionCommandType.FIRST_COMMAND,
+ to = InputConnectionCommandType.LAST_COMMAND)
+ @InputConnectionCommandType int type) {
+ return create(type, 0);
+ }
+
+ @NonNull
+ static InputConnectionCommand create(
+ @IntRange(
+ from = InputConnectionCommandType.FIRST_COMMAND,
+ to = InputConnectionCommandType.LAST_COMMAND)
+ @InputConnectionCommandType int type, int intArg0) {
+ return create(type, intArg0, 0);
+ }
+
+ @NonNull
+ static InputConnectionCommand create(
+ @IntRange(
+ from = InputConnectionCommandType.FIRST_COMMAND,
+ to = InputConnectionCommandType.LAST_COMMAND)
+ @InputConnectionCommandType int type, int intArg0, int intArg1) {
+ return create(type, intArg0, intArg1, 0, null);
+ }
+
+ @NonNull
+ static InputConnectionCommand create(
+ @IntRange(
+ from = InputConnectionCommandType.FIRST_COMMAND,
+ to = InputConnectionCommandType.LAST_COMMAND)
+ @InputConnectionCommandType int type, int intArg0,
+ int intArg1, int flags, @Nullable CharSequence charSequence) {
+ return create(type, intArg0, intArg1, flags, charSequence, null, null);
+ }
+
+ @NonNull
+ static InputConnectionCommand create(
+ @IntRange(
+ from = InputConnectionCommandType.FIRST_COMMAND,
+ to = InputConnectionCommandType.LAST_COMMAND)
+ @InputConnectionCommandType int type,
+ int intArg0, int intArg1, int flags, @Nullable CharSequence charSequence,
+ @Nullable String string, @Nullable Bundle bundle) {
+ return create(type, intArg0, intArg1, flags, charSequence, string,
+ bundle, ParcelableType.NULL, null);
+ }
+
+ @NonNull
+ static InputConnectionCommand create(
+ @IntRange(
+ from = InputConnectionCommandType.FIRST_COMMAND,
+ to = InputConnectionCommandType.LAST_COMMAND)
+ @InputConnectionCommandType int type,
+ int intArg0, int intArg1, int flags, @Nullable CharSequence charSequence,
+ @Nullable String string, @Nullable Bundle bundle,
+ @ParcelableType int parcelableType, @Nullable Parcelable parcelable) {
+ return new InputConnectionCommand(type, intArg0, intArg1, flags, charSequence, string,
+ bundle, parcelableType, parcelable, ResultCallbackType.NULL, null);
+ }
+
+ @NonNull
+ static InputConnectionCommand create(
+ @IntRange(
+ from = InputConnectionCommandType.FIRST_COMMAND,
+ to = InputConnectionCommandType.LAST_COMMAND)
+ @InputConnectionCommandType int type,
+ int intArg0, int intArg1, int flags, @Nullable CharSequence charSequence,
+ @Nullable String string, @Nullable Bundle bundle,
+ @ParcelableType int parcelableType, @Nullable Parcelable parcelable,
+ @NonNull Completable.Boolean returnValue) {
+ return new InputConnectionCommand(type, intArg0, intArg1, flags, charSequence, string,
+ bundle, parcelableType, parcelable,
+ ResultCallbackType.BOOLEAN, ResultCallbacks.of(returnValue));
+ }
+
+ @NonNull
+ static InputConnectionCommand create(
+ @IntRange(
+ from = InputConnectionCommandType.FIRST_COMMAND,
+ to = InputConnectionCommandType.LAST_COMMAND)
+ @InputConnectionCommandType int type,
+ int intArg0, int intArg1, int flags, @Nullable CharSequence charSequence,
+ @Nullable String string, @Nullable Bundle bundle,
+ @ParcelableType int parcelableType, @Nullable Parcelable parcelable,
+ @NonNull Completable.Int returnValue) {
+ return new InputConnectionCommand(type, intArg0, intArg1, flags, charSequence, string,
+ bundle, parcelableType, parcelable,
+ ResultCallbackType.INT, ResultCallbacks.of(returnValue));
+ }
+
+ @NonNull
+ static InputConnectionCommand create(
+ @IntRange(
+ from = InputConnectionCommandType.FIRST_COMMAND,
+ to = InputConnectionCommandType.LAST_COMMAND)
+ @InputConnectionCommandType int type,
+ int intArg0, int intArg1, int flags, @Nullable CharSequence charSequence,
+ @Nullable String string, @Nullable Bundle bundle,
+ @ParcelableType int parcelableType, @Nullable Parcelable parcelable,
+ @NonNull Completable.CharSequence returnValue) {
+ return new InputConnectionCommand(type, intArg0, intArg1, flags, charSequence, string,
+ bundle, parcelableType, parcelable,
+ ResultCallbackType.CHAR_SEQUENCE, ResultCallbacks.of(returnValue));
+ }
+
+ @NonNull
+ static InputConnectionCommand create(
+ @IntRange(
+ from = InputConnectionCommandType.FIRST_COMMAND,
+ to = InputConnectionCommandType.LAST_COMMAND)
+ @InputConnectionCommandType int type,
+ int intArg0, int intArg1, int flags, @Nullable CharSequence charSequence,
+ @Nullable String string, @Nullable Bundle bundle,
+ @ParcelableType int parcelableType, @Nullable Parcelable parcelable,
+ @NonNull Completable.ExtractedText returnValue) {
+ return new InputConnectionCommand(type, intArg0, intArg1, flags, charSequence, string,
+ bundle, parcelableType, parcelable,
+ ResultCallbackType.EXTRACTED_TEXT, ResultCallbacks.of(returnValue));
+ }
+
+ @NonNull
+ static InputConnectionCommand create(
+ @IntRange(
+ from = InputConnectionCommandType.FIRST_COMMAND,
+ to = InputConnectionCommandType.LAST_COMMAND)
+ @InputConnectionCommandType int type,
+ int intArg0, int intArg1, int flags, @Nullable CharSequence charSequence,
+ @Nullable String string, @Nullable Bundle bundle,
+ @ParcelableType int parcelableType, @Nullable Parcelable parcelable,
+ @NonNull Completable.SurroundingText returnValue) {
+ return new InputConnectionCommand(type, intArg0, intArg1, flags, charSequence, string,
+ bundle, parcelableType, parcelable,
+ ResultCallbackType.SURROUNDING_TEXT, ResultCallbacks.of(returnValue));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @AnyThread
+ @Override
+ public int describeContents() {
+ int result = 0;
+ if (mBundle != null) {
+ result |= mBundle.describeContents();
+ }
+ if (mParcelable != null) {
+ result |= mParcelable.describeContents();
+ }
+ // Here we assume other objects will never contain FDs to be parcelled.
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @AnyThread
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mCommandType);
+
+ @FieldMask final int fieldMask = getFieldMask();
+ dest.writeInt(fieldMask);
+ if ((fieldMask & FieldMask.INT_ARG0) != 0) {
+ dest.writeInt(mIntArg0);
+ }
+ if ((fieldMask & FieldMask.INT_ARG1) != 0) {
+ dest.writeInt(mIntArg1);
+ }
+ if ((fieldMask & FieldMask.FLAGS) != 0) {
+ dest.writeInt(mFlags);
+ }
+ if ((fieldMask & FieldMask.CHAR_SEQUENCE) != 0) {
+ TextUtils.writeToParcel(mCharSequence, dest, flags);
+ }
+ if ((fieldMask & FieldMask.STRING) != 0) {
+ dest.writeString(mString);
+ }
+ if ((fieldMask & FieldMask.BUNDLE) != 0) {
+ dest.writeBundle(mBundle);
+ }
+ if ((fieldMask & FieldMask.PARCELABLE) != 0) {
+ dest.writeInt(mParcelableType);
+ dest.writeTypedObject(mParcelable, flags);
+ }
+ if ((fieldMask & FieldMask.CALLBACK) != 0) {
+ dest.writeInt(mResultCallbackType);
+ dest.writeStrongBinder(mResultCallback);
+ }
+ }
+
+ @FieldMask
+ @AnyThread
+ private int getFieldMask() {
+ return (mIntArg0 != 0 ? FieldMask.INT_ARG0 : 0)
+ | (mIntArg1 != 0 ? FieldMask.INT_ARG1 : 0)
+ | (mFlags != 0 ? FieldMask.FLAGS : 0)
+ | (mCharSequence != null ? FieldMask.CHAR_SEQUENCE : 0)
+ | (mString != null ? FieldMask.STRING : 0)
+ | (mBundle != null ? FieldMask.BUNDLE : 0)
+ | (mParcelableType != ParcelableType.NULL ? FieldMask.PARCELABLE : 0)
+ | (mResultCallbackType != ResultCallbackType.NULL ? FieldMask.CALLBACK : 0);
+ }
+
+ @AnyThread
+ @Nullable
+ private static InputConnectionCommand createFromParcel(@NonNull Parcel source) {
+ final int type = source.readInt();
+ if (type < InputConnectionCommandType.FIRST_COMMAND
+ || InputConnectionCommandType.LAST_COMMAND < type) {
+ Log.e(TAG, "Invalid InputConnectionCommand type=" + type);
+ return null;
+ }
+
+ @FieldMask final int fieldMask = source.readInt();
+ final int intArg0 = (fieldMask & FieldMask.INT_ARG0) != 0 ? source.readInt() : 0;
+ final int intArg1 = (fieldMask & FieldMask.INT_ARG1) != 0 ? source.readInt() : 0;
+ final int flags = (fieldMask & FieldMask.FLAGS) != 0 ? source.readInt() : 0;
+ final CharSequence charSequence = (fieldMask & FieldMask.CHAR_SEQUENCE) != 0
+ ? TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source) : null;
+ final String string = (fieldMask & FieldMask.STRING) != 0 ? source.readString() : null;
+ final Bundle bundle = (fieldMask & FieldMask.BUNDLE) != 0 ? source.readBundle() : null;
+
+ @ParcelableType final int parcelableType;
+ final Parcelable parcelable;
+ if ((fieldMask & FieldMask.PARCELABLE) != 0) {
+ parcelableType = source.readInt();
+ switch (parcelableType) {
+ case ParcelableType.NULL:
+ Log.e(TAG, "Unexpected ParcelableType=NULL");
+ return null;
+ case ParcelableType.EXTRACTED_TEXT_REQUEST:
+ parcelable = source.readTypedObject(ExtractedTextRequest.CREATOR);
+ break;
+ case ParcelableType.COMPLETION_INFO:
+ parcelable = source.readTypedObject(CompletionInfo.CREATOR);
+ break;
+ case ParcelableType.CORRECTION_INFO:
+ parcelable = source.readTypedObject(CorrectionInfo.CREATOR);
+ break;
+ case ParcelableType.KEY_EVENT:
+ parcelable = source.readTypedObject(KeyEvent.CREATOR);
+ break;
+ case ParcelableType.INPUT_CONTENT_INFO:
+ parcelable = source.readTypedObject(InputContentInfo.CREATOR);
+ break;
+ default:
+ Log.e(TAG, "Unknown ParcelableType=" + parcelableType);
+ return null;
+ }
+ } else {
+ parcelableType = ParcelableType.NULL;
+ parcelable = null;
+ }
+ @ResultCallbackType final int resultCallbackType;
+ final IBinder resultCallback;
+ if ((fieldMask & FieldMask.CALLBACK) != 0) {
+ resultCallbackType = source.readInt();
+ switch (resultCallbackType) {
+ case ResultCallbackType.NULL:
+ Log.e(TAG, "Unexpected ResultCallbackType=NULL");
+ return null;
+ case ResultCallbackType.BOOLEAN:
+ case ResultCallbackType.INT:
+ case ResultCallbackType.CHAR_SEQUENCE:
+ case ResultCallbackType.EXTRACTED_TEXT:
+ case ResultCallbackType.SURROUNDING_TEXT:
+ resultCallback = source.readStrongBinder();
+ break;
+ default:
+ Log.e(TAG, "Unknown ResultCallbackType=" + resultCallbackType);
+ return null;
+ }
+ } else {
+ resultCallbackType = ResultCallbackType.NULL;
+ resultCallback = null;
+ }
+ return new InputConnectionCommand(type, intArg0, intArg1, flags, charSequence, string,
+ bundle, parcelableType, parcelable, resultCallbackType, resultCallback);
+ }
+
+ /**
+ * Used to make this class parcelable.
+ */
+ public static final Parcelable.Creator<InputConnectionCommand> CREATOR =
+ new Parcelable.Creator<InputConnectionCommand>() {
+ @AnyThread
+ @Nullable
+ @Override
+ public InputConnectionCommand createFromParcel(Parcel source) {
+ try {
+ return InputConnectionCommand.createFromParcel(source);
+ } catch (Exception e) {
+ Log.e(TAG, "Returning null due to exception.", e);
+ return null;
+ }
+ }
+
+ @AnyThread
+ @NonNull
+ @Override
+ public InputConnectionCommand[] newArray(int size) {
+ return new InputConnectionCommand[size];
+ }
+ };
+}
diff --git a/core/java/com/android/internal/inputmethod/InputConnectionCommandType.java b/core/java/com/android/internal/inputmethod/InputConnectionCommandType.java
new file mode 100644
index 0000000..1eb0101
--- /dev/null
+++ b/core/java/com/android/internal/inputmethod/InputConnectionCommandType.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.inputmethod;
+
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+
+@Retention(SOURCE)
+@IntDef(value = {
+ InputConnectionCommandType.BEGIN_BATCH_EDIT,
+ InputConnectionCommandType.CLEAR_META_KEY_STATES,
+ InputConnectionCommandType.COMMIT_COMPLETION,
+ InputConnectionCommandType.COMMIT_CONTENT,
+ InputConnectionCommandType.COMMIT_CORRECTION,
+ InputConnectionCommandType.COMMIT_TEXT,
+ InputConnectionCommandType.DELETE_SURROUNDING_TEXT,
+ InputConnectionCommandType.DELETE_SURROUNDING_TEXT_IN_CODE_POINTS,
+ InputConnectionCommandType.END_BATCH_EDIT,
+ InputConnectionCommandType.FINISH_COMPOSING_TEXT,
+ InputConnectionCommandType.GET_CURSOR_CAPS_MODE,
+ InputConnectionCommandType.GET_EXTRACTED_TEXT,
+ InputConnectionCommandType.GET_SELECTED_TEXT,
+ InputConnectionCommandType.GET_SURROUNDING_TEXT,
+ InputConnectionCommandType.GET_TEXT_AFTER_CURSOR,
+ InputConnectionCommandType.GET_TEXT_BEFORE_CURSOR,
+ InputConnectionCommandType.PERFORM_CONTEXT_MENU_ACTION,
+ InputConnectionCommandType.PERFORM_EDITOR_ACTION,
+ InputConnectionCommandType.PERFORM_SPELL_CHECK,
+ InputConnectionCommandType.REQUEST_CURSOR_UPDATES,
+ InputConnectionCommandType.SEND_KEY_EVENT,
+ InputConnectionCommandType.SET_COMPOSING_REGION,
+ InputConnectionCommandType.SET_COMPOSING_TEXT,
+ InputConnectionCommandType.SET_IME_CONSUMES_INPUT,
+ InputConnectionCommandType.SET_SELECTION,
+})
+public @interface InputConnectionCommandType {
+ int FIRST_COMMAND = 1;
+
+ int BEGIN_BATCH_EDIT = FIRST_COMMAND;
+ int CLEAR_META_KEY_STATES = 2;
+ int COMMIT_COMPLETION = 3;
+ int COMMIT_CONTENT = 4;
+ int COMMIT_CORRECTION = 5;
+ int COMMIT_TEXT = 6;
+ int DELETE_SURROUNDING_TEXT = 7;
+ int DELETE_SURROUNDING_TEXT_IN_CODE_POINTS = 8;
+ int END_BATCH_EDIT = 9;
+ int FINISH_COMPOSING_TEXT = 10;
+ int GET_CURSOR_CAPS_MODE = 11;
+ int GET_EXTRACTED_TEXT = 12;
+ int GET_SELECTED_TEXT = 13;
+ int GET_SURROUNDING_TEXT = 14;
+ int GET_TEXT_AFTER_CURSOR = 15;
+ int GET_TEXT_BEFORE_CURSOR = 16;
+ int PERFORM_CONTEXT_MENU_ACTION = 17;
+ int PERFORM_EDITOR_ACTION = 18;
+ int PERFORM_SPELL_CHECK = 19;
+ int PERFORM_PRIVATE_COMMAND = 20;
+ int REQUEST_CURSOR_UPDATES = 21;
+ int SEND_KEY_EVENT = 22;
+ int SET_COMPOSING_REGION = 23;
+ int SET_COMPOSING_TEXT = 24;
+ int SET_IME_CONSUMES_INPUT = 25;
+ int SET_SELECTION = 26;
+
+ int LAST_COMMAND = SET_SELECTION;
+}
diff --git a/core/java/com/android/internal/inputmethod/InputMethodDebug.java b/core/java/com/android/internal/inputmethod/InputMethodDebug.java
index a00b993..0475ed0 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodDebug.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodDebug.java
@@ -18,6 +18,7 @@
import android.annotation.AnyThread;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
@@ -242,6 +243,133 @@
}
/**
+ * Converts {@link InputConnectionCommandType} to human readable {@link String}.
+ */
+ public static String inputConnectionCommandTypeToString(@InputConnectionCommandType int type) {
+ switch (type) {
+ case InputConnectionCommandType.BEGIN_BATCH_EDIT:
+ return "beginBatchEdit";
+ case InputConnectionCommandType.CLEAR_META_KEY_STATES:
+ return "clearMetaKeyStates";
+ case InputConnectionCommandType.COMMIT_COMPLETION:
+ return "commitCompletion";
+ case InputConnectionCommandType.COMMIT_CONTENT:
+ return "commitContent";
+ case InputConnectionCommandType.COMMIT_CORRECTION:
+ return "commitCorrection";
+ case InputConnectionCommandType.COMMIT_TEXT:
+ return "commitText";
+ case InputConnectionCommandType.DELETE_SURROUNDING_TEXT:
+ return "deleteSurroundingText";
+ case InputConnectionCommandType.DELETE_SURROUNDING_TEXT_IN_CODE_POINTS:
+ return "deleteSurroundingTextInCodePoints";
+ case InputConnectionCommandType.END_BATCH_EDIT:
+ return "endBatchEdit";
+ case InputConnectionCommandType.FINISH_COMPOSING_TEXT:
+ return "finishComposingText";
+ case InputConnectionCommandType.GET_CURSOR_CAPS_MODE:
+ return "getCursorCapsMode";
+ case InputConnectionCommandType.GET_EXTRACTED_TEXT:
+ return "getExtractedText";
+ case InputConnectionCommandType.GET_SELECTED_TEXT:
+ return "getSelectedText";
+ case InputConnectionCommandType.GET_SURROUNDING_TEXT:
+ return "getSurroundingText";
+ case InputConnectionCommandType.GET_TEXT_AFTER_CURSOR:
+ return "getTextAfterCursor";
+ case InputConnectionCommandType.GET_TEXT_BEFORE_CURSOR:
+ return "getTextBeforeCursor";
+ case InputConnectionCommandType.PERFORM_CONTEXT_MENU_ACTION:
+ return "performContextMenuAction";
+ case InputConnectionCommandType.PERFORM_EDITOR_ACTION:
+ return "performEditorAction";
+ case InputConnectionCommandType.PERFORM_SPELL_CHECK:
+ return "performSpellCheck";
+ case InputConnectionCommandType.REQUEST_CURSOR_UPDATES:
+ return "requestCursorUpdates";
+ case InputConnectionCommandType.SEND_KEY_EVENT:
+ return "sendKeyEvent";
+ case InputConnectionCommandType.SET_COMPOSING_REGION:
+ return "setComposingRegion";
+ case InputConnectionCommandType.SET_COMPOSING_TEXT:
+ return "setComposingText";
+ case InputConnectionCommandType.SET_IME_CONSUMES_INPUT:
+ return "setImeConsumesInput";
+ case InputConnectionCommandType.SET_SELECTION:
+ return "setSelection";
+ default:
+ return "Unknown=" + type;
+ }
+ }
+
+ /**
+ * Converts {@link InputConnectionCommand} to human readable {@link String}.
+ */
+ @NonNull
+ public static String dumpInputConnectionCommand(@Nullable InputConnectionCommand command) {
+ if (command == null) {
+ return "null";
+ }
+ switch (command.mCommandType) {
+ case InputConnectionCommandType.BEGIN_BATCH_EDIT:
+ return "beginBatchEdit()";
+ case InputConnectionCommandType.CLEAR_META_KEY_STATES:
+ return "clearMetaKeyStates(" + command.mIntArg0 + ")";
+ case InputConnectionCommandType.COMMIT_COMPLETION:
+ return "commitCompletion(" + command.mParcelable + ")";
+ case InputConnectionCommandType.COMMIT_CONTENT:
+ return "commitContent(" + command.mParcelable + ", " + command.mFlags + ", "
+ + command.mBundle + ")";
+ case InputConnectionCommandType.COMMIT_CORRECTION:
+ return "commitCorrection(" + command.mParcelable + ")";
+ case InputConnectionCommandType.COMMIT_TEXT:
+ return "commitText(" + command.mCharSequence + ", " + command.mIntArg0 + ")";
+ case InputConnectionCommandType.DELETE_SURROUNDING_TEXT:
+ return "deleteSurroundingText(" + command.mIntArg0 + ", " + command.mIntArg1 + ")";
+ case InputConnectionCommandType.DELETE_SURROUNDING_TEXT_IN_CODE_POINTS:
+ return "deleteSurroundingTextInCodePoints(" + command.mIntArg0 + ", "
+ + command.mIntArg1 + ")";
+ case InputConnectionCommandType.END_BATCH_EDIT:
+ return "endBatchEdit()";
+ case InputConnectionCommandType.FINISH_COMPOSING_TEXT:
+ return "finishComposingText()";
+ case InputConnectionCommandType.GET_CURSOR_CAPS_MODE:
+ return "getCursorCapsMode(" + command.mIntArg0 + ")";
+ case InputConnectionCommandType.GET_EXTRACTED_TEXT:
+ return "getExtractedText(" + command.mParcelable + ", " + command.mFlags + ")";
+ case InputConnectionCommandType.GET_SELECTED_TEXT:
+ return "getSelectedText(" + command.mFlags + ")";
+ case InputConnectionCommandType.GET_SURROUNDING_TEXT:
+ return "getSurroundingText(" + command.mIntArg0 + ", " + command.mIntArg1 + ", "
+ + command.mFlags + ")";
+ case InputConnectionCommandType.GET_TEXT_AFTER_CURSOR:
+ return "getTextAfterCursor(" + command.mIntArg0 + ", " + command.mFlags + ")";
+ case InputConnectionCommandType.GET_TEXT_BEFORE_CURSOR:
+ return "getTextBeforeCursor(" + command.mIntArg0 + ", " + command.mFlags + ")";
+ case InputConnectionCommandType.PERFORM_CONTEXT_MENU_ACTION:
+ return "performContextMenuAction(" + command.mIntArg0 + ")";
+ case InputConnectionCommandType.PERFORM_EDITOR_ACTION:
+ return "performEditorAction(" + command.mIntArg0 + ")";
+ case InputConnectionCommandType.PERFORM_SPELL_CHECK:
+ return "performSpellCheck()";
+ case InputConnectionCommandType.REQUEST_CURSOR_UPDATES:
+ return "requestCursorUpdates(" + command.mIntArg0 + ")";
+ case InputConnectionCommandType.SEND_KEY_EVENT:
+ return "sendKeyEvent(" + command.mParcelable + ")";
+ case InputConnectionCommandType.SET_COMPOSING_REGION:
+ return "setComposingRegion(" + command.mIntArg0 + ", " + command.mIntArg1 + ")";
+ case InputConnectionCommandType.SET_COMPOSING_TEXT:
+ return "setComposingText(" + command.mCharSequence + ", " + command.mIntArg0 + ")";
+ case InputConnectionCommandType.SET_IME_CONSUMES_INPUT:
+ return "setImeConsumesInput(" + (command.mIntArg0 != 0) + ")";
+ case InputConnectionCommandType.SET_SELECTION:
+ return "setSelection(" + command.mIntArg0 + ", " + command.mIntArg1 + ")";
+ default:
+ return "unknown(type=" + command.mCommandType + ")";
+ }
+ }
+
+ /**
* Return a fixed size string of the object.
* TODO(b/151575861): Take & return with StringBuilder to make more memory efficient.
*/
diff --git a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
index ed1fe1a..9fb0bb5 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
@@ -142,7 +142,7 @@
/**
* Calls {@link IInputMethodPrivilegedOperations#createInputContentUriToken(Uri, String,
- * IIInputContentUriTokenResultCallback)}.
+ * IInputContentUriTokenResultCallback)}.
*
* @param contentUri Content URI to which a temporary read permission should be granted
* @param packageName Indicates what package needs to have a temporary read permission
diff --git a/core/java/com/android/internal/inputmethod/ResultCallbacks.java b/core/java/com/android/internal/inputmethod/ResultCallbacks.java
index 398cffb..343a6e6 100644
--- a/core/java/com/android/internal/inputmethod/ResultCallbacks.java
+++ b/core/java/com/android/internal/inputmethod/ResultCallbacks.java
@@ -21,7 +21,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import java.lang.ref.WeakReference;
import java.util.concurrent.atomic.AtomicReference;
/**
@@ -38,15 +37,9 @@
@AnyThread
@Nullable
- private static <T> T unwrap(@NonNull AtomicReference<WeakReference<T>> atomicRef) {
- final WeakReference<T> ref = atomicRef.getAndSet(null);
- if (ref == null) {
- // Double-call is guaranteed to be ignored here.
- return null;
- }
- final T value = ref.get();
- ref.clear();
- return value;
+ private static <T> T unwrap(@NonNull AtomicReference<T> atomicRef) {
+ // Only the first caller will receive the non-null original object.
+ return atomicRef.getAndSet(null);
}
/**
@@ -58,8 +51,7 @@
*/
@AnyThread
public static IIntResultCallback.Stub of(@NonNull Completable.Int value) {
- final AtomicReference<WeakReference<Completable.Int>>
- atomicRef = new AtomicReference<>(new WeakReference<>(value));
+ final AtomicReference<Completable.Int> atomicRef = new AtomicReference<>(value);
return new IIntResultCallback.Stub() {
@BinderThread
@@ -95,8 +87,7 @@
@AnyThread
public static ICharSequenceResultCallback.Stub of(
@NonNull Completable.CharSequence value) {
- final AtomicReference<WeakReference<Completable.CharSequence>> atomicRef =
- new AtomicReference<>(new WeakReference<>(value));
+ final AtomicReference<Completable.CharSequence> atomicRef = new AtomicReference<>(value);
return new ICharSequenceResultCallback.Stub() {
@BinderThread
@@ -122,8 +113,7 @@
@AnyThread
public static IExtractedTextResultCallback.Stub of(
@NonNull Completable.ExtractedText value) {
- final AtomicReference<WeakReference<Completable.ExtractedText>>
- atomicRef = new AtomicReference<>(new WeakReference<>(value));
+ final AtomicReference<Completable.ExtractedText> atomicRef = new AtomicReference<>(value);
return new IExtractedTextResultCallback.Stub() {
@BinderThread
@@ -149,8 +139,7 @@
@AnyThread
public static ISurroundingTextResultCallback.Stub of(
@NonNull Completable.SurroundingText value) {
- final AtomicReference<WeakReference<Completable.SurroundingText>>
- atomicRef = new AtomicReference<>(new WeakReference<>(value));
+ final AtomicReference<Completable.SurroundingText> atomicRef = new AtomicReference<>(value);
return new ISurroundingTextResultCallback.Stub() {
@BinderThread
@@ -174,8 +163,7 @@
*/
@AnyThread
public static IBooleanResultCallback.Stub of(@NonNull Completable.Boolean value) {
- final AtomicReference<WeakReference<Completable.Boolean>>
- atomicRef = new AtomicReference<>(new WeakReference<>(value));
+ final AtomicReference<Completable.Boolean> atomicRef = new AtomicReference<>(value);
return new IBooleanResultCallback.Stub() {
@BinderThread
@@ -209,8 +197,7 @@
*/
@AnyThread
public static IVoidResultCallback.Stub of(@NonNull Completable.Void value) {
- final AtomicReference<WeakReference<Completable.Void>> atomicRef =
- new AtomicReference<>(new WeakReference<>(value));
+ final AtomicReference<Completable.Void> atomicRef = new AtomicReference<>(value);
return new IVoidResultCallback.Stub() {
@BinderThread
@@ -236,20 +223,20 @@
}
/**
- * Creates {@link IIInputContentUriTokenResultCallback.Stub} that is to set
+ * Creates {@link IInputContentUriTokenResultCallback.Stub} that is to set
* {@link Completable.IInputContentUriToken} when receiving the result.
*
* @param value {@link Completable.IInputContentUriToken} to be set when receiving the result.
- * @return {@link IIInputContentUriTokenResultCallback.Stub} that can be passed as a binder IPC
+ * @return {@link IInputContentUriTokenResultCallback.Stub} that can be passed as a binder IPC
* parameter.
*/
@AnyThread
- public static IIInputContentUriTokenResultCallback.Stub of(
+ public static IInputContentUriTokenResultCallback.Stub of(
@NonNull Completable.IInputContentUriToken value) {
- final AtomicReference<WeakReference<Completable.IInputContentUriToken>>
- atomicRef = new AtomicReference<>(new WeakReference<>(value));
+ final AtomicReference<Completable.IInputContentUriToken>
+ atomicRef = new AtomicReference<>(value);
- return new IIInputContentUriTokenResultCallback.Stub() {
+ return new IInputContentUriTokenResultCallback.Stub() {
@BinderThread
@Override
public void onResult(IInputContentUriToken result) {
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 84ef5a1..4043060 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -196,7 +196,7 @@
public static final int RESET_REASON_FULL_CHARGE = 3;
public static final int RESET_REASON_MEASURED_ENERGY_BUCKETS_CHANGE = 4;
- protected Clocks mClocks;
+ protected Clock mClock;
private final AtomicFile mStatsFile;
public final AtomicFile mCheckinFile;
@@ -215,19 +215,15 @@
private final KernelWakelockStats mTmpWakelockStats = new KernelWakelockStats();
@VisibleForTesting
- protected KernelCpuUidUserSysTimeReader mCpuUidUserSysTimeReader =
- new KernelCpuUidUserSysTimeReader(true);
+ protected KernelCpuUidUserSysTimeReader mCpuUidUserSysTimeReader;
@VisibleForTesting
protected KernelCpuSpeedReader[] mKernelCpuSpeedReaders;
@VisibleForTesting
- protected KernelCpuUidFreqTimeReader mCpuUidFreqTimeReader =
- new KernelCpuUidFreqTimeReader(true);
+ protected KernelCpuUidFreqTimeReader mCpuUidFreqTimeReader;
@VisibleForTesting
- protected KernelCpuUidActiveTimeReader mCpuUidActiveTimeReader =
- new KernelCpuUidActiveTimeReader(true);
+ protected KernelCpuUidActiveTimeReader mCpuUidActiveTimeReader;
@VisibleForTesting
- protected KernelCpuUidClusterTimeReader mCpuUidClusterTimeReader =
- new KernelCpuUidClusterTimeReader(true);
+ protected KernelCpuUidClusterTimeReader mCpuUidClusterTimeReader;
@VisibleForTesting
protected KernelSingleUidTimeReader mKernelSingleUidTimeReader;
@VisibleForTesting
@@ -300,9 +296,9 @@
@VisibleForTesting
public final class UidToRemove {
- int startUid;
- int endUid;
- long mTimeAddedInQueueMs;
+ private final int mStartUid;
+ private final int mEndUid;
+ private final long mUidRemovalTimestamp;
/** Remove just one UID */
public UidToRemove(int uid, long timestamp) {
@@ -311,38 +307,18 @@
/** Remove a range of UIDs, startUid must be smaller than endUid. */
public UidToRemove(int startUid, int endUid, long timestamp) {
- this.startUid = startUid;
- this.endUid = endUid;
- mTimeAddedInQueueMs = timestamp;
+ mStartUid = startUid;
+ mEndUid = endUid;
+ mUidRemovalTimestamp = timestamp;
}
- void remove() {
- if (startUid == endUid) {
- mCpuUidUserSysTimeReader.removeUid(startUid);
- mCpuUidFreqTimeReader.removeUid(startUid);
- if (mConstants.TRACK_CPU_ACTIVE_CLUSTER_TIME) {
- mCpuUidActiveTimeReader.removeUid(startUid);
- mCpuUidClusterTimeReader.removeUid(startUid);
- }
- if (mKernelSingleUidTimeReader != null) {
- mKernelSingleUidTimeReader.removeUid(startUid);
- }
- mNumUidsRemoved++;
- } else if (startUid < endUid) {
- mCpuUidFreqTimeReader.removeUidsInRange(startUid, endUid);
- mCpuUidUserSysTimeReader.removeUidsInRange(startUid, endUid);
- if (mConstants.TRACK_CPU_ACTIVE_CLUSTER_TIME) {
- mCpuUidActiveTimeReader.removeUidsInRange(startUid, endUid);
- mCpuUidClusterTimeReader.removeUidsInRange(startUid, endUid);
- }
- if (mKernelSingleUidTimeReader != null) {
- mKernelSingleUidTimeReader.removeUidsInRange(startUid, endUid);
- }
- // Treat as one. We don't know how many uids there are in between.
- mNumUidsRemoved++;
- } else {
- Slog.w(TAG, "End UID " + endUid + " is smaller than start UID " + startUid);
- }
+ public long getUidRemovalTimestamp() {
+ return mUidRemovalTimestamp;
+ }
+
+ @GuardedBy("BatteryStatsImpl.this")
+ void removeLocked() {
+ removeCpuStatsForUidRangeLocked(mStartUid, mEndUid);
}
}
@@ -407,8 +383,8 @@
}
boolean changed = setChargingLocked(true);
if (changed) {
- final long uptimeMs = mClocks.uptimeMillis();
- final long elapsedRealtimeMs = mClocks.elapsedRealtime();
+ final long uptimeMs = mClock.uptimeMillis();
+ final long elapsedRealtimeMs = mClock.elapsedRealtime();
addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
}
}
@@ -526,11 +502,16 @@
}
}
- public void clearPendingRemovedUids() {
- long cutOffTimeMs = mClocks.elapsedRealtime() - mConstants.UID_REMOVE_DELAY_MS;
+ /**
+ * Removes kernel CPU stats for removed UIDs, in the order they were added to the
+ * mPendingRemovedUids queue.
+ */
+ @GuardedBy("this")
+ public void clearPendingRemovedUidsLocked() {
+ long cutOffTimeMs = mClock.elapsedRealtime() - mConstants.UID_REMOVE_DELAY_MS;
while (!mPendingRemovedUids.isEmpty()
- && mPendingRemovedUids.peek().mTimeAddedInQueueMs < cutOffTimeMs) {
- mPendingRemovedUids.poll().remove();
+ && mPendingRemovedUids.peek().getUidRemovalTimestamp() < cutOffTimeMs) {
+ mPendingRemovedUids.poll().removeLocked();
}
}
@@ -628,35 +609,6 @@
return true;
}
- public interface Clocks {
- /** Elapsed Realtime, see SystemClock.elapsedRealtime() */
- long elapsedRealtime();
-
- /** Uptime, see SystemClock.uptimeMillis() */
- long uptimeMillis();
-
- /** Wall-clock time as per System.currentTimeMillis() */
- long currentTimeMillis();
- }
-
- public static class SystemClocks implements Clocks {
-
- @Override
- public long elapsedRealtime() {
- return SystemClock.elapsedRealtime();
- }
-
- @Override
- public long uptimeMillis() {
- return SystemClock.uptimeMillis();
- }
-
- @Override
- public long currentTimeMillis() {
- return System.currentTimeMillis();
- }
- }
-
public interface ExternalStatsSync {
int UPDATE_CPU = 0x01;
int UPDATE_WIFI = 0x02;
@@ -694,6 +646,8 @@
Future<?> scheduleCpuSyncDueToWakelockChange(long delayMillis);
void cancelCpuSyncDueToWakelockChange();
Future<?> scheduleSyncDueToBatteryLevelChange(long delayMillis);
+ /** Schedule removal of UIDs corresponding to a removed user */
+ Future<?> scheduleCleanupDueToRemovedUser(int userId);
}
public Handler mHandler;
@@ -1193,12 +1147,12 @@
}
public BatteryStatsImpl() {
- this(new SystemClocks());
+ this(Clock.SYSTEM_CLOCK);
}
- public BatteryStatsImpl(Clocks clocks) {
- init(clocks);
- mStartClockTimeMs = clocks.currentTimeMillis();
+ public BatteryStatsImpl(Clock clock) {
+ init(clock);
+ mStartClockTimeMs = clock.currentTimeMillis();
mStatsFile = null;
mCheckinFile = null;
mDailyFile = null;
@@ -1211,8 +1165,12 @@
clearHistoryLocked();
}
- private void init(Clocks clocks) {
- mClocks = clocks;
+ private void init(Clock clock) {
+ mClock = clock;
+ mCpuUidUserSysTimeReader = new KernelCpuUidUserSysTimeReader(true, clock);
+ mCpuUidFreqTimeReader = new KernelCpuUidFreqTimeReader(true, clock);
+ mCpuUidActiveTimeReader = new KernelCpuUidActiveTimeReader(true, clock);
+ mCpuUidClusterTimeReader = new KernelCpuUidClusterTimeReader(true, clock);
}
/**
@@ -1768,7 +1726,7 @@
* State for keeping track of timing information.
*/
public static abstract class Timer extends BatteryStats.Timer implements TimeBaseObs {
- protected final Clocks mClocks;
+ protected final Clock mClock;
protected final int mType;
protected final TimeBase mTimeBase;
@@ -1796,8 +1754,8 @@
* @param timeBase
* @param in
*/
- public Timer(Clocks clocks, int type, TimeBase timeBase, Parcel in) {
- mClocks = clocks;
+ public Timer(Clock clock, int type, TimeBase timeBase, Parcel in) {
+ mClock = clock;
mType = type;
mTimeBase = timeBase;
@@ -1808,8 +1766,8 @@
if (DEBUG) Log.i(TAG, "**** READ TIMER #" + mType + ": mTotalTime=" + mTotalTimeUs);
}
- public Timer(Clocks clocks, int type, TimeBase timeBase) {
- mClocks = clocks;
+ public Timer(Clock clock, int type, TimeBase timeBase) {
+ mClock = clock;
mType = type;
mTimeBase = timeBase;
timeBase.add(this);
@@ -1838,7 +1796,7 @@
*/
@Override
public boolean reset(boolean detachIfReset) {
- return reset(detachIfReset, mClocks.elapsedRealtime() * 1000);
+ return reset(detachIfReset, mClock.elapsedRealtime() * 1000);
}
@Override
@@ -1984,8 +1942,8 @@
int mUpdateVersion;
@VisibleForTesting
- public SamplingTimer(Clocks clocks, TimeBase timeBase, Parcel in) {
- super(clocks, 0, timeBase, in);
+ public SamplingTimer(Clock clock, TimeBase timeBase, Parcel in) {
+ super(clock, 0, timeBase, in);
mCurrentReportedCount = in.readInt();
mUnpluggedReportedCount = in.readInt();
mCurrentReportedTotalTimeUs = in.readLong();
@@ -1995,8 +1953,8 @@
}
@VisibleForTesting
- public SamplingTimer(Clocks clocks, TimeBase timeBase) {
- super(clocks, 0, timeBase);
+ public SamplingTimer(Clock clock, TimeBase timeBase) {
+ super(clock, 0, timeBase);
mTrackingReportedValues = false;
mTimeBaseRunning = timeBase.isRunning();
}
@@ -2006,7 +1964,7 @@
* be less than the values used for a previous invocation.
*/
public void endSample() {
- endSample(mClocks.elapsedRealtime() * 1000);
+ endSample(mClock.elapsedRealtime() * 1000);
}
/**
@@ -2041,7 +1999,7 @@
* @param count total number of times the event being sampled occurred.
*/
public void updated(long totalTimeUs, int count) {
- update(totalTimeUs, count, mClocks.elapsedRealtime() * 1000);
+ update(totalTimeUs, count, mClock.elapsedRealtime() * 1000);
}
/**
@@ -2071,7 +2029,7 @@
* @param deltaCount additional number of times the event being sampled occurred.
*/
public void add(long deltaTimeUs, int deltaCount) {
- add(deltaTimeUs, deltaCount, mClocks.elapsedRealtime() * 1000);
+ add(deltaTimeUs, deltaCount, mClock.elapsedRealtime() * 1000);
}
/**
@@ -2161,16 +2119,16 @@
*/
boolean mInDischarge;
- BatchTimer(Clocks clocks, Uid uid, int type, TimeBase timeBase, Parcel in) {
- super(clocks, type, timeBase, in);
+ BatchTimer(Clock clock, Uid uid, int type, TimeBase timeBase, Parcel in) {
+ super(clock, type, timeBase, in);
mUid = uid;
mLastAddedTimeUs = in.readLong();
mLastAddedDurationUs = in.readLong();
mInDischarge = timeBase.isRunning();
}
- BatchTimer(Clocks clocks, Uid uid, int type, TimeBase timeBase) {
- super(clocks, type, timeBase);
+ BatchTimer(Clock clock, Uid uid, int type, TimeBase timeBase) {
+ super(clock, type, timeBase);
mUid = uid;
mInDischarge = timeBase.isRunning();
}
@@ -2233,7 +2191,7 @@
}
public void addDuration(BatteryStatsImpl stats, long durationMs) {
- addDuration(stats, durationMs, mClocks.elapsedRealtime());
+ addDuration(stats, durationMs, mClock.elapsedRealtime());
}
public void addDuration(BatteryStatsImpl stats, long durationMs, long elapsedRealtimeMs) {
@@ -2248,7 +2206,7 @@
}
public void abortLastDuration(BatteryStatsImpl stats) {
- abortLastDuration(stats, mClocks.elapsedRealtime());
+ abortLastDuration(stats, mClock.elapsedRealtime());
}
public void abortLastDuration(BatteryStatsImpl stats, long elapsedRealtimeMs) {
@@ -2316,17 +2274,17 @@
*/
long mTotalDurationMs;
- public DurationTimer(Clocks clocks, Uid uid, int type, ArrayList<StopwatchTimer> timerPool,
+ public DurationTimer(Clock clock, Uid uid, int type, ArrayList<StopwatchTimer> timerPool,
TimeBase timeBase, Parcel in) {
- super(clocks, uid, type, timerPool, timeBase, in);
+ super(clock, uid, type, timerPool, timeBase, in);
mMaxDurationMs = in.readLong();
mTotalDurationMs = in.readLong();
mCurrentDurationMs = in.readLong();
}
- public DurationTimer(Clocks clocks, Uid uid, int type, ArrayList<StopwatchTimer> timerPool,
+ public DurationTimer(Clock clock, Uid uid, int type, ArrayList<StopwatchTimer> timerPool,
TimeBase timeBase) {
- super(clocks, uid, type, timerPool, timeBase);
+ super(clock, uid, type, timerPool, timeBase);
}
@Override
@@ -2527,17 +2485,17 @@
@VisibleForTesting
public boolean mInList;
- public StopwatchTimer(Clocks clocks, Uid uid, int type, ArrayList<StopwatchTimer> timerPool,
+ public StopwatchTimer(Clock clock, Uid uid, int type, ArrayList<StopwatchTimer> timerPool,
TimeBase timeBase, Parcel in) {
- super(clocks, type, timeBase, in);
+ super(clock, type, timeBase, in);
mUid = uid;
mTimerPool = timerPool;
mUpdateTimeUs = in.readLong();
}
- public StopwatchTimer(Clocks clocks, Uid uid, int type, ArrayList<StopwatchTimer> timerPool,
+ public StopwatchTimer(Clock clock, Uid uid, int type, ArrayList<StopwatchTimer> timerPool,
TimeBase timeBase) {
- super(clocks, type, timeBase);
+ super(clock, type, timeBase);
mUid = uid;
mTimerPool = timerPool;
}
@@ -2745,10 +2703,10 @@
* The mSubTimer is based on the given subTimeBase. The mSubTimer is not pooled, even if
* the main timer is.
*/
- public DualTimer(Clocks clocks, Uid uid, int type, ArrayList<StopwatchTimer> timerPool,
+ public DualTimer(Clock clock, Uid uid, int type, ArrayList<StopwatchTimer> timerPool,
TimeBase timeBase, TimeBase subTimeBase, Parcel in) {
- super(clocks, uid, type, timerPool, timeBase, in);
- mSubTimer = new DurationTimer(clocks, uid, type, null, subTimeBase, in);
+ super(clock, uid, type, timerPool, timeBase, in);
+ mSubTimer = new DurationTimer(clock, uid, type, null, subTimeBase, in);
}
/**
@@ -2757,10 +2715,10 @@
* The mSubTimer is based on the given subTimeBase. The mSubTimer is not pooled, even if
* the main timer is.
*/
- public DualTimer(Clocks clocks, Uid uid, int type, ArrayList<StopwatchTimer> timerPool,
+ public DualTimer(Clock clock, Uid uid, int type, ArrayList<StopwatchTimer> timerPool,
TimeBase timeBase, TimeBase subTimeBase) {
- super(clocks, uid, type, timerPool, timeBase);
- mSubTimer = new DurationTimer(clocks, uid, type, null, subTimeBase);
+ super(clock, uid, type, timerPool, timeBase);
+ mSubTimer = new DurationTimer(clock, uid, type, null, subTimeBase);
}
/** Get the secondary timer. */
@@ -3181,7 +3139,7 @@
public SamplingTimer getRpmTimerLocked(String name) {
SamplingTimer rpmt = mRpmStats.get(name);
if (rpmt == null) {
- rpmt = new SamplingTimer(mClocks, mOnBatteryTimeBase);
+ rpmt = new SamplingTimer(mClock, mOnBatteryTimeBase);
mRpmStats.put(name, rpmt);
}
return rpmt;
@@ -3191,7 +3149,7 @@
public SamplingTimer getScreenOffRpmTimerLocked(String name) {
SamplingTimer rpmt = mScreenOffRpmStats.get(name);
if (rpmt == null) {
- rpmt = new SamplingTimer(mClocks, mOnBatteryScreenOffTimeBase);
+ rpmt = new SamplingTimer(mClock, mOnBatteryScreenOffTimeBase);
mScreenOffRpmStats.put(name, rpmt);
}
return rpmt;
@@ -3204,7 +3162,7 @@
public SamplingTimer getWakeupReasonTimerLocked(String name) {
SamplingTimer timer = mWakeupReasonStats.get(name);
if (timer == null) {
- timer = new SamplingTimer(mClocks, mOnBatteryTimeBase);
+ timer = new SamplingTimer(mClock, mOnBatteryTimeBase);
mWakeupReasonStats.put(name, timer);
}
return timer;
@@ -3217,7 +3175,7 @@
public SamplingTimer getKernelWakelockTimerLocked(String name) {
SamplingTimer kwlt = mKernelWakelockStats.get(name);
if (kwlt == null) {
- kwlt = new SamplingTimer(mClocks, mOnBatteryScreenOffTimeBase);
+ kwlt = new SamplingTimer(mClock, mOnBatteryScreenOffTimeBase);
mKernelWakelockStats.put(name, kwlt);
}
return kwlt;
@@ -3226,7 +3184,7 @@
public SamplingTimer getKernelMemoryTimerLocked(long bucket) {
SamplingTimer kmt = mKernelMemoryStats.get(bucket);
if (kmt == null) {
- kmt = new SamplingTimer(mClocks, mOnBatteryTimeBase);
+ kmt = new SamplingTimer(mClock, mOnBatteryTimeBase);
mKernelMemoryStats.put(bucket, kmt);
}
return kmt;
@@ -3631,8 +3589,8 @@
}
public void createFakeHistoryEvents(long numEvents) {
- final long elapsedRealtimeMs = mClocks.elapsedRealtime();
- final long uptimeMs = mClocks.uptimeMillis();
+ final long elapsedRealtimeMs = mClock.elapsedRealtime();
+ final long uptimeMs = mClock.uptimeMillis();
for(long i = 0; i < numEvents; i++) {
noteLongPartialWakelockStart("name1", "historyName1", 1000,
elapsedRealtimeMs, uptimeMs);
@@ -3729,7 +3687,7 @@
if (dataSize == 0) {
// The history is currently empty; we need it to start with a time stamp.
- cur.currentTime = mClocks.currentTimeMillis();
+ cur.currentTime = mClock.currentTimeMillis();
addHistoryBufferLocked(elapsedRealtimeMs, HistoryItem.CMD_RESET, cur);
}
addHistoryBufferLocked(elapsedRealtimeMs, HistoryItem.CMD_UPDATE, cur);
@@ -3891,7 +3849,7 @@
public void addIsolatedUidLocked(int isolatedUid, int appUid) {
addIsolatedUidLocked(isolatedUid, appUid,
- mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void addIsolatedUidLocked(int isolatedUid, int appUid,
@@ -3936,7 +3894,7 @@
}
public void noteEventLocked(int code, String name, int uid) {
- noteEventLocked(code, name, uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteEventLocked(code, name, uid, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteEventLocked(int code, String name, int uid,
@@ -3949,9 +3907,9 @@
}
public void noteCurrentTimeChangedLocked() {
- final long currentTime = mClocks.currentTimeMillis();
- final long elapsedRealtime = mClocks.elapsedRealtime();
- final long uptime = mClocks.uptimeMillis();
+ final long currentTime = mClock.currentTimeMillis();
+ final long elapsedRealtime = mClock.elapsedRealtime();
+ final long uptime = mClock.uptimeMillis();
noteCurrentTimeChangedLocked(currentTime, elapsedRealtime, uptime);
}
@@ -3961,7 +3919,7 @@
}
public void noteProcessStartLocked(String name, int uid) {
- noteProcessStartLocked(name, uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteProcessStartLocked(name, uid, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteProcessStartLocked(String name, int uid,
@@ -3981,7 +3939,7 @@
}
public void noteProcessCrashLocked(String name, int uid) {
- noteProcessCrashLocked(name, uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteProcessCrashLocked(name, uid, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteProcessCrashLocked(String name, int uid,
@@ -3994,7 +3952,7 @@
}
public void noteProcessAnrLocked(String name, int uid) {
- noteProcessAnrLocked(name, uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteProcessAnrLocked(name, uid, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteProcessAnrLocked(String name, int uid, long elapsedRealtimeMs, long uptimeMs) {
@@ -4006,7 +3964,7 @@
}
public void noteUidProcessStateLocked(int uid, int state) {
- noteUidProcessStateLocked(uid, state, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteUidProcessStateLocked(uid, state, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteUidProcessStateLocked(int uid, int state,
@@ -4027,7 +3985,7 @@
}
public void noteProcessFinishLocked(String name, int uid) {
- noteProcessFinishLocked(name, uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteProcessFinishLocked(name, uid, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteProcessFinishLocked(String name, int uid,
@@ -4044,7 +4002,7 @@
}
public void noteSyncStartLocked(String name, int uid) {
- noteSyncStartLocked(name, uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteSyncStartLocked(name, uid, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteSyncStartLocked(String name, int uid, long elapsedRealtimeMs, long uptimeMs) {
@@ -4058,7 +4016,7 @@
}
public void noteSyncFinishLocked(String name, int uid) {
- noteSyncFinishLocked(name, uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteSyncFinishLocked(name, uid, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteSyncFinishLocked(String name, int uid, long elapsedRealtimeMs, long uptimeMs) {
@@ -4073,7 +4031,7 @@
}
public void noteJobStartLocked(String name, int uid) {
- noteJobStartLocked(name, uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteJobStartLocked(name, uid, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteJobStartLocked(String name, int uid, long elapsedRealtimeMs, long uptimeMs) {
@@ -4088,7 +4046,7 @@
public void noteJobFinishLocked(String name, int uid, int stopReason) {
noteJobFinishLocked(name, uid, stopReason,
- mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteJobFinishLocked(String name, int uid, int stopReason,
@@ -4104,7 +4062,7 @@
public void noteJobsDeferredLocked(int uid, int numDeferred, long sinceLast) {
noteJobsDeferredLocked(uid, numDeferred, sinceLast,
- mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteJobsDeferredLocked(int uid, int numDeferred, long sinceLast,
@@ -4116,7 +4074,7 @@
public void noteAlarmStartLocked(String name, WorkSource workSource, int uid) {
noteAlarmStartLocked(name, workSource, uid,
- mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteAlarmStartLocked(String name, WorkSource workSource, int uid,
@@ -4127,7 +4085,7 @@
public void noteAlarmFinishLocked(String name, WorkSource workSource, int uid) {
noteAlarmFinishLocked(name, workSource, uid,
- mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteAlarmFinishLocked(String name, WorkSource workSource, int uid,
@@ -4139,7 +4097,7 @@
private void noteAlarmStartOrFinishLocked(int historyItem, String name, WorkSource workSource,
int uid) {
noteAlarmStartOrFinishLocked(historyItem, name, workSource, uid,
- mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ mClock.elapsedRealtime(), mClock.uptimeMillis());
}
private void noteAlarmStartOrFinishLocked(int historyItem, String name, WorkSource workSource,
@@ -4177,7 +4135,7 @@
public void noteWakupAlarmLocked(String packageName, int uid, WorkSource workSource,
String tag) {
noteWakupAlarmLocked(packageName, uid, workSource, tag,
- mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteWakupAlarmLocked(String packageName, int uid, WorkSource workSource,
@@ -4236,8 +4194,8 @@
HashMap<String, SparseIntArray> active = mActiveEvents.getStateForEvent(
HistoryItem.EVENT_PROC);
if (active != null) {
- long mSecRealtime = mClocks.elapsedRealtime();
- final long mSecUptime = mClocks.uptimeMillis();
+ long mSecRealtime = mClock.elapsedRealtime();
+ final long mSecUptime = mClock.uptimeMillis();
for (HashMap.Entry<String, SparseIntArray> ent : active.entrySet()) {
SparseIntArray uids = ent.getValue();
for (int j=0; j<uids.size(); j++) {
@@ -4251,8 +4209,8 @@
HashMap<String, SparseIntArray> active = mActiveEvents.getStateForEvent(
HistoryItem.EVENT_PROC);
if (active != null) {
- long mSecRealtime = mClocks.elapsedRealtime();
- final long mSecUptime = mClocks.uptimeMillis();
+ long mSecRealtime = mClock.elapsedRealtime();
+ final long mSecUptime = mClock.uptimeMillis();
for (HashMap.Entry<String, SparseIntArray> ent : active.entrySet()) {
SparseIntArray uids = ent.getValue();
for (int j=0; j<uids.size(); j++) {
@@ -4272,7 +4230,7 @@
if (mPretendScreenOff != pretendScreenOff) {
mPretendScreenOff = pretendScreenOff;
noteScreenStateLocked(pretendScreenOff ? Display.STATE_OFF : Display.STATE_ON,
- mClocks.elapsedRealtime(), mClocks.uptimeMillis(), mClocks.currentTimeMillis());
+ mClock.elapsedRealtime(), mClock.uptimeMillis(), mClock.currentTimeMillis());
}
}
@@ -4282,7 +4240,7 @@
public void noteStartWakeLocked(int uid, int pid, WorkChain wc, String name, String historyName,
int type, boolean unimportantForLogging) {
noteStartWakeLocked(uid, pid, wc, name, historyName, type, unimportantForLogging,
- mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteStartWakeLocked(int uid, int pid, WorkChain wc, String name, String historyName,
@@ -4353,7 +4311,7 @@
public void noteStopWakeLocked(int uid, int pid, WorkChain wc, String name, String historyName,
int type) {
noteStopWakeLocked(uid, pid, wc, name, historyName, type,
- mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteStopWakeLocked(int uid, int pid, WorkChain wc, String name, String historyName,
@@ -4436,7 +4394,7 @@
public void noteStartWakeFromSourceLocked(WorkSource ws, int pid, String name,
String historyName, int type, boolean unimportantForLogging) {
noteStartWakeFromSourceLocked(ws, pid, name, historyName, type, unimportantForLogging,
- mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteStartWakeFromSourceLocked(WorkSource ws, int pid, String name,
@@ -4463,7 +4421,7 @@
String newHistoryName, int newType, boolean newUnimportantForLogging) {
noteChangeWakelockFromSourceLocked(ws, pid, name, historyName, type, newWs, newPid,
newName, newHistoryName, newType, newUnimportantForLogging,
- mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteChangeWakelockFromSourceLocked(WorkSource ws, int pid, String name,
@@ -4515,7 +4473,7 @@
public void noteStopWakeFromSourceLocked(WorkSource ws, int pid, String name,
String historyName, int type) {
noteStopWakeFromSourceLocked(ws, pid, name, historyName, type,
- mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteStopWakeFromSourceLocked(WorkSource ws, int pid, String name,
@@ -4538,7 +4496,7 @@
public void noteLongPartialWakelockStart(String name, String historyName, int uid) {
noteLongPartialWakelockStart(name, historyName, uid,
- mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteLongPartialWakelockStart(String name, String historyName, int uid,
@@ -4550,7 +4508,7 @@
public void noteLongPartialWakelockStartFromSource(String name, String historyName,
WorkSource workSource) {
noteLongPartialWakelockStartFromSource(name, historyName, workSource,
- mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteLongPartialWakelockStartFromSource(String name, String historyName,
@@ -4588,7 +4546,7 @@
public void noteLongPartialWakelockFinish(String name, String historyName, int uid) {
noteLongPartialWakelockFinish(name, historyName, uid,
- mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteLongPartialWakelockFinish(String name, String historyName, int uid,
@@ -4600,7 +4558,7 @@
public void noteLongPartialWakelockFinishFromSource(String name, String historyName,
WorkSource workSource) {
noteLongPartialWakelockFinishFromSource(name, historyName, workSource,
- mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteLongPartialWakelockFinishFromSource(String name, String historyName,
@@ -4648,7 +4606,7 @@
}
public void noteWakeupReasonLocked(String reason) {
- noteWakeupReasonLocked(reason, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteWakeupReasonLocked(reason, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteWakeupReasonLocked(String reason, long elapsedRealtimeMs, long uptimeMs) {
@@ -4718,7 +4676,7 @@
int mSensorNesting;
public void noteStartSensorLocked(int uid, int sensor) {
- noteStartSensorLocked(uid, sensor, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteStartSensorLocked(uid, sensor, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteStartSensorLocked(int uid, int sensor, long elapsedRealtimeMs, long uptimeMs) {
@@ -4735,7 +4693,7 @@
}
public void noteStopSensorLocked(int uid, int sensor) {
- noteStopSensorLocked(uid, sensor, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteStopSensorLocked(uid, sensor, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteStopSensorLocked(int uid, int sensor, long elapsedRealtimeMs, long uptimeMs) {
@@ -4754,7 +4712,7 @@
int mGpsNesting;
public void noteGpsChangedLocked(WorkSource oldWs, WorkSource newWs) {
- noteGpsChangedLocked(oldWs, newWs, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteGpsChangedLocked(oldWs, newWs, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteGpsChangedLocked(WorkSource oldWs, WorkSource newWs,
@@ -4833,7 +4791,7 @@
}
public void noteGpsSignalQualityLocked(int signalLevel) {
- noteGpsSignalQualityLocked(signalLevel, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteGpsSignalQualityLocked(signalLevel, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteGpsSignalQualityLocked(int signalLevel, long elapsedRealtimeMs, long uptimeMs) {
@@ -4861,8 +4819,8 @@
@GuardedBy("this")
public void noteScreenStateLocked(int state) {
- noteScreenStateLocked(state, mClocks.elapsedRealtime(), mClocks.uptimeMillis(),
- mClocks.currentTimeMillis());
+ noteScreenStateLocked(state, mClock.elapsedRealtime(), mClock.uptimeMillis(),
+ mClock.currentTimeMillis());
}
@GuardedBy("this")
@@ -4962,7 +4920,7 @@
@UnsupportedAppUsage
public void noteScreenBrightnessLocked(int brightness) {
- noteScreenBrightnessLocked(brightness, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteScreenBrightnessLocked(brightness, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteScreenBrightnessLocked(int brightness, long elapsedRealtimeMs, long uptimeMs) {
@@ -4990,7 +4948,7 @@
@UnsupportedAppUsage
public void noteUserActivityLocked(int uid, int event) {
- noteUserActivityLocked(uid, event, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteUserActivityLocked(uid, event, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteUserActivityLocked(int uid, int event, long elapsedRealtimeMs, long uptimeMs) {
@@ -5001,7 +4959,7 @@
}
public void noteWakeUpLocked(String reason, int reasonUid) {
- noteWakeUpLocked(reason, reasonUid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteWakeUpLocked(reason, reasonUid, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteWakeUpLocked(String reason, int reasonUid,
@@ -5011,7 +4969,7 @@
}
public void noteInteractiveLocked(boolean interactive) {
- noteInteractiveLocked(interactive, mClocks.elapsedRealtime());
+ noteInteractiveLocked(interactive, mClock.elapsedRealtime());
}
public void noteInteractiveLocked(boolean interactive, long elapsedRealtimeMs) {
@@ -5028,7 +4986,7 @@
public void noteConnectivityChangedLocked(int type, String extra) {
noteConnectivityChangedLocked(type, extra,
- mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteConnectivityChangedLocked(int type, String extra,
@@ -5051,7 +5009,7 @@
*/
public boolean noteMobileRadioPowerStateLocked(int powerState, long timestampNs, int uid) {
return noteMobileRadioPowerStateLocked(powerState, timestampNs, uid,
- mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public boolean noteMobileRadioPowerStateLocked(int powerState, long timestampNs, int uid,
@@ -5099,7 +5057,7 @@
}
public void notePowerSaveModeLocked(boolean enabled) {
- notePowerSaveModeLocked(enabled, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ notePowerSaveModeLocked(enabled, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
/**
@@ -5146,7 +5104,7 @@
public void noteDeviceIdleModeLocked(final int mode, String activeReason, int activeUid) {
noteDeviceIdleModeLocked(mode, activeReason, activeUid,
- mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteDeviceIdleModeLocked(final int mode, String activeReason, int activeUid,
@@ -5224,7 +5182,7 @@
public void notePackageInstalledLocked(String pkgName, long versionCode) {
notePackageInstalledLocked(pkgName, versionCode,
- mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void notePackageInstalledLocked(String pkgName, long versionCode,
@@ -5240,7 +5198,7 @@
}
public void notePackageUninstalledLocked(String pkgName) {
- notePackageUninstalledLocked(pkgName, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ notePackageUninstalledLocked(pkgName, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void notePackageUninstalledLocked(String pkgName,
@@ -5261,7 +5219,7 @@
}
void stopAllGpsSignalQualityTimersLocked(int except) {
- stopAllGpsSignalQualityTimersLocked(except, mClocks.elapsedRealtime());
+ stopAllGpsSignalQualityTimersLocked(except, mClock.elapsedRealtime());
}
void stopAllGpsSignalQualityTimersLocked(int except, long elapsedRealtimeMs) {
@@ -5277,7 +5235,7 @@
@UnsupportedAppUsage
public void notePhoneOnLocked() {
- notePhoneOnLocked(mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ notePhoneOnLocked(mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void notePhoneOnLocked(long elapsedRealtimeMs, long uptimeMs) {
@@ -5293,7 +5251,7 @@
@UnsupportedAppUsage
public void notePhoneOffLocked() {
- notePhoneOffLocked(mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ notePhoneOffLocked(mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void notePhoneOffLocked(long elapsedRealtimeMs, long uptimeMs) {
@@ -5315,8 +5273,8 @@
public void onReceive(Context context, Intent intent) {
final boolean state = intent.getBooleanExtra(UsbManager.USB_CONNECTED, false);
synchronized (BatteryStatsImpl.this) {
- noteUsbConnectionStateLocked(state, mClocks.elapsedRealtime(),
- mClocks.uptimeMillis());
+ noteUsbConnectionStateLocked(state, mClock.elapsedRealtime(),
+ mClock.uptimeMillis());
}
}
}, usbStateFilter);
@@ -5325,8 +5283,8 @@
final Intent usbState = context.registerReceiver(null, usbStateFilter);
final boolean initState = usbState != null && usbState.getBooleanExtra(
UsbManager.USB_CONNECTED, false);
- noteUsbConnectionStateLocked(initState, mClocks.elapsedRealtime(),
- mClocks.uptimeMillis());
+ noteUsbConnectionStateLocked(initState, mClock.elapsedRealtime(),
+ mClock.uptimeMillis());
}
}
}
@@ -5466,7 +5424,7 @@
* @param state phone state from ServiceState.getState()
*/
public void notePhoneStateLocked(int state, int simState) {
- notePhoneStateLocked(state, simState, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ notePhoneStateLocked(state, simState, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void notePhoneStateLocked(int state, int simState,
@@ -5478,7 +5436,7 @@
@UnsupportedAppUsage
public void notePhoneSignalStrengthLocked(SignalStrength signalStrength) {
notePhoneSignalStrengthLocked(signalStrength,
- mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void notePhoneSignalStrengthLocked(SignalStrength signalStrength,
@@ -5492,7 +5450,7 @@
@UnsupportedAppUsage
public void notePhoneDataConnectionStateLocked(int dataType, boolean hasData, int serviceType) {
notePhoneDataConnectionStateLocked(dataType, hasData, serviceType,
- mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void notePhoneDataConnectionStateLocked(int dataType, boolean hasData, int serviceType,
@@ -5535,7 +5493,7 @@
}
public void noteWifiOnLocked() {
- noteWifiOnLocked(mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteWifiOnLocked(mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteWifiOnLocked(long elapsedRealtimeMs, long uptimeMs) {
@@ -5551,7 +5509,7 @@
}
public void noteWifiOffLocked() {
- noteWifiOffLocked(mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteWifiOffLocked(mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteWifiOffLocked(long elapsedRealtimeMs, long uptimeMs) {
@@ -5568,7 +5526,7 @@
@UnsupportedAppUsage
public void noteAudioOnLocked(int uid) {
- noteAudioOnLocked(uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteAudioOnLocked(uid, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteAudioOnLocked(int uid, long elapsedRealtimeMs, long uptimeMs) {
@@ -5587,7 +5545,7 @@
@UnsupportedAppUsage
public void noteAudioOffLocked(int uid) {
- noteAudioOffLocked(uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteAudioOffLocked(uid, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteAudioOffLocked(int uid, long elapsedRealtimeMs, long uptimeMs) {
@@ -5608,7 +5566,7 @@
@UnsupportedAppUsage
public void noteVideoOnLocked(int uid) {
- noteVideoOnLocked(uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteVideoOnLocked(uid, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteVideoOnLocked(int uid, long elapsedRealtimeMs, long uptimeMs) {
@@ -5627,7 +5585,7 @@
@UnsupportedAppUsage
public void noteVideoOffLocked(int uid) {
- noteVideoOffLocked(uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteVideoOffLocked(uid, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteVideoOffLocked(int uid, long elapsedRealtimeMs, long uptimeMs) {
@@ -5647,7 +5605,7 @@
}
public void noteResetAudioLocked() {
- noteResetAudioLocked(mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteResetAudioLocked(mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteResetAudioLocked(long elapsedRealtimeMs, long uptimeMs) {
@@ -5666,7 +5624,7 @@
}
public void noteResetVideoLocked() {
- noteResetVideoLocked(mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteResetVideoLocked(mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteResetVideoLocked(long elapsedRealtimeMs, long uptimeMs) {
@@ -5685,7 +5643,7 @@
}
public void noteActivityResumedLocked(int uid) {
- noteActivityResumedLocked(uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteActivityResumedLocked(uid, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteActivityResumedLocked(int uid, long elapsedRealtimeMs, long uptimeMs) {
@@ -5695,7 +5653,7 @@
}
public void noteActivityPausedLocked(int uid) {
- noteActivityPausedLocked(uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteActivityPausedLocked(uid, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteActivityPausedLocked(int uid, long elapsedRealtimeMs, long uptimeMs) {
@@ -5706,7 +5664,7 @@
public void noteVibratorOnLocked(int uid, long durationMillis) {
noteVibratorOnLocked(uid, durationMillis,
- mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteVibratorOnLocked(int uid, long durationMillis,
@@ -5717,7 +5675,7 @@
}
public void noteVibratorOffLocked(int uid) {
- noteVibratorOffLocked(uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteVibratorOffLocked(uid, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteVibratorOffLocked(int uid, long elapsedRealtimeMs, long uptimeMs) {
@@ -5727,7 +5685,7 @@
}
public void noteFlashlightOnLocked(int uid) {
- noteFlashlightOnLocked(uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteFlashlightOnLocked(uid, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteFlashlightOnLocked(int uid, long elapsedRealtimeMs, long uptimeMs) {
@@ -5744,7 +5702,7 @@
}
public void noteFlashlightOffLocked(int uid) {
- noteFlashlightOffLocked(uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteFlashlightOffLocked(uid, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteFlashlightOffLocked(int uid, long elapsedRealtimeMs, long uptimeMs) {
@@ -5764,7 +5722,7 @@
}
public void noteCameraOnLocked(int uid) {
- noteCameraOnLocked(uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteCameraOnLocked(uid, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteCameraOnLocked(int uid, long elapsedRealtimeMs, long uptimeMs) {
@@ -5781,7 +5739,7 @@
}
public void noteCameraOffLocked(int uid) {
- noteCameraOffLocked(uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteCameraOffLocked(uid, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteCameraOffLocked(int uid, long elapsedRealtimeMs, long uptimeMs) {
@@ -5801,7 +5759,7 @@
}
public void noteResetCameraLocked() {
- noteResetCameraLocked(mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteResetCameraLocked(mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteResetCameraLocked(long elapsedRealtimeMs, long uptimeMs) {
@@ -5820,7 +5778,7 @@
}
public void noteResetFlashlightLocked() {
- noteResetFlashlightLocked(mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteResetFlashlightLocked(mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteResetFlashlightLocked(long elapsedRealtimeMs, long uptimeMs) {
@@ -5855,7 +5813,7 @@
public void noteBluetoothScanStartedFromSourceLocked(WorkSource ws, boolean isUnoptimized) {
noteBluetoothScanStartedFromSourceLocked(ws, isUnoptimized,
- mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteBluetoothScanStartedFromSourceLocked(WorkSource ws, boolean isUnoptimized,
@@ -5900,7 +5858,7 @@
public void noteBluetoothScanStoppedFromSourceLocked(WorkSource ws, boolean isUnoptimized) {
noteBluetoothScanStoppedFromSourceLocked(ws, isUnoptimized,
- mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteBluetoothScanStoppedFromSourceLocked(WorkSource ws, boolean isUnoptimized,
@@ -5921,7 +5879,7 @@
}
public void noteResetBluetoothScanLocked() {
- noteResetBluetoothScanLocked(mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteResetBluetoothScanLocked(mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteResetBluetoothScanLocked(long elapsedRealtimeMs, long uptimeMs) {
@@ -5941,7 +5899,7 @@
public void noteBluetoothScanResultsFromSourceLocked(WorkSource ws, int numNewResults) {
noteBluetoothScanResultsFromSourceLocked(ws, numNewResults,
- mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteBluetoothScanResultsFromSourceLocked(WorkSource ws, int numNewResults,
@@ -5974,7 +5932,7 @@
public void noteWifiRadioPowerState(int powerState, long timestampNs, int uid) {
noteWifiRadioPowerState(powerState, timestampNs, uid,
- mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteWifiRadioPowerState(int powerState, long timestampNs, int uid,
@@ -6001,7 +5959,7 @@
}
public void noteWifiRunningLocked(WorkSource ws) {
- noteWifiRunningLocked(ws, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteWifiRunningLocked(ws, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteWifiRunningLocked(WorkSource ws, long elapsedRealtimeMs, long uptimeMs) {
@@ -6036,7 +5994,7 @@
public void noteWifiRunningChangedLocked(WorkSource oldWs, WorkSource newWs) {
noteWifiRunningChangedLocked(oldWs, newWs,
- mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteWifiRunningChangedLocked(WorkSource oldWs, WorkSource newWs,
@@ -6079,7 +6037,7 @@
}
public void noteWifiStoppedLocked(WorkSource ws) {
- noteWifiStoppedLocked(ws, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteWifiStoppedLocked(ws, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteWifiStoppedLocked(WorkSource ws, long elapsedRealtimeMs, long uptimeMs) {
@@ -6113,7 +6071,7 @@
}
public void noteWifiStateLocked(int wifiState, String accessPoint) {
- noteWifiStateLocked(wifiState, accessPoint, mClocks.elapsedRealtime());
+ noteWifiStateLocked(wifiState, accessPoint, mClock.elapsedRealtime());
}
public void noteWifiStateLocked(int wifiState, String accessPoint, long elapsedRealtimeMs) {
@@ -6130,7 +6088,7 @@
public void noteWifiSupplicantStateChangedLocked(int supplState, boolean failedAuth) {
noteWifiSupplicantStateChangedLocked(supplState, failedAuth,
- mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteWifiSupplicantStateChangedLocked(int supplState, boolean failedAuth,
@@ -6163,7 +6121,7 @@
}
public void noteWifiRssiChangedLocked(int newRssi) {
- noteWifiRssiChangedLocked(newRssi, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteWifiRssiChangedLocked(newRssi, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteWifiRssiChangedLocked(int newRssi, long elapsedRealtimeMs, long uptimeMs) {
@@ -6195,7 +6153,7 @@
@UnsupportedAppUsage
public void noteFullWifiLockAcquiredLocked(int uid) {
- noteFullWifiLockAcquiredLocked(uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteFullWifiLockAcquiredLocked(uid, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteFullWifiLockAcquiredLocked(int uid, long elapsedRealtimeMs, long uptimeMs) {
@@ -6212,7 +6170,7 @@
@UnsupportedAppUsage
public void noteFullWifiLockReleasedLocked(int uid) {
- noteFullWifiLockReleasedLocked(uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteFullWifiLockReleasedLocked(uid, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteFullWifiLockReleasedLocked(int uid, long elapsedRealtimeMs, long uptimeMs) {
@@ -6230,7 +6188,7 @@
int mWifiScanNesting = 0;
public void noteWifiScanStartedLocked(int uid) {
- noteWifiScanStartedLocked(uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteWifiScanStartedLocked(uid, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteWifiScanStartedLocked(int uid, long elapsedRealtimeMs, long uptimeMs) {
@@ -6246,7 +6204,7 @@
}
public void noteWifiScanStoppedLocked(int uid) {
- noteWifiScanStoppedLocked(uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteWifiScanStoppedLocked(uid, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteWifiScanStoppedLocked(int uid, long elapsedRealtimeMs, long uptimeMs) {
@@ -6263,7 +6221,7 @@
public void noteWifiBatchedScanStartedLocked(int uid, int csph) {
noteWifiBatchedScanStartedLocked(uid, csph,
- mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteWifiBatchedScanStartedLocked(int uid, int csph,
@@ -6274,7 +6232,7 @@
}
public void noteWifiBatchedScanStoppedLocked(int uid) {
- noteWifiBatchedScanStoppedLocked(uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteWifiBatchedScanStoppedLocked(uid, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteWifiBatchedScanStoppedLocked(int uid, long elapsedRealtimeMs, long uptimeMs) {
@@ -6287,7 +6245,7 @@
@UnsupportedAppUsage
public void noteWifiMulticastEnabledLocked(int uid) {
- noteWifiMulticastEnabledLocked(uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteWifiMulticastEnabledLocked(uid, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteWifiMulticastEnabledLocked(int uid, long elapsedRealtimeMs, long uptimeMs) {
@@ -6311,7 +6269,7 @@
@UnsupportedAppUsage
public void noteWifiMulticastDisabledLocked(int uid) {
- noteWifiMulticastDisabledLocked(uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteWifiMulticastDisabledLocked(uid, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteWifiMulticastDisabledLocked(int uid, long elapsedRealtimeMs, long uptimeMs) {
@@ -6335,7 +6293,7 @@
public void noteFullWifiLockAcquiredFromSourceLocked(WorkSource ws) {
noteFullWifiLockAcquiredFromSourceLocked(ws,
- mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteFullWifiLockAcquiredFromSourceLocked(WorkSource ws,
@@ -6358,7 +6316,7 @@
public void noteFullWifiLockReleasedFromSourceLocked(WorkSource ws) {
noteFullWifiLockReleasedFromSourceLocked(ws,
- mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteFullWifiLockReleasedFromSourceLocked(WorkSource ws,
@@ -6380,7 +6338,7 @@
}
public void noteWifiScanStartedFromSourceLocked(WorkSource ws) {
- noteWifiScanStartedFromSourceLocked(ws, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteWifiScanStartedFromSourceLocked(ws, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteWifiScanStartedFromSourceLocked(WorkSource ws,
@@ -6402,7 +6360,7 @@
}
public void noteWifiScanStoppedFromSourceLocked(WorkSource ws) {
- noteWifiScanStoppedFromSourceLocked(ws, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ noteWifiScanStoppedFromSourceLocked(ws, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteWifiScanStoppedFromSourceLocked(WorkSource ws,
@@ -6425,7 +6383,7 @@
public void noteWifiBatchedScanStartedFromSourceLocked(WorkSource ws, int csph) {
noteWifiBatchedScanStartedFromSourceLocked(ws, csph,
- mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteWifiBatchedScanStartedFromSourceLocked(WorkSource ws, int csph,
@@ -6446,7 +6404,7 @@
public void noteWifiBatchedScanStoppedFromSourceLocked(WorkSource ws) {
noteWifiBatchedScanStoppedFromSourceLocked(ws,
- mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteWifiBatchedScanStoppedFromSourceLocked(WorkSource ws,
long elapsedRealtimeMs, long uptimeMs) {
@@ -6522,7 +6480,7 @@
public void noteBinderCallStats(int workSourceUid, long incrementalCallCount,
Collection<BinderCallsStats.CallStat> callStats) {
noteBinderCallStats(workSourceUid, incrementalCallCount, callStats,
- mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public void noteBinderCallStats(int workSourceUid, long incrementalCallCount,
@@ -7024,16 +6982,16 @@
}
@Override public long getStartClockTime() {
- final long currentTimeMs = mClocks.currentTimeMillis();
+ final long currentTimeMs = mClock.currentTimeMillis();
if ((currentTimeMs > MILLISECONDS_IN_YEAR
&& mStartClockTimeMs < (currentTimeMs - MILLISECONDS_IN_YEAR))
|| (mStartClockTimeMs > currentTimeMs)) {
// If the start clock time has changed by more than a year, then presumably
// the previous time was completely bogus. So we are going to figure out a
// new time based on how much time has elapsed since we started counting.
- recordCurrentTimeChangeLocked(currentTimeMs, mClocks.elapsedRealtime(),
- mClocks.uptimeMillis());
- return currentTimeMs - (mClocks.elapsedRealtime() - (mRealtimeStartUs / 1000));
+ recordCurrentTimeChangeLocked(currentTimeMs, mClock.elapsedRealtime(),
+ mClock.uptimeMillis());
+ return currentTimeMs - (mClock.elapsedRealtime() - (mRealtimeStartUs / 1000));
}
return mStartClockTimeMs;
}
@@ -7396,7 +7354,7 @@
private double mProportionalSystemServiceUsage;
public Uid(BatteryStatsImpl bsi, int uid) {
- this(bsi, uid, bsi.mClocks.elapsedRealtime(), bsi.mClocks.uptimeMillis());
+ this(bsi, uid, bsi.mClock.elapsedRealtime(), bsi.mClock.uptimeMillis());
}
public Uid(BatteryStatsImpl bsi, int uid, long elapsedRealtimeMs, long uptimeMs) {
@@ -7422,25 +7380,25 @@
};
mSyncStats = mBsi.new OverflowArrayMap<DualTimer>(uid) {
@Override public DualTimer instantiateObject() {
- return new DualTimer(mBsi.mClocks, Uid.this, SYNC, null,
+ return new DualTimer(mBsi.mClock, Uid.this, SYNC, null,
mBsi.mOnBatteryTimeBase, mOnBatteryBackgroundTimeBase);
}
};
mJobStats = mBsi.new OverflowArrayMap<DualTimer>(uid) {
@Override public DualTimer instantiateObject() {
- return new DualTimer(mBsi.mClocks, Uid.this, JOB, null,
+ return new DualTimer(mBsi.mClock, Uid.this, JOB, null,
mBsi.mOnBatteryTimeBase, mOnBatteryBackgroundTimeBase);
}
};
- mWifiRunningTimer = new StopwatchTimer(mBsi.mClocks, this, WIFI_RUNNING,
+ mWifiRunningTimer = new StopwatchTimer(mBsi.mClock, this, WIFI_RUNNING,
mBsi.mWifiRunningTimers, mBsi.mOnBatteryTimeBase);
- mFullWifiLockTimer = new StopwatchTimer(mBsi.mClocks, this, FULL_WIFI_LOCK,
+ mFullWifiLockTimer = new StopwatchTimer(mBsi.mClock, this, FULL_WIFI_LOCK,
mBsi.mFullWifiLockTimers, mBsi.mOnBatteryTimeBase);
- mWifiScanTimer = new DualTimer(mBsi.mClocks, this, WIFI_SCAN,
+ mWifiScanTimer = new DualTimer(mBsi.mClock, this, WIFI_SCAN,
mBsi.mWifiScanTimers, mBsi.mOnBatteryTimeBase, mOnBatteryBackgroundTimeBase);
mWifiBatchedScanTimer = new StopwatchTimer[NUM_WIFI_BATCHED_SCAN_BINS];
- mWifiMulticastTimer = new StopwatchTimer(mBsi.mClocks, this, WIFI_MULTICAST_ENABLED,
+ mWifiMulticastTimer = new StopwatchTimer(mBsi.mClock, this, WIFI_MULTICAST_ENABLED,
mBsi.mWifiMulticastTimers, mBsi.mOnBatteryTimeBase);
mProcessStateTimer = new StopwatchTimer[NUM_PROCESS_STATE];
mJobsDeferredEventCount = new Counter(mBsi.mOnBatteryTimeBase);
@@ -7638,7 +7596,7 @@
if (!mWifiRunning) {
mWifiRunning = true;
if (mWifiRunningTimer == null) {
- mWifiRunningTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, WIFI_RUNNING,
+ mWifiRunningTimer = new StopwatchTimer(mBsi.mClock, Uid.this, WIFI_RUNNING,
mBsi.mWifiRunningTimers, mBsi.mOnBatteryTimeBase);
}
mWifiRunningTimer.startRunningLocked(elapsedRealtimeMs);
@@ -7658,7 +7616,7 @@
if (!mFullWifiLockOut) {
mFullWifiLockOut = true;
if (mFullWifiLockTimer == null) {
- mFullWifiLockTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, FULL_WIFI_LOCK,
+ mFullWifiLockTimer = new StopwatchTimer(mBsi.mClock, Uid.this, FULL_WIFI_LOCK,
mBsi.mFullWifiLockTimers, mBsi.mOnBatteryTimeBase);
}
mFullWifiLockTimer.startRunningLocked(elapsedRealtimeMs);
@@ -7678,7 +7636,7 @@
if (!mWifiScanStarted) {
mWifiScanStarted = true;
if (mWifiScanTimer == null) {
- mWifiScanTimer = new DualTimer(mBsi.mClocks, Uid.this, WIFI_SCAN,
+ mWifiScanTimer = new DualTimer(mBsi.mClock, Uid.this, WIFI_SCAN,
mBsi.mWifiScanTimers, mBsi.mOnBatteryTimeBase,
mOnBatteryBackgroundTimeBase);
}
@@ -7728,7 +7686,7 @@
public void noteWifiMulticastEnabledLocked(long elapsedRealtimeMs) {
if (mWifiMulticastWakelockCount == 0) {
if (mWifiMulticastTimer == null) {
- mWifiMulticastTimer = new StopwatchTimer(mBsi.mClocks, Uid.this,
+ mWifiMulticastTimer = new StopwatchTimer(mBsi.mClock, Uid.this,
WIFI_MULTICAST_ENABLED, mBsi.mWifiMulticastTimers, mBsi.mOnBatteryTimeBase);
}
mWifiMulticastTimer.startRunningLocked(elapsedRealtimeMs);
@@ -7917,7 +7875,7 @@
public StopwatchTimer createAudioTurnedOnTimerLocked() {
if (mAudioTurnedOnTimer == null) {
- mAudioTurnedOnTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, AUDIO_TURNED_ON,
+ mAudioTurnedOnTimer = new StopwatchTimer(mBsi.mClock, Uid.this, AUDIO_TURNED_ON,
mBsi.mAudioTurnedOnTimers, mBsi.mOnBatteryTimeBase);
}
return mAudioTurnedOnTimer;
@@ -7941,7 +7899,7 @@
public StopwatchTimer createVideoTurnedOnTimerLocked() {
if (mVideoTurnedOnTimer == null) {
- mVideoTurnedOnTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, VIDEO_TURNED_ON,
+ mVideoTurnedOnTimer = new StopwatchTimer(mBsi.mClock, Uid.this, VIDEO_TURNED_ON,
mBsi.mVideoTurnedOnTimers, mBsi.mOnBatteryTimeBase);
}
return mVideoTurnedOnTimer;
@@ -7965,7 +7923,7 @@
public StopwatchTimer createFlashlightTurnedOnTimerLocked() {
if (mFlashlightTurnedOnTimer == null) {
- mFlashlightTurnedOnTimer = new StopwatchTimer(mBsi.mClocks, Uid.this,
+ mFlashlightTurnedOnTimer = new StopwatchTimer(mBsi.mClock, Uid.this,
FLASHLIGHT_TURNED_ON, mBsi.mFlashlightTurnedOnTimers, mBsi.mOnBatteryTimeBase);
}
return mFlashlightTurnedOnTimer;
@@ -7989,7 +7947,7 @@
public StopwatchTimer createCameraTurnedOnTimerLocked() {
if (mCameraTurnedOnTimer == null) {
- mCameraTurnedOnTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, CAMERA_TURNED_ON,
+ mCameraTurnedOnTimer = new StopwatchTimer(mBsi.mClock, Uid.this, CAMERA_TURNED_ON,
mBsi.mCameraTurnedOnTimers, mBsi.mOnBatteryTimeBase);
}
return mCameraTurnedOnTimer;
@@ -8013,7 +7971,7 @@
public StopwatchTimer createForegroundActivityTimerLocked() {
if (mForegroundActivityTimer == null) {
- mForegroundActivityTimer = new StopwatchTimer(mBsi.mClocks, Uid.this,
+ mForegroundActivityTimer = new StopwatchTimer(mBsi.mClock, Uid.this,
FOREGROUND_ACTIVITY, null, mBsi.mOnBatteryTimeBase);
}
return mForegroundActivityTimer;
@@ -8021,7 +7979,7 @@
public StopwatchTimer createForegroundServiceTimerLocked() {
if (mForegroundServiceTimer == null) {
- mForegroundServiceTimer = new StopwatchTimer(mBsi.mClocks, Uid.this,
+ mForegroundServiceTimer = new StopwatchTimer(mBsi.mClock, Uid.this,
FOREGROUND_SERVICE, null, mBsi.mOnBatteryTimeBase);
}
return mForegroundServiceTimer;
@@ -8029,7 +7987,7 @@
public DualTimer createAggregatedPartialWakelockTimerLocked() {
if (mAggregatedPartialWakelockTimer == null) {
- mAggregatedPartialWakelockTimer = new DualTimer(mBsi.mClocks, this,
+ mAggregatedPartialWakelockTimer = new DualTimer(mBsi.mClock, this,
AGGREGATED_WAKE_TYPE_PARTIAL, null,
mBsi.mOnBatteryScreenOffTimeBase, mOnBatteryScreenOffBackgroundTimeBase);
}
@@ -8038,7 +7996,7 @@
public DualTimer createBluetoothScanTimerLocked() {
if (mBluetoothScanTimer == null) {
- mBluetoothScanTimer = new DualTimer(mBsi.mClocks, Uid.this, BLUETOOTH_SCAN_ON,
+ mBluetoothScanTimer = new DualTimer(mBsi.mClock, Uid.this, BLUETOOTH_SCAN_ON,
mBsi.mBluetoothScanOnTimers, mBsi.mOnBatteryTimeBase,
mOnBatteryBackgroundTimeBase);
}
@@ -8047,7 +8005,7 @@
public DualTimer createBluetoothUnoptimizedScanTimerLocked() {
if (mBluetoothUnoptimizedScanTimer == null) {
- mBluetoothUnoptimizedScanTimer = new DualTimer(mBsi.mClocks, Uid.this,
+ mBluetoothUnoptimizedScanTimer = new DualTimer(mBsi.mClock, Uid.this,
BLUETOOTH_UNOPTIMIZED_SCAN_ON, null,
mBsi.mOnBatteryTimeBase, mOnBatteryBackgroundTimeBase);
}
@@ -8125,7 +8083,7 @@
public BatchTimer createVibratorOnTimerLocked() {
if (mVibratorOnTimer == null) {
- mVibratorOnTimer = new BatchTimer(mBsi.mClocks, Uid.this, VIBRATOR_ON,
+ mVibratorOnTimer = new BatchTimer(mBsi.mClock, Uid.this, VIBRATOR_ON,
mBsi.mOnBatteryTimeBase);
}
return mVibratorOnTimer;
@@ -8311,10 +8269,10 @@
detachIfNotNull(mProcessStateTimer[i]);
if (in == null) {
- mProcessStateTimer[i] = new StopwatchTimer(mBsi.mClocks, this, PROCESS_STATE, null,
+ mProcessStateTimer[i] = new StopwatchTimer(mBsi.mClock, this, PROCESS_STATE, null,
mBsi.mOnBatteryTimeBase);
} else {
- mProcessStateTimer[i] = new StopwatchTimer(mBsi.mClocks, this, PROCESS_STATE, null,
+ mProcessStateTimer[i] = new StopwatchTimer(mBsi.mClock, this, PROCESS_STATE, null,
mBsi.mOnBatteryTimeBase, in);
}
}
@@ -8375,10 +8333,10 @@
}
detachIfNotNull(mWifiBatchedScanTimer[i]);
if (in == null) {
- mWifiBatchedScanTimer[i] = new StopwatchTimer(mBsi.mClocks, this, WIFI_BATCHED_SCAN,
+ mWifiBatchedScanTimer[i] = new StopwatchTimer(mBsi.mClock, this, WIFI_BATCHED_SCAN,
collected, mBsi.mOnBatteryTimeBase);
} else {
- mWifiBatchedScanTimer[i] = new StopwatchTimer(mBsi.mClocks, this, WIFI_BATCHED_SCAN,
+ mWifiBatchedScanTimer[i] = new StopwatchTimer(mBsi.mClock, this, WIFI_BATCHED_SCAN,
collected, mBsi.mOnBatteryTimeBase, in);
}
}
@@ -9172,7 +9130,7 @@
for (int j = 0; j < numSyncs; j++) {
String syncName = in.readString();
if (in.readInt() != 0) {
- mSyncStats.add(syncName, new DualTimer(mBsi.mClocks, Uid.this, SYNC, null,
+ mSyncStats.add(syncName, new DualTimer(mBsi.mClock, Uid.this, SYNC, null,
mBsi.mOnBatteryTimeBase, mOnBatteryBackgroundTimeBase, in));
}
}
@@ -9182,7 +9140,7 @@
for (int j = 0; j < numJobs; j++) {
String jobName = in.readString();
if (in.readInt() != 0) {
- mJobStats.add(jobName, new DualTimer(mBsi.mClocks, Uid.this, JOB, null,
+ mJobStats.add(jobName, new DualTimer(mBsi.mClock, Uid.this, JOB, null,
mBsi.mOnBatteryTimeBase, mOnBatteryBackgroundTimeBase, in));
}
}
@@ -9227,21 +9185,21 @@
mWifiRunning = false;
if (in.readInt() != 0) {
- mWifiRunningTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, WIFI_RUNNING,
+ mWifiRunningTimer = new StopwatchTimer(mBsi.mClock, Uid.this, WIFI_RUNNING,
mBsi.mWifiRunningTimers, mBsi.mOnBatteryTimeBase, in);
} else {
mWifiRunningTimer = null;
}
mFullWifiLockOut = false;
if (in.readInt() != 0) {
- mFullWifiLockTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, FULL_WIFI_LOCK,
+ mFullWifiLockTimer = new StopwatchTimer(mBsi.mClock, Uid.this, FULL_WIFI_LOCK,
mBsi.mFullWifiLockTimers, mBsi.mOnBatteryTimeBase, in);
} else {
mFullWifiLockTimer = null;
}
mWifiScanStarted = false;
if (in.readInt() != 0) {
- mWifiScanTimer = new DualTimer(mBsi.mClocks, Uid.this, WIFI_SCAN,
+ mWifiScanTimer = new DualTimer(mBsi.mClock, Uid.this, WIFI_SCAN,
mBsi.mWifiScanTimers, mBsi.mOnBatteryTimeBase, mOnBatteryBackgroundTimeBase,
in);
} else {
@@ -9257,49 +9215,50 @@
}
mWifiMulticastWakelockCount = 0;
if (in.readInt() != 0) {
- mWifiMulticastTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, WIFI_MULTICAST_ENABLED,
+ mWifiMulticastTimer = new StopwatchTimer(mBsi.mClock, Uid.this,
+ WIFI_MULTICAST_ENABLED,
mBsi.mWifiMulticastTimers, mBsi.mOnBatteryTimeBase, in);
} else {
mWifiMulticastTimer = null;
}
if (in.readInt() != 0) {
- mAudioTurnedOnTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, AUDIO_TURNED_ON,
+ mAudioTurnedOnTimer = new StopwatchTimer(mBsi.mClock, Uid.this, AUDIO_TURNED_ON,
mBsi.mAudioTurnedOnTimers, mBsi.mOnBatteryTimeBase, in);
} else {
mAudioTurnedOnTimer = null;
}
if (in.readInt() != 0) {
- mVideoTurnedOnTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, VIDEO_TURNED_ON,
+ mVideoTurnedOnTimer = new StopwatchTimer(mBsi.mClock, Uid.this, VIDEO_TURNED_ON,
mBsi.mVideoTurnedOnTimers, mBsi.mOnBatteryTimeBase, in);
} else {
mVideoTurnedOnTimer = null;
}
if (in.readInt() != 0) {
- mFlashlightTurnedOnTimer = new StopwatchTimer(mBsi.mClocks, Uid.this,
+ mFlashlightTurnedOnTimer = new StopwatchTimer(mBsi.mClock, Uid.this,
FLASHLIGHT_TURNED_ON, mBsi.mFlashlightTurnedOnTimers, mBsi.mOnBatteryTimeBase, in);
} else {
mFlashlightTurnedOnTimer = null;
}
if (in.readInt() != 0) {
- mCameraTurnedOnTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, CAMERA_TURNED_ON,
+ mCameraTurnedOnTimer = new StopwatchTimer(mBsi.mClock, Uid.this, CAMERA_TURNED_ON,
mBsi.mCameraTurnedOnTimers, mBsi.mOnBatteryTimeBase, in);
} else {
mCameraTurnedOnTimer = null;
}
if (in.readInt() != 0) {
- mForegroundActivityTimer = new StopwatchTimer(mBsi.mClocks, Uid.this,
+ mForegroundActivityTimer = new StopwatchTimer(mBsi.mClock, Uid.this,
FOREGROUND_ACTIVITY, null, mBsi.mOnBatteryTimeBase, in);
} else {
mForegroundActivityTimer = null;
}
if (in.readInt() != 0) {
- mForegroundServiceTimer = new StopwatchTimer(mBsi.mClocks, Uid.this,
+ mForegroundServiceTimer = new StopwatchTimer(mBsi.mClock, Uid.this,
FOREGROUND_SERVICE, null, mBsi.mOnBatteryTimeBase, in);
} else {
mForegroundServiceTimer = null;
}
if (in.readInt() != 0) {
- mAggregatedPartialWakelockTimer = new DualTimer(mBsi.mClocks, this,
+ mAggregatedPartialWakelockTimer = new DualTimer(mBsi.mClock, this,
AGGREGATED_WAKE_TYPE_PARTIAL, null,
mBsi.mOnBatteryScreenOffTimeBase, mOnBatteryScreenOffBackgroundTimeBase,
in);
@@ -9307,14 +9266,14 @@
mAggregatedPartialWakelockTimer = null;
}
if (in.readInt() != 0) {
- mBluetoothScanTimer = new DualTimer(mBsi.mClocks, Uid.this, BLUETOOTH_SCAN_ON,
+ mBluetoothScanTimer = new DualTimer(mBsi.mClock, Uid.this, BLUETOOTH_SCAN_ON,
mBsi.mBluetoothScanOnTimers, mBsi.mOnBatteryTimeBase,
mOnBatteryBackgroundTimeBase, in);
} else {
mBluetoothScanTimer = null;
}
if (in.readInt() != 0) {
- mBluetoothUnoptimizedScanTimer = new DualTimer(mBsi.mClocks, Uid.this,
+ mBluetoothUnoptimizedScanTimer = new DualTimer(mBsi.mClock, Uid.this,
BLUETOOTH_UNOPTIMIZED_SCAN_ON, null,
mBsi.mOnBatteryTimeBase, mOnBatteryBackgroundTimeBase, in);
} else {
@@ -9339,7 +9298,7 @@
}
}
if (in.readInt() != 0) {
- mVibratorOnTimer = new BatchTimer(mBsi.mClocks, Uid.this, VIBRATOR_ON,
+ mVibratorOnTimer = new BatchTimer(mBsi.mClock, Uid.this, VIBRATOR_ON,
mBsi.mOnBatteryTimeBase, in);
} else {
mVibratorOnTimer = null;
@@ -9549,7 +9508,7 @@
return null;
}
- return new StopwatchTimer(mBsi.mClocks, mUid, type, pool, timeBase, in);
+ return new StopwatchTimer(mBsi.mClock, mUid, type, pool, timeBase, in);
}
/**
@@ -9565,7 +9524,7 @@
return null;
}
- return new DualTimer(mBsi.mClocks, mUid, type, pool, timeBase, bgTimeBase, in);
+ return new DualTimer(mBsi.mClock, mUid, type, pool, timeBase, bgTimeBase, in);
}
boolean reset(long elapsedRealtimeUs) {
@@ -9662,7 +9621,7 @@
pool = new ArrayList<StopwatchTimer>();
mBsi.mSensorTimers.put(mHandle, pool);
}
- return new DualTimer(mBsi.mClocks, mUid, 0, pool, timeBase, bgTimeBase, in);
+ return new DualTimer(mBsi.mClock, mUid, 0, pool, timeBase, bgTimeBase, in);
}
boolean reset(long elapsedRealtimeUs) {
@@ -10164,7 +10123,7 @@
@UnsupportedAppUsage
public void startLaunchedLocked() {
- startLaunchedLocked(mBsi.mClocks.uptimeMillis());
+ startLaunchedLocked(mBsi.mClock.uptimeMillis());
}
public void startLaunchedLocked(long uptimeMs) {
@@ -10177,7 +10136,7 @@
@UnsupportedAppUsage
public void stopLaunchedLocked() {
- stopLaunchedLocked(mBsi.mClocks.uptimeMillis());
+ stopLaunchedLocked(mBsi.mClock.uptimeMillis());
}
public void stopLaunchedLocked(long uptimeMs) {
@@ -10195,7 +10154,7 @@
@UnsupportedAppUsage
public void startRunningLocked() {
- startRunningLocked(mBsi.mClocks.uptimeMillis());
+ startRunningLocked(mBsi.mClock.uptimeMillis());
}
public void startRunningLocked(long uptimeMs) {
@@ -10208,7 +10167,7 @@
@UnsupportedAppUsage
public void stopRunningLocked() {
- stopRunningLocked(mBsi.mClocks.uptimeMillis());
+ stopRunningLocked(mBsi.mClock.uptimeMillis());
}
public void stopRunningLocked(long uptimeMs) {
@@ -10267,7 +10226,7 @@
@GuardedBy("mBsi")
public void updateUidProcessStateLocked(int procState) {
updateUidProcessStateLocked(procState,
- mBsi.mClocks.elapsedRealtime(), mBsi.mClocks.uptimeMillis());
+ mBsi.mClock.elapsedRealtime(), mBsi.mClock.uptimeMillis());
}
public void updateUidProcessStateLocked(int procState,
@@ -10432,7 +10391,7 @@
timers = new ArrayList<StopwatchTimer>();
mBsi.mSensorTimers.put(sensor, timers);
}
- t = new DualTimer(mBsi.mClocks, this, BatteryStats.SENSOR, timers,
+ t = new DualTimer(mBsi.mClock, this, BatteryStats.SENSOR, timers,
mBsi.mOnBatteryTimeBase, mOnBatteryBackgroundTimeBase);
se.mTimer = t;
return t;
@@ -10483,7 +10442,7 @@
case WAKE_TYPE_PARTIAL: {
DualTimer t = wl.mTimerPartial;
if (t == null) {
- t = new DualTimer(mBsi.mClocks, this, WAKE_TYPE_PARTIAL,
+ t = new DualTimer(mBsi.mClock, this, WAKE_TYPE_PARTIAL,
mBsi.mPartialTimers, mBsi.mOnBatteryScreenOffTimeBase,
mOnBatteryScreenOffBackgroundTimeBase);
wl.mTimerPartial = t;
@@ -10493,7 +10452,7 @@
case WAKE_TYPE_FULL: {
StopwatchTimer t = wl.mTimerFull;
if (t == null) {
- t = new StopwatchTimer(mBsi.mClocks, this, WAKE_TYPE_FULL,
+ t = new StopwatchTimer(mBsi.mClock, this, WAKE_TYPE_FULL,
mBsi.mFullTimers, mBsi.mOnBatteryTimeBase);
wl.mTimerFull = t;
}
@@ -10502,7 +10461,7 @@
case WAKE_TYPE_WINDOW: {
StopwatchTimer t = wl.mTimerWindow;
if (t == null) {
- t = new StopwatchTimer(mBsi.mClocks, this, WAKE_TYPE_WINDOW,
+ t = new StopwatchTimer(mBsi.mClock, this, WAKE_TYPE_WINDOW,
mBsi.mWindowTimers, mBsi.mOnBatteryTimeBase);
wl.mTimerWindow = t;
}
@@ -10511,7 +10470,7 @@
case WAKE_TYPE_DRAW: {
StopwatchTimer t = wl.mTimerDraw;
if (t == null) {
- t = new StopwatchTimer(mBsi.mClocks, this, WAKE_TYPE_DRAW,
+ t = new StopwatchTimer(mBsi.mClock, this, WAKE_TYPE_DRAW,
mBsi.mDrawTimers, mBsi.mOnBatteryTimeBase);
wl.mTimerDraw = t;
}
@@ -10599,13 +10558,13 @@
public BatteryStatsImpl(File systemDir, Handler handler, PlatformIdleStateCallback cb,
MeasuredEnergyRetriever energyStatsCb, UserInfoProvider userInfoProvider) {
- this(new SystemClocks(), systemDir, handler, cb, energyStatsCb, userInfoProvider);
+ this(Clock.SYSTEM_CLOCK, systemDir, handler, cb, energyStatsCb, userInfoProvider);
}
- private BatteryStatsImpl(Clocks clocks, File systemDir, Handler handler,
+ private BatteryStatsImpl(Clock clock, File systemDir, Handler handler,
PlatformIdleStateCallback cb, MeasuredEnergyRetriever energyStatsCb,
UserInfoProvider userInfoProvider) {
- init(clocks);
+ init(clock);
if (systemDir == null) {
mStatsFile = null;
@@ -10621,8 +10580,8 @@
mStartCount++;
initTimersAndCounters();
mOnBattery = mOnBatteryInternal = false;
- long uptimeUs = mClocks.uptimeMillis() * 1000;
- long realtimeUs = mClocks.elapsedRealtime() * 1000;
+ long uptimeUs = mClock.uptimeMillis() * 1000;
+ long realtimeUs = mClock.elapsedRealtime() * 1000;
initTimes(uptimeUs, realtimeUs);
mStartPlatformVersion = mEndPlatformVersion = Build.ID;
initDischarge(realtimeUs);
@@ -10639,29 +10598,29 @@
@VisibleForTesting
protected void initTimersAndCounters() {
- mScreenOnTimer = new StopwatchTimer(mClocks, null, -1, null, mOnBatteryTimeBase);
- mScreenDozeTimer = new StopwatchTimer(mClocks, null, -1, null, mOnBatteryTimeBase);
+ mScreenOnTimer = new StopwatchTimer(mClock, null, -1, null, mOnBatteryTimeBase);
+ mScreenDozeTimer = new StopwatchTimer(mClock, null, -1, null, mOnBatteryTimeBase);
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
- mScreenBrightnessTimer[i] = new StopwatchTimer(mClocks, null, -100-i, null,
+ mScreenBrightnessTimer[i] = new StopwatchTimer(mClock, null, -100 - i, null,
mOnBatteryTimeBase);
}
- mInteractiveTimer = new StopwatchTimer(mClocks, null, -10, null, mOnBatteryTimeBase);
- mPowerSaveModeEnabledTimer = new StopwatchTimer(mClocks, null, -2, null,
+ mInteractiveTimer = new StopwatchTimer(mClock, null, -10, null, mOnBatteryTimeBase);
+ mPowerSaveModeEnabledTimer = new StopwatchTimer(mClock, null, -2, null,
mOnBatteryTimeBase);
- mDeviceIdleModeLightTimer = new StopwatchTimer(mClocks, null, -11, null,
+ mDeviceIdleModeLightTimer = new StopwatchTimer(mClock, null, -11, null,
mOnBatteryTimeBase);
- mDeviceIdleModeFullTimer = new StopwatchTimer(mClocks, null, -14, null, mOnBatteryTimeBase);
- mDeviceLightIdlingTimer = new StopwatchTimer(mClocks, null, -15, null, mOnBatteryTimeBase);
- mDeviceIdlingTimer = new StopwatchTimer(mClocks, null, -12, null, mOnBatteryTimeBase);
- mPhoneOnTimer = new StopwatchTimer(mClocks, null, -3, null, mOnBatteryTimeBase);
+ mDeviceIdleModeFullTimer = new StopwatchTimer(mClock, null, -14, null, mOnBatteryTimeBase);
+ mDeviceLightIdlingTimer = new StopwatchTimer(mClock, null, -15, null, mOnBatteryTimeBase);
+ mDeviceIdlingTimer = new StopwatchTimer(mClock, null, -12, null, mOnBatteryTimeBase);
+ mPhoneOnTimer = new StopwatchTimer(mClock, null, -3, null, mOnBatteryTimeBase);
for (int i = 0; i < CellSignalStrength.getNumSignalStrengthLevels(); i++) {
- mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(mClocks, null, -200-i, null,
+ mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(mClock, null, -200 - i, null,
mOnBatteryTimeBase);
}
- mPhoneSignalScanningTimer = new StopwatchTimer(mClocks, null, -200+1, null,
+ mPhoneSignalScanningTimer = new StopwatchTimer(mClock, null, -200 + 1, null,
mOnBatteryTimeBase);
for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
- mPhoneDataConnectionsTimer[i] = new StopwatchTimer(mClocks, null, -300-i, null,
+ mPhoneDataConnectionsTimer[i] = new StopwatchTimer(mClock, null, -300 - i, null,
mOnBatteryTimeBase);
}
for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
@@ -10673,38 +10632,38 @@
NUM_BT_TX_LEVELS);
mModemActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
ModemActivityInfo.getNumTxPowerLevels());
- mMobileRadioActiveTimer = new StopwatchTimer(mClocks, null, -400, null, mOnBatteryTimeBase);
- mMobileRadioActivePerAppTimer = new StopwatchTimer(mClocks, null, -401, null,
+ mMobileRadioActiveTimer = new StopwatchTimer(mClock, null, -400, null, mOnBatteryTimeBase);
+ mMobileRadioActivePerAppTimer = new StopwatchTimer(mClock, null, -401, null,
mOnBatteryTimeBase);
mMobileRadioActiveAdjustedTime = new LongSamplingCounter(mOnBatteryTimeBase);
mMobileRadioActiveUnknownTime = new LongSamplingCounter(mOnBatteryTimeBase);
mMobileRadioActiveUnknownCount = new LongSamplingCounter(mOnBatteryTimeBase);
- mWifiMulticastWakelockTimer = new StopwatchTimer(mClocks, null,
+ mWifiMulticastWakelockTimer = new StopwatchTimer(mClock, null,
WIFI_AGGREGATE_MULTICAST_ENABLED, null, mOnBatteryTimeBase);
- mWifiOnTimer = new StopwatchTimer(mClocks, null, -4, null, mOnBatteryTimeBase);
- mGlobalWifiRunningTimer = new StopwatchTimer(mClocks, null, -5, null, mOnBatteryTimeBase);
+ mWifiOnTimer = new StopwatchTimer(mClock, null, -4, null, mOnBatteryTimeBase);
+ mGlobalWifiRunningTimer = new StopwatchTimer(mClock, null, -5, null, mOnBatteryTimeBase);
for (int i=0; i<NUM_WIFI_STATES; i++) {
- mWifiStateTimer[i] = new StopwatchTimer(mClocks, null, -600-i, null,
+ mWifiStateTimer[i] = new StopwatchTimer(mClock, null, -600 - i, null,
mOnBatteryTimeBase);
}
for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
- mWifiSupplStateTimer[i] = new StopwatchTimer(mClocks, null, -700-i, null,
+ mWifiSupplStateTimer[i] = new StopwatchTimer(mClock, null, -700 - i, null,
mOnBatteryTimeBase);
}
for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
- mWifiSignalStrengthsTimer[i] = new StopwatchTimer(mClocks, null, -800-i, null,
+ mWifiSignalStrengthsTimer[i] = new StopwatchTimer(mClock, null, -800 - i, null,
mOnBatteryTimeBase);
}
- mWifiActiveTimer = new StopwatchTimer(mClocks, null, -900, null, mOnBatteryTimeBase);
+ mWifiActiveTimer = new StopwatchTimer(mClock, null, -900, null, mOnBatteryTimeBase);
for (int i=0; i< mGpsSignalQualityTimer.length; i++) {
- mGpsSignalQualityTimer[i] = new StopwatchTimer(mClocks, null, -1000-i, null,
- mOnBatteryTimeBase);
+ mGpsSignalQualityTimer[i] = new StopwatchTimer(mClock, null, -1000 - i, null,
+ mOnBatteryTimeBase);
}
- mAudioOnTimer = new StopwatchTimer(mClocks, null, -7, null, mOnBatteryTimeBase);
- mVideoOnTimer = new StopwatchTimer(mClocks, null, -8, null, mOnBatteryTimeBase);
- mFlashlightOnTimer = new StopwatchTimer(mClocks, null, -9, null, mOnBatteryTimeBase);
- mCameraOnTimer = new StopwatchTimer(mClocks, null, -13, null, mOnBatteryTimeBase);
- mBluetoothScanTimer = new StopwatchTimer(mClocks, null, -14, null, mOnBatteryTimeBase);
+ mAudioOnTimer = new StopwatchTimer(mClock, null, -7, null, mOnBatteryTimeBase);
+ mVideoOnTimer = new StopwatchTimer(mClock, null, -8, null, mOnBatteryTimeBase);
+ mFlashlightOnTimer = new StopwatchTimer(mClock, null, -9, null, mOnBatteryTimeBase);
+ mCameraOnTimer = new StopwatchTimer(mClock, null, -13, null, mOnBatteryTimeBase);
+ mBluetoothScanTimer = new StopwatchTimer(mClock, null, -14, null, mOnBatteryTimeBase);
mDischargeScreenOffCounter = new LongSamplingCounter(mOnBatteryScreenOffTimeBase);
mDischargeScreenDozeCounter = new LongSamplingCounter(mOnBatteryTimeBase);
mDischargeLightDozeCounter = new LongSamplingCounter(mOnBatteryTimeBase);
@@ -10719,11 +10678,11 @@
@UnsupportedAppUsage
public BatteryStatsImpl(Parcel p) {
- this(new SystemClocks(), p);
+ this(Clock.SYSTEM_CLOCK, p);
}
- public BatteryStatsImpl(Clocks clocks, Parcel p) {
- init(clocks);
+ public BatteryStatsImpl(Clock clock, Parcel p) {
+ init(clock);
mStatsFile = null;
mCheckinFile = null;
mDailyFile = null;
@@ -10791,7 +10750,7 @@
public void updateDailyDeadlineLocked() {
// Get the current time.
- long currentTimeMs = mDailyStartTimeMs = mClocks.currentTimeMillis();
+ long currentTimeMs = mDailyStartTimeMs = mClock.currentTimeMillis();
Calendar calDeadline = Calendar.getInstance();
calDeadline.setTimeInMillis(currentTimeMs);
@@ -10819,7 +10778,7 @@
public void recordDailyStatsLocked() {
DailyItem item = new DailyItem();
item.mStartTime = mDailyStartTimeMs;
- item.mEndTime = mClocks.currentTimeMillis();
+ item.mEndTime = mClock.currentTimeMillis();
boolean hasData = false;
if (mDailyDischargeStepTracker.mNumStepDurations > 0) {
hasData = true;
@@ -11184,7 +11143,7 @@
}
void initTimes(long uptimeUs, long realtimeUs) {
- mStartClockTimeMs = mClocks.currentTimeMillis();
+ mStartClockTimeMs = mClock.currentTimeMillis();
mOnBatteryTimeBase.init(uptimeUs, realtimeUs);
mOnBatteryScreenOffTimeBase.init(uptimeUs, realtimeUs);
mRealtimeUs = 0;
@@ -11216,9 +11175,9 @@
}
public void resetAllStatsCmdLocked() {
- final long mSecUptime = mClocks.uptimeMillis();
+ final long mSecUptime = mClock.uptimeMillis();
long uptimeUs = mSecUptime * 1000;
- long mSecRealtime = mClocks.elapsedRealtime();
+ long mSecRealtime = mClock.elapsedRealtime();
long realtimeUs = mSecRealtime * 1000;
resetAllStatsLocked(mSecUptime, mSecRealtime, RESET_REASON_ADB_COMMAND);
mDischargeStartLevel = mHistoryCur.batteryLevel;
@@ -12752,7 +12711,7 @@
* Read and distribute kernel wake lock use across apps.
*/
public void updateKernelWakelocksLocked() {
- updateKernelWakelocksLocked(mClocks.elapsedRealtime() * 1000);
+ updateKernelWakelocksLocked(mClock.elapsedRealtime() * 1000);
}
/**
@@ -12773,7 +12732,7 @@
SamplingTimer kwlt = mKernelWakelockStats.get(name);
if (kwlt == null) {
- kwlt = new SamplingTimer(mClocks, mOnBatteryScreenOffTimeBase);
+ kwlt = new SamplingTimer(mClock, mOnBatteryScreenOffTimeBase);
mKernelWakelockStats.put(name, kwlt);
}
@@ -12815,7 +12774,7 @@
* Reads the newest memory stats from the kernel.
*/
public void updateKernelMemoryBandwidthLocked() {
- updateKernelMemoryBandwidthLocked(mClocks.elapsedRealtime() * 1000);
+ updateKernelMemoryBandwidthLocked(mClock.elapsedRealtime() * 1000);
}
public void updateKernelMemoryBandwidthLocked(long elapsedRealtimeUs) {
@@ -12828,7 +12787,7 @@
if ((index = mKernelMemoryStats.indexOfKey(bandwidthEntries.keyAt(i))) >= 0) {
timer = mKernelMemoryStats.valueAt(index);
} else {
- timer = new SamplingTimer(mClocks, mOnBatteryTimeBase);
+ timer = new SamplingTimer(mClock, mOnBatteryTimeBase);
mKernelMemoryStats.put(bandwidthEntries.keyAt(i), timer);
}
timer.update(bandwidthEntries.valueAt(i), 1, elapsedRealtimeUs);
@@ -13126,8 +13085,8 @@
// So, we distribute total time spent by an uid to different cpu freqs based on the
// amount of time cpu was running at that freq.
final int updatedUidsCount = updatedUids.size();
- final long elapsedRealtimeMs = mClocks.elapsedRealtime();
- final long uptimeMs = mClocks.uptimeMillis();
+ final long elapsedRealtimeMs = mClock.elapsedRealtime();
+ final long uptimeMs = mClock.uptimeMillis();
for (int i = 0; i < updatedUidsCount; ++i) {
final Uid u = getUidStatsLocked(updatedUids.keyAt(i), elapsedRealtimeMs, uptimeMs);
final long appCpuTimeUs = updatedUids.valueAt(i);
@@ -13179,8 +13138,8 @@
@Nullable SparseLongArray updatedUids, boolean onBattery) {
mTempTotalCpuUserTimeUs = mTempTotalCpuSystemTimeUs = 0;
final int numWakelocks = partialTimers == null ? 0 : partialTimers.size();
- final long startTimeMs = mClocks.uptimeMillis();
- final long elapsedRealtimeMs = mClocks.elapsedRealtime();
+ final long startTimeMs = mClock.uptimeMillis();
+ final long elapsedRealtimeMs = mClock.elapsedRealtime();
mCpuUidUserSysTimeReader.readDelta(false, (uid, timesUs) -> {
long userTimeUs = timesUs[0], systemTimeUs = timesUs[1];
@@ -13235,7 +13194,7 @@
}
});
- final long elapsedTimeMs = mClocks.uptimeMillis() - startTimeMs;
+ final long elapsedTimeMs = mClock.uptimeMillis() - startTimeMs;
if (DEBUG_ENERGY_CPU || elapsedTimeMs >= 100) {
Slog.d(TAG, "Reading cpu stats took " + elapsedTimeMs + "ms");
}
@@ -13296,8 +13255,8 @@
final int numWakelocks = partialTimers == null ? 0 : partialTimers.size();
final int numClusters = mPowerProfile.getNumCpuClusters();
mWakeLockAllocationsUs = null;
- final long startTimeMs = mClocks.uptimeMillis();
- final long elapsedRealtimeMs = mClocks.elapsedRealtime();
+ final long startTimeMs = mClock.uptimeMillis();
+ final long elapsedRealtimeMs = mClock.elapsedRealtime();
// If power is being accumulated for attribution, data needs to be read immediately.
final boolean forceRead = powerAccumulator != null;
mCpuUidFreqTimeReader.readDelta(forceRead, (uid, cpuFreqTimeMs) -> {
@@ -13372,7 +13331,7 @@
}
});
- final long elapsedTimeMs = mClocks.uptimeMillis() - startTimeMs;
+ final long elapsedTimeMs = mClock.uptimeMillis() - startTimeMs;
if (DEBUG_ENERGY_CPU || elapsedTimeMs >= 100) {
Slog.d(TAG, "Reading cpu freq times took " + elapsedTimeMs + "ms");
}
@@ -13420,8 +13379,8 @@
*/
@VisibleForTesting
public void readKernelUidCpuActiveTimesLocked(boolean onBattery) {
- final long startTimeMs = mClocks.uptimeMillis();
- final long elapsedRealtimeMs = mClocks.elapsedRealtime();
+ final long startTimeMs = mClock.uptimeMillis();
+ final long elapsedRealtimeMs = mClock.elapsedRealtime();
mCpuUidActiveTimeReader.readDelta(false, (uid, cpuActiveTimesMs) -> {
uid = mapUid(uid);
if (Process.isIsolated(uid)) {
@@ -13436,7 +13395,7 @@
u.mCpuActiveTimeMs.addCountLocked(cpuActiveTimesMs, onBattery);
});
- final long elapsedTimeMs = mClocks.uptimeMillis() - startTimeMs;
+ final long elapsedTimeMs = mClock.uptimeMillis() - startTimeMs;
if (DEBUG_ENERGY_CPU || elapsedTimeMs >= 100) {
Slog.d(TAG, "Reading cpu active times took " + elapsedTimeMs + "ms");
}
@@ -13453,8 +13412,8 @@
@VisibleForTesting
public void readKernelUidCpuClusterTimesLocked(boolean onBattery,
@Nullable CpuDeltaPowerAccumulator powerAccumulator) {
- final long startTimeMs = mClocks.uptimeMillis();
- final long elapsedRealtimeMs = mClocks.elapsedRealtime();
+ final long startTimeMs = mClock.uptimeMillis();
+ final long elapsedRealtimeMs = mClock.elapsedRealtime();
// If power is being accumulated for attribution, data needs to be read immediately.
final boolean forceRead = powerAccumulator != null;
mCpuUidClusterTimeReader.readDelta(forceRead, (uid, cpuClusterTimesMs) -> {
@@ -13475,7 +13434,7 @@
}
});
- final long elapsedTimeMs = mClocks.uptimeMillis() - startTimeMs;
+ final long elapsedTimeMs = mClock.uptimeMillis() - startTimeMs;
if (DEBUG_ENERGY_CPU || elapsedTimeMs >= 100) {
Slog.d(TAG, "Reading cpu cluster times took " + elapsedTimeMs + "ms");
}
@@ -13654,7 +13613,7 @@
private void startRecordingHistory(final long elapsedRealtimeMs, final long uptimeMs,
boolean reset) {
mRecordingHistory = true;
- mHistoryCur.currentTime = mClocks.currentTimeMillis();
+ mHistoryCur.currentTime = mClock.currentTimeMillis();
addHistoryBufferLocked(elapsedRealtimeMs,
reset ? HistoryItem.CMD_RESET : HistoryItem.CMD_CURRENT_TIME,
mHistoryCur);
@@ -13696,7 +13655,7 @@
final int chargeFullUah, final long chargeTimeToFullSeconds) {
setBatteryStateLocked(status, health, plugType, level, temp, voltageMv, chargeUah,
chargeFullUah, chargeTimeToFullSeconds,
- mClocks.elapsedRealtime(), mClocks.uptimeMillis(), mClocks.currentTimeMillis());
+ mClock.elapsedRealtime(), mClock.uptimeMillis(), mClock.currentTimeMillis());
}
public void setBatteryStateLocked(final int status, final int health, final int plugType,
@@ -13933,12 +13892,12 @@
public long getAwakeTimeBattery() {
// This previously evaluated to mOnBatteryTimeBase.getUptime(getBatteryUptimeLocked());
// for over a decade, but surely that was a mistake.
- return getBatteryUptimeLocked(mClocks.uptimeMillis());
+ return getBatteryUptimeLocked(mClock.uptimeMillis());
}
@UnsupportedAppUsage
public long getAwakeTimePlugged() {
- return (mClocks.uptimeMillis() * 1000) - getAwakeTimeBattery();
+ return (mClock.uptimeMillis() * 1000) - getAwakeTimeBattery();
}
@Override
@@ -14188,7 +14147,7 @@
* @return battery uptime in microseconds
*/
protected long getBatteryUptimeLocked() {
- return getBatteryUptimeLocked(mClocks.uptimeMillis());
+ return getBatteryUptimeLocked(mClock.uptimeMillis());
}
/**
@@ -14361,7 +14320,7 @@
*/
@UnsupportedAppUsage
public Uid getUidStatsLocked(int uid) {
- return getUidStatsLocked(uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ return getUidStatsLocked(uid, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public Uid getUidStatsLocked(int uid, long elapsedRealtimeMs, long uptimeMs) {
@@ -14390,6 +14349,18 @@
}
public void onUserRemovedLocked(int userId) {
+ if (mExternalSync != null) {
+ // Clear out the removed user's UIDs after a short delay. The delay is needed
+ // because at the point that this method is called, some activities are still
+ // being wrapped up by those UIDs
+ mExternalSync.scheduleCleanupDueToRemovedUser(userId);
+ }
+ }
+
+ /**
+ * Removes battery stats for UIDs corresponding to a removed user.
+ */
+ public void clearRemovedUserUidsLocked(int userId) {
final int firstUidForUser = UserHandle.getUid(userId, 0);
final int lastUidForUser = UserHandle.getUid(userId, UserHandle.PER_USER_RANGE - 1);
mUidStats.put(firstUidForUser, null);
@@ -14403,6 +14374,7 @@
}
}
mUidStats.removeAtRange(firstIndex, lastIndex - firstIndex + 1);
+ removeCpuStatsForUidRangeLocked(firstUidForUser, lastUidForUser);
}
/**
@@ -14410,7 +14382,7 @@
*/
@UnsupportedAppUsage
public void removeUidStatsLocked(int uid) {
- removeUidStatsLocked(uid, mClocks.elapsedRealtime());
+ removeUidStatsLocked(uid, mClock.elapsedRealtime());
}
/**
@@ -14426,12 +14398,45 @@
}
/**
+ * Removes the data for the deleted UIDs from the underlying kernel eBPF tables.
+ */
+ @GuardedBy("this")
+ private void removeCpuStatsForUidRangeLocked(int startUid, int endUid) {
+ if (startUid == endUid) {
+ mCpuUidUserSysTimeReader.removeUid(startUid);
+ mCpuUidFreqTimeReader.removeUid(startUid);
+ if (mConstants.TRACK_CPU_ACTIVE_CLUSTER_TIME) {
+ mCpuUidActiveTimeReader.removeUid(startUid);
+ mCpuUidClusterTimeReader.removeUid(startUid);
+ }
+ if (mKernelSingleUidTimeReader != null) {
+ mKernelSingleUidTimeReader.removeUid(startUid);
+ }
+ mNumUidsRemoved++;
+ } else if (startUid < endUid) {
+ mCpuUidFreqTimeReader.removeUidsInRange(startUid, endUid);
+ mCpuUidUserSysTimeReader.removeUidsInRange(startUid, endUid);
+ if (mConstants.TRACK_CPU_ACTIVE_CLUSTER_TIME) {
+ mCpuUidActiveTimeReader.removeUidsInRange(startUid, endUid);
+ mCpuUidClusterTimeReader.removeUidsInRange(startUid, endUid);
+ }
+ if (mKernelSingleUidTimeReader != null) {
+ mKernelSingleUidTimeReader.removeUidsInRange(startUid, endUid);
+ }
+ // Treat as one. We don't know how many uids there are in between.
+ mNumUidsRemoved++;
+ } else {
+ Slog.w(TAG, "End UID " + endUid + " is smaller than start UID " + startUid);
+ }
+ }
+
+ /**
* Retrieve the statistics object for a particular process, creating
* if needed.
*/
@UnsupportedAppUsage
public Uid.Proc getProcessStatsLocked(int uid, String name) {
- return getProcessStatsLocked(uid, name, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ return getProcessStatsLocked(uid, name, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
/**
@@ -14450,7 +14455,7 @@
*/
@UnsupportedAppUsage
public Uid.Pkg getPackageStatsLocked(int uid, String pkg) {
- return getPackageStatsLocked(uid, pkg, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ return getPackageStatsLocked(uid, pkg, mClock.elapsedRealtime(), mClock.uptimeMillis());
}
/**
@@ -14470,7 +14475,7 @@
@UnsupportedAppUsage
public Uid.Pkg.Serv getServiceStatsLocked(int uid, String pkg, String name) {
return getServiceStatsLocked(uid, pkg, name,
- mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ mClock.elapsedRealtime(), mClock.uptimeMillis());
}
public Uid.Pkg.Serv getServiceStatsLocked(int uid, String pkg, String name,
@@ -14481,7 +14486,7 @@
}
public void shutdownLocked() {
- recordShutdownLocked(mClocks.currentTimeMillis(), mClocks.elapsedRealtime());
+ recordShutdownLocked(mClock.currentTimeMillis(), mClock.elapsedRealtime());
writeSyncLocked();
mShuttingDown = true;
}
@@ -14703,7 +14708,7 @@
mNumSingleUidCpuTimeReads = 0;
mNumBatchedSingleUidCpuTimeReads = 0;
- mCpuTimeReadsTrackingStartTimeMs = mClocks.uptimeMillis();
+ mCpuTimeReadsTrackingStartTimeMs = mClock.uptimeMillis();
}
}
@@ -14712,7 +14717,7 @@
if (oldDelayMillis != newDelayMillis) {
mNumSingleUidCpuTimeReads = 0;
mNumBatchedSingleUidCpuTimeReads = 0;
- mCpuTimeReadsTrackingStartTimeMs = mClocks.uptimeMillis();
+ mCpuTimeReadsTrackingStartTimeMs = mClock.uptimeMillis();
}
}
@@ -14729,7 +14734,7 @@
private void updateUidRemoveDelay(long newTimeMs) {
UID_REMOVE_DELAY_MS = newTimeMs;
- clearPendingRemovedUids();
+ clearPendingRemovedUidsLocked();
}
public void dumpLocked(PrintWriter pw) {
@@ -14892,7 +14897,7 @@
Slog.d(TAG, "writeSummaryToParcel duration ms:"
+ (SystemClock.uptimeMillis() - start) + " bytes:" + p.dataSize());
}
- mLastWriteTimeMs = mClocks.elapsedRealtime();
+ mLastWriteTimeMs = mClock.elapsedRealtime();
writeParcelToFileLocked(p, mStatsFile, sync);
}
@@ -15026,13 +15031,13 @@
if (mHistoryBuffer.dataPosition() > 0
|| mBatteryStatsHistory.getFilesNumbers().size() > 1) {
mRecordingHistory = true;
- final long elapsedRealtimeMs = mClocks.elapsedRealtime();
- final long uptimeMs = mClocks.uptimeMillis();
+ final long elapsedRealtimeMs = mClock.elapsedRealtime();
+ final long uptimeMs = mClock.uptimeMillis();
addHistoryBufferLocked(elapsedRealtimeMs, HistoryItem.CMD_START, mHistoryCur);
startRecordingHistory(elapsedRealtimeMs, uptimeMs, false);
}
- recordDailyStatsIfNeededLocked(false, mClocks.currentTimeMillis());
+ recordDailyStatsIfNeededLocked(false, mClock.currentTimeMillis());
}
public int describeContents() {
@@ -15084,7 +15089,7 @@
// We are just arbitrarily going to insert 1 minute from the sample of
// the last run until samples in this run.
if (mHistoryBaseTimeMs > 0) {
- long oldnow = mClocks.elapsedRealtime();
+ long oldnow = mClock.elapsedRealtime();
mHistoryBaseTimeMs = mHistoryBaseTimeMs - oldnow + 1;
if (DEBUG_HISTORY) {
StringBuilder sb = new StringBuilder(128);
@@ -15335,8 +15340,8 @@
if (NU > 10000) {
throw new ParcelFormatException("File corrupt: too many uids " + NU);
}
- final long elapsedRealtimeMs = mClocks.elapsedRealtime();
- final long uptimeMs = mClocks.uptimeMillis();
+ final long elapsedRealtimeMs = mClock.elapsedRealtime();
+ final long uptimeMs = mClock.uptimeMillis();
for (int iu = 0; iu < NU; iu++) {
int uid = in.readInt();
Uid u = new Uid(this, uid, elapsedRealtimeMs, uptimeMs);
@@ -15644,8 +15649,8 @@
// if we had originally pulled a time before the RTC was set.
getStartClockTime();
- final long NOW_SYS = mClocks.uptimeMillis() * 1000;
- final long NOWREAL_SYS = mClocks.elapsedRealtime() * 1000;
+ final long nowUptime = mClock.uptimeMillis() * 1000;
+ final long nowRealtime = mClock.elapsedRealtime() * 1000;
out.writeInt(VERSION);
@@ -15664,13 +15669,13 @@
}
out.writeInt(mStartCount);
- out.writeLong(computeUptime(NOW_SYS, STATS_SINCE_CHARGED));
- out.writeLong(computeRealtime(NOWREAL_SYS, STATS_SINCE_CHARGED));
+ out.writeLong(computeUptime(nowUptime, STATS_SINCE_CHARGED));
+ out.writeLong(computeRealtime(nowRealtime, STATS_SINCE_CHARGED));
out.writeLong(mStartClockTimeMs);
out.writeString(mStartPlatformVersion);
out.writeString(mEndPlatformVersion);
- mOnBatteryTimeBase.writeSummaryToParcel(out, NOW_SYS, NOWREAL_SYS);
- mOnBatteryScreenOffTimeBase.writeSummaryToParcel(out, NOW_SYS, NOWREAL_SYS);
+ mOnBatteryTimeBase.writeSummaryToParcel(out, nowUptime, nowRealtime);
+ mOnBatteryScreenOffTimeBase.writeSummaryToParcel(out, nowUptime, nowRealtime);
out.writeInt(mDischargeUnplugLevel);
out.writeInt(mDischargePlugLevel);
out.writeInt(mDischargeCurrentLevel);
@@ -15712,52 +15717,52 @@
MeasuredEnergyStats.writeSummaryToParcel(mGlobalMeasuredEnergyStats, out, false, false);
- mScreenOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
- mScreenDozeTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ mScreenOnTimer.writeSummaryFromParcelLocked(out, nowRealtime);
+ mScreenDozeTimer.writeSummaryFromParcelLocked(out, nowRealtime);
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
- mScreenBrightnessTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ mScreenBrightnessTimer[i].writeSummaryFromParcelLocked(out, nowRealtime);
}
- mInteractiveTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
- mPowerSaveModeEnabledTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ mInteractiveTimer.writeSummaryFromParcelLocked(out, nowRealtime);
+ mPowerSaveModeEnabledTimer.writeSummaryFromParcelLocked(out, nowRealtime);
out.writeLong(mLongestLightIdleTimeMs);
out.writeLong(mLongestFullIdleTimeMs);
- mDeviceIdleModeLightTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
- mDeviceIdleModeFullTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
- mDeviceLightIdlingTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
- mDeviceIdlingTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
- mPhoneOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ mDeviceIdleModeLightTimer.writeSummaryFromParcelLocked(out, nowRealtime);
+ mDeviceIdleModeFullTimer.writeSummaryFromParcelLocked(out, nowRealtime);
+ mDeviceLightIdlingTimer.writeSummaryFromParcelLocked(out, nowRealtime);
+ mDeviceIdlingTimer.writeSummaryFromParcelLocked(out, nowRealtime);
+ mPhoneOnTimer.writeSummaryFromParcelLocked(out, nowRealtime);
for (int i = 0; i < CellSignalStrength.getNumSignalStrengthLevels(); i++) {
- mPhoneSignalStrengthsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ mPhoneSignalStrengthsTimer[i].writeSummaryFromParcelLocked(out, nowRealtime);
}
- mPhoneSignalScanningTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ mPhoneSignalScanningTimer.writeSummaryFromParcelLocked(out, nowRealtime);
for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
- mPhoneDataConnectionsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ mPhoneDataConnectionsTimer[i].writeSummaryFromParcelLocked(out, nowRealtime);
}
for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
mNetworkByteActivityCounters[i].writeSummaryFromParcelLocked(out);
mNetworkPacketActivityCounters[i].writeSummaryFromParcelLocked(out);
}
- mMobileRadioActiveTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
- mMobileRadioActivePerAppTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ mMobileRadioActiveTimer.writeSummaryFromParcelLocked(out, nowRealtime);
+ mMobileRadioActivePerAppTimer.writeSummaryFromParcelLocked(out, nowRealtime);
mMobileRadioActiveAdjustedTime.writeSummaryFromParcelLocked(out);
mMobileRadioActiveUnknownTime.writeSummaryFromParcelLocked(out);
mMobileRadioActiveUnknownCount.writeSummaryFromParcelLocked(out);
- mWifiMulticastWakelockTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
- mWifiOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
- mGlobalWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ mWifiMulticastWakelockTimer.writeSummaryFromParcelLocked(out, nowRealtime);
+ mWifiOnTimer.writeSummaryFromParcelLocked(out, nowRealtime);
+ mGlobalWifiRunningTimer.writeSummaryFromParcelLocked(out, nowRealtime);
for (int i=0; i<NUM_WIFI_STATES; i++) {
- mWifiStateTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ mWifiStateTimer[i].writeSummaryFromParcelLocked(out, nowRealtime);
}
for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
- mWifiSupplStateTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ mWifiSupplStateTimer[i].writeSummaryFromParcelLocked(out, nowRealtime);
}
for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
- mWifiSignalStrengthsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ mWifiSignalStrengthsTimer[i].writeSummaryFromParcelLocked(out, nowRealtime);
}
- mWifiActiveTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ mWifiActiveTimer.writeSummaryFromParcelLocked(out, nowRealtime);
mWifiActivity.writeSummaryToParcel(out);
for (int i=0; i< mGpsSignalQualityTimer.length; i++) {
- mGpsSignalQualityTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ mGpsSignalQualityTimer[i].writeSummaryFromParcelLocked(out, nowRealtime);
}
mBluetoothActivity.writeSummaryToParcel(out);
mModemActivity.writeSummaryToParcel(out);
@@ -15766,9 +15771,9 @@
out.writeInt(mHasModemReporting ? 1 : 0);
out.writeInt(mNumConnectivityChange);
- mFlashlightOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
- mCameraOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
- mBluetoothScanTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ mFlashlightOnTimer.writeSummaryFromParcelLocked(out, nowRealtime);
+ mCameraOnTimer.writeSummaryFromParcelLocked(out, nowRealtime);
+ mBluetoothScanTimer.writeSummaryFromParcelLocked(out, nowRealtime);
out.writeInt(mRpmStats.size());
for (Map.Entry<String, SamplingTimer> ent : mRpmStats.entrySet()) {
@@ -15776,7 +15781,7 @@
if (rpmt != null) {
out.writeInt(1);
out.writeString(ent.getKey());
- rpmt.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ rpmt.writeSummaryFromParcelLocked(out, nowRealtime);
} else {
out.writeInt(0);
}
@@ -15787,7 +15792,7 @@
if (rpmt != null) {
out.writeInt(1);
out.writeString(ent.getKey());
- rpmt.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ rpmt.writeSummaryFromParcelLocked(out, nowRealtime);
} else {
out.writeInt(0);
}
@@ -15799,7 +15804,7 @@
if (kwlt != null) {
out.writeInt(1);
out.writeString(ent.getKey());
- kwlt.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ kwlt.writeSummaryFromParcelLocked(out, nowRealtime);
} else {
out.writeInt(0);
}
@@ -15811,7 +15816,7 @@
if (timer != null) {
out.writeInt(1);
out.writeString(ent.getKey());
- timer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ timer.writeSummaryFromParcelLocked(out, nowRealtime);
} else {
out.writeInt(0);
}
@@ -15823,7 +15828,7 @@
if (kmt != null) {
out.writeInt(1);
out.writeLong(mKernelMemoryStats.keyAt(i));
- kmt.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ kmt.writeSummaryFromParcelLocked(out, nowRealtime);
} else {
out.writeInt(0);
}
@@ -15835,92 +15840,93 @@
out.writeInt(mUidStats.keyAt(iu));
Uid u = mUidStats.valueAt(iu);
- u.mOnBatteryBackgroundTimeBase.writeSummaryToParcel(out, NOW_SYS, NOWREAL_SYS);
- u.mOnBatteryScreenOffBackgroundTimeBase.writeSummaryToParcel(out, NOW_SYS, NOWREAL_SYS);
+ u.mOnBatteryBackgroundTimeBase.writeSummaryToParcel(out, nowUptime, nowRealtime);
+ u.mOnBatteryScreenOffBackgroundTimeBase.writeSummaryToParcel(out, nowUptime,
+ nowRealtime);
if (u.mWifiRunningTimer != null) {
out.writeInt(1);
- u.mWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ u.mWifiRunningTimer.writeSummaryFromParcelLocked(out, nowRealtime);
} else {
out.writeInt(0);
}
if (u.mFullWifiLockTimer != null) {
out.writeInt(1);
- u.mFullWifiLockTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ u.mFullWifiLockTimer.writeSummaryFromParcelLocked(out, nowRealtime);
} else {
out.writeInt(0);
}
if (u.mWifiScanTimer != null) {
out.writeInt(1);
- u.mWifiScanTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ u.mWifiScanTimer.writeSummaryFromParcelLocked(out, nowRealtime);
} else {
out.writeInt(0);
}
for (int i = 0; i < Uid.NUM_WIFI_BATCHED_SCAN_BINS; i++) {
if (u.mWifiBatchedScanTimer[i] != null) {
out.writeInt(1);
- u.mWifiBatchedScanTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ u.mWifiBatchedScanTimer[i].writeSummaryFromParcelLocked(out, nowRealtime);
} else {
out.writeInt(0);
}
}
if (u.mWifiMulticastTimer != null) {
out.writeInt(1);
- u.mWifiMulticastTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ u.mWifiMulticastTimer.writeSummaryFromParcelLocked(out, nowRealtime);
} else {
out.writeInt(0);
}
if (u.mAudioTurnedOnTimer != null) {
out.writeInt(1);
- u.mAudioTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ u.mAudioTurnedOnTimer.writeSummaryFromParcelLocked(out, nowRealtime);
} else {
out.writeInt(0);
}
if (u.mVideoTurnedOnTimer != null) {
out.writeInt(1);
- u.mVideoTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ u.mVideoTurnedOnTimer.writeSummaryFromParcelLocked(out, nowRealtime);
} else {
out.writeInt(0);
}
if (u.mFlashlightTurnedOnTimer != null) {
out.writeInt(1);
- u.mFlashlightTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ u.mFlashlightTurnedOnTimer.writeSummaryFromParcelLocked(out, nowRealtime);
} else {
out.writeInt(0);
}
if (u.mCameraTurnedOnTimer != null) {
out.writeInt(1);
- u.mCameraTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ u.mCameraTurnedOnTimer.writeSummaryFromParcelLocked(out, nowRealtime);
} else {
out.writeInt(0);
}
if (u.mForegroundActivityTimer != null) {
out.writeInt(1);
- u.mForegroundActivityTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ u.mForegroundActivityTimer.writeSummaryFromParcelLocked(out, nowRealtime);
} else {
out.writeInt(0);
}
if (u.mForegroundServiceTimer != null) {
out.writeInt(1);
- u.mForegroundServiceTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ u.mForegroundServiceTimer.writeSummaryFromParcelLocked(out, nowRealtime);
} else {
out.writeInt(0);
}
if (u.mAggregatedPartialWakelockTimer != null) {
out.writeInt(1);
- u.mAggregatedPartialWakelockTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ u.mAggregatedPartialWakelockTimer.writeSummaryFromParcelLocked(out, nowRealtime);
} else {
out.writeInt(0);
}
if (u.mBluetoothScanTimer != null) {
out.writeInt(1);
- u.mBluetoothScanTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ u.mBluetoothScanTimer.writeSummaryFromParcelLocked(out, nowRealtime);
} else {
out.writeInt(0);
}
if (u.mBluetoothUnoptimizedScanTimer != null) {
out.writeInt(1);
- u.mBluetoothUnoptimizedScanTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ u.mBluetoothUnoptimizedScanTimer.writeSummaryFromParcelLocked(out, nowRealtime);
} else {
out.writeInt(0);
}
@@ -15939,14 +15945,14 @@
for (int i = 0; i < Uid.NUM_PROCESS_STATE; i++) {
if (u.mProcessStateTimer[i] != null) {
out.writeInt(1);
- u.mProcessStateTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ u.mProcessStateTimer[i].writeSummaryFromParcelLocked(out, nowRealtime);
} else {
out.writeInt(0);
}
}
if (u.mVibratorOnTimer != null) {
out.writeInt(1);
- u.mVibratorOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ u.mVibratorOnTimer.writeSummaryFromParcelLocked(out, nowRealtime);
} else {
out.writeInt(0);
}
@@ -16045,25 +16051,25 @@
Uid.Wakelock wl = wakeStats.valueAt(iw);
if (wl.mTimerFull != null) {
out.writeInt(1);
- wl.mTimerFull.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ wl.mTimerFull.writeSummaryFromParcelLocked(out, nowRealtime);
} else {
out.writeInt(0);
}
if (wl.mTimerPartial != null) {
out.writeInt(1);
- wl.mTimerPartial.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ wl.mTimerPartial.writeSummaryFromParcelLocked(out, nowRealtime);
} else {
out.writeInt(0);
}
if (wl.mTimerWindow != null) {
out.writeInt(1);
- wl.mTimerWindow.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ wl.mTimerWindow.writeSummaryFromParcelLocked(out, nowRealtime);
} else {
out.writeInt(0);
}
if (wl.mTimerDraw != null) {
out.writeInt(1);
- wl.mTimerDraw.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ wl.mTimerDraw.writeSummaryFromParcelLocked(out, nowRealtime);
} else {
out.writeInt(0);
}
@@ -16074,7 +16080,7 @@
out.writeInt(NS);
for (int is=0; is<NS; is++) {
out.writeString(syncStats.keyAt(is));
- syncStats.valueAt(is).writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ syncStats.valueAt(is).writeSummaryFromParcelLocked(out, nowRealtime);
}
final ArrayMap<String, DualTimer> jobStats = u.mJobStats.getMap();
@@ -16082,7 +16088,7 @@
out.writeInt(NJ);
for (int ij=0; ij<NJ; ij++) {
out.writeString(jobStats.keyAt(ij));
- jobStats.valueAt(ij).writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ jobStats.valueAt(ij).writeSummaryFromParcelLocked(out, nowRealtime);
}
u.writeJobCompletionsToParcelLocked(out);
@@ -16106,7 +16112,7 @@
Uid.Sensor se = u.mSensorStats.valueAt(ise);
if (se.mTimer != null) {
out.writeInt(1);
- se.mTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ se.mTimer.writeSummaryFromParcelLocked(out, nowRealtime);
} else {
out.writeInt(0);
}
@@ -16145,7 +16151,7 @@
out.writeString(ps.mServiceStats.keyAt(is));
BatteryStatsImpl.Uid.Pkg.Serv ss = ps.mServiceStats.valueAt(is);
long time = ss.getStartTimeToNowLocked(
- mOnBatteryTimeBase.getUptime(NOW_SYS) / 1000);
+ mOnBatteryTimeBase.getUptime(nowUptime) / 1000);
out.writeLong(time);
out.writeInt(ss.mStarts);
out.writeInt(ss.mLaunches);
@@ -16188,35 +16194,35 @@
mOnBatteryScreenOffTimeBase.readFromParcel(in);
mScreenState = Display.STATE_UNKNOWN;
- mScreenOnTimer = new StopwatchTimer(mClocks, null, -1, null, mOnBatteryTimeBase, in);
- mScreenDozeTimer = new StopwatchTimer(mClocks, null, -1, null, mOnBatteryTimeBase, in);
+ mScreenOnTimer = new StopwatchTimer(mClock, null, -1, null, mOnBatteryTimeBase, in);
+ mScreenDozeTimer = new StopwatchTimer(mClock, null, -1, null, mOnBatteryTimeBase, in);
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
- mScreenBrightnessTimer[i] = new StopwatchTimer(mClocks, null, -100-i, null,
+ mScreenBrightnessTimer[i] = new StopwatchTimer(mClock, null, -100 - i, null,
mOnBatteryTimeBase, in);
}
mInteractive = false;
- mInteractiveTimer = new StopwatchTimer(mClocks, null, -10, null, mOnBatteryTimeBase, in);
+ mInteractiveTimer = new StopwatchTimer(mClock, null, -10, null, mOnBatteryTimeBase, in);
mPhoneOn = false;
- mPowerSaveModeEnabledTimer = new StopwatchTimer(mClocks, null, -2, null,
+ mPowerSaveModeEnabledTimer = new StopwatchTimer(mClock, null, -2, null,
mOnBatteryTimeBase, in);
mLongestLightIdleTimeMs = in.readLong();
mLongestFullIdleTimeMs = in.readLong();
- mDeviceIdleModeLightTimer = new StopwatchTimer(mClocks, null, -14, null,
+ mDeviceIdleModeLightTimer = new StopwatchTimer(mClock, null, -14, null,
mOnBatteryTimeBase, in);
- mDeviceIdleModeFullTimer = new StopwatchTimer(mClocks, null, -11, null,
+ mDeviceIdleModeFullTimer = new StopwatchTimer(mClock, null, -11, null,
mOnBatteryTimeBase, in);
- mDeviceLightIdlingTimer = new StopwatchTimer(mClocks, null, -15, null,
+ mDeviceLightIdlingTimer = new StopwatchTimer(mClock, null, -15, null,
mOnBatteryTimeBase, in);
- mDeviceIdlingTimer = new StopwatchTimer(mClocks, null, -12, null, mOnBatteryTimeBase, in);
- mPhoneOnTimer = new StopwatchTimer(mClocks, null, -3, null, mOnBatteryTimeBase, in);
+ mDeviceIdlingTimer = new StopwatchTimer(mClock, null, -12, null, mOnBatteryTimeBase, in);
+ mPhoneOnTimer = new StopwatchTimer(mClock, null, -3, null, mOnBatteryTimeBase, in);
for (int i = 0; i < CellSignalStrength.getNumSignalStrengthLevels(); i++) {
- mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(mClocks, null, -200-i,
+ mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(mClock, null, -200 - i,
null, mOnBatteryTimeBase, in);
}
- mPhoneSignalScanningTimer = new StopwatchTimer(mClocks, null, -200+1, null,
+ mPhoneSignalScanningTimer = new StopwatchTimer(mClock, null, -200 + 1, null,
mOnBatteryTimeBase, in);
for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
- mPhoneDataConnectionsTimer[i] = new StopwatchTimer(mClocks, null, -300-i,
+ mPhoneDataConnectionsTimer[i] = new StopwatchTimer(mClock, null, -300 - i,
null, mOnBatteryTimeBase, in);
}
for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
@@ -16224,39 +16230,39 @@
mNetworkPacketActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
}
mMobileRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
- mMobileRadioActiveTimer = new StopwatchTimer(mClocks, null, -400, null,
+ mMobileRadioActiveTimer = new StopwatchTimer(mClock, null, -400, null,
mOnBatteryTimeBase, in);
- mMobileRadioActivePerAppTimer = new StopwatchTimer(mClocks, null, -401, null,
+ mMobileRadioActivePerAppTimer = new StopwatchTimer(mClock, null, -401, null,
mOnBatteryTimeBase, in);
mMobileRadioActiveAdjustedTime = new LongSamplingCounter(mOnBatteryTimeBase, in);
mMobileRadioActiveUnknownTime = new LongSamplingCounter(mOnBatteryTimeBase, in);
mMobileRadioActiveUnknownCount = new LongSamplingCounter(mOnBatteryTimeBase, in);
- mWifiMulticastWakelockTimer = new StopwatchTimer(mClocks, null, -4, null,
+ mWifiMulticastWakelockTimer = new StopwatchTimer(mClock, null, -4, null,
mOnBatteryTimeBase, in);
mWifiRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
mWifiOn = false;
- mWifiOnTimer = new StopwatchTimer(mClocks, null, -4, null, mOnBatteryTimeBase, in);
+ mWifiOnTimer = new StopwatchTimer(mClock, null, -4, null, mOnBatteryTimeBase, in);
mGlobalWifiRunning = false;
- mGlobalWifiRunningTimer = new StopwatchTimer(mClocks, null, -5, null,
+ mGlobalWifiRunningTimer = new StopwatchTimer(mClock, null, -5, null,
mOnBatteryTimeBase, in);
for (int i=0; i<NUM_WIFI_STATES; i++) {
- mWifiStateTimer[i] = new StopwatchTimer(mClocks, null, -600-i,
+ mWifiStateTimer[i] = new StopwatchTimer(mClock, null, -600 - i,
null, mOnBatteryTimeBase, in);
}
for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
- mWifiSupplStateTimer[i] = new StopwatchTimer(mClocks, null, -700-i,
+ mWifiSupplStateTimer[i] = new StopwatchTimer(mClock, null, -700 - i,
null, mOnBatteryTimeBase, in);
}
for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
- mWifiSignalStrengthsTimer[i] = new StopwatchTimer(mClocks, null, -800-i,
+ mWifiSignalStrengthsTimer[i] = new StopwatchTimer(mClock, null, -800 - i,
null, mOnBatteryTimeBase, in);
}
- mWifiActiveTimer = new StopwatchTimer(mClocks, null, -900, null,
+ mWifiActiveTimer = new StopwatchTimer(mClock, null, -900, null,
mOnBatteryTimeBase, in);
mWifiActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
NUM_WIFI_TX_LEVELS, in);
for (int i=0; i<mGpsSignalQualityTimer.length; i++) {
- mGpsSignalQualityTimer[i] = new StopwatchTimer(mClocks, null, -1000-i,
+ mGpsSignalQualityTimer[i] = new StopwatchTimer(mClock, null, -1000 - i,
null, mOnBatteryTimeBase, in);
}
mBluetoothActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
@@ -16270,15 +16276,15 @@
mNumConnectivityChange = in.readInt();
mAudioOnNesting = 0;
// TODO: It's likely a mistake that mAudioOnTimer/mVideoOnTimer don't write/read to parcel!
- mAudioOnTimer = new StopwatchTimer(mClocks, null, -7, null, mOnBatteryTimeBase);
+ mAudioOnTimer = new StopwatchTimer(mClock, null, -7, null, mOnBatteryTimeBase);
mVideoOnNesting = 0;
- mVideoOnTimer = new StopwatchTimer(mClocks, null, -8, null, mOnBatteryTimeBase);
+ mVideoOnTimer = new StopwatchTimer(mClock, null, -8, null, mOnBatteryTimeBase);
mFlashlightOnNesting = 0;
- mFlashlightOnTimer = new StopwatchTimer(mClocks, null, -9, null, mOnBatteryTimeBase, in);
+ mFlashlightOnTimer = new StopwatchTimer(mClock, null, -9, null, mOnBatteryTimeBase, in);
mCameraOnNesting = 0;
- mCameraOnTimer = new StopwatchTimer(mClocks, null, -13, null, mOnBatteryTimeBase, in);
+ mCameraOnTimer = new StopwatchTimer(mClock, null, -13, null, mOnBatteryTimeBase, in);
mBluetoothScanNesting = 0;
- mBluetoothScanTimer = new StopwatchTimer(mClocks, null, -14, null, mOnBatteryTimeBase, in);
+ mBluetoothScanTimer = new StopwatchTimer(mClock, null, -14, null, mOnBatteryTimeBase, in);
mDischargeUnplugLevel = in.readInt();
mDischargePlugLevel = in.readInt();
mDischargeCurrentLevel = in.readInt();
@@ -16310,7 +16316,7 @@
for (int irpm = 0; irpm < NRPMS; irpm++) {
if (in.readInt() != 0) {
String rpmName = in.readString();
- SamplingTimer rpmt = new SamplingTimer(mClocks, mOnBatteryTimeBase, in);
+ SamplingTimer rpmt = new SamplingTimer(mClock, mOnBatteryTimeBase, in);
mRpmStats.put(rpmName, rpmt);
}
}
@@ -16319,7 +16325,7 @@
for (int irpm = 0; irpm < NSORPMS; irpm++) {
if (in.readInt() != 0) {
String rpmName = in.readString();
- SamplingTimer rpmt = new SamplingTimer(mClocks, mOnBatteryScreenOffTimeBase, in);
+ SamplingTimer rpmt = new SamplingTimer(mClock, mOnBatteryScreenOffTimeBase, in);
mScreenOffRpmStats.put(rpmName, rpmt);
}
}
@@ -16329,7 +16335,7 @@
for (int ikw = 0; ikw < NKW; ikw++) {
if (in.readInt() != 0) {
String wakelockName = in.readString();
- SamplingTimer kwlt = new SamplingTimer(mClocks, mOnBatteryScreenOffTimeBase, in);
+ SamplingTimer kwlt = new SamplingTimer(mClock, mOnBatteryScreenOffTimeBase, in);
mKernelWakelockStats.put(wakelockName, kwlt);
}
}
@@ -16339,7 +16345,7 @@
for (int iwr = 0; iwr < NWR; iwr++) {
if (in.readInt() != 0) {
String reasonName = in.readString();
- SamplingTimer timer = new SamplingTimer(mClocks, mOnBatteryTimeBase, in);
+ SamplingTimer timer = new SamplingTimer(mClock, mOnBatteryTimeBase, in);
mWakeupReasonStats.put(reasonName, timer);
}
}
@@ -16349,7 +16355,7 @@
for (int imt = 0; imt < nmt; imt++) {
if (in.readInt() != 0) {
Long bucket = in.readLong();
- SamplingTimer kmt = new SamplingTimer(mClocks, mOnBatteryTimeBase, in);
+ SamplingTimer kmt = new SamplingTimer(mClock, mOnBatteryTimeBase, in);
mKernelMemoryStats.put(bucket, kmt);
}
}
@@ -16369,8 +16375,8 @@
int numUids = in.readInt();
mUidStats.clear();
- final long elapsedRealtimeMs = mClocks.elapsedRealtime();
- final long uptimeMs = mClocks.uptimeMillis();
+ final long elapsedRealtimeMs = mClock.elapsedRealtime();
+ final long uptimeMs = mClock.uptimeMillis();
for (int i = 0; i < numUids; i++) {
int uid = in.readInt();
Uid u = new Uid(this, uid, elapsedRealtimeMs, uptimeMs);
@@ -16400,8 +16406,8 @@
// if we had originally pulled a time before the RTC was set.
getStartClockTime();
- final long uSecUptime = mClocks.uptimeMillis() * 1000;
- final long uSecRealtime = mClocks.elapsedRealtime() * 1000;
+ final long uSecUptime = mClock.uptimeMillis() * 1000;
+ final long uSecRealtime = mClock.elapsedRealtime() * 1000;
final long batteryRealtime = mOnBatteryTimeBase.getRealtime(uSecRealtime);
final long batteryScreenOffRealtime = mOnBatteryScreenOffTimeBase.getRealtime(uSecRealtime);
@@ -16757,7 +16763,7 @@
pw.print("Batched cpu time reads: ");
pw.println(mNumBatchedSingleUidCpuTimeReads);
pw.print("Batching Duration (min): ");
- pw.println((mClocks.uptimeMillis() - mCpuTimeReadsTrackingStartTimeMs) / (60 * 1000));
+ pw.println((mClock.uptimeMillis() - mCpuTimeReadsTrackingStartTimeMs) / (60 * 1000));
pw.print("All UID cpu time reads since the later of device start or stats reset: ");
pw.println(mNumAllUidCpuTimeReads);
pw.print("UIDs removed since the later of device start or stats reset: ");
diff --git a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
index 0038579..c0a22e0 100644
--- a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
+++ b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
@@ -256,7 +256,7 @@
private long elapsedRealtime() {
if (mStats instanceof BatteryStatsImpl) {
- return ((BatteryStatsImpl) mStats).mClocks.elapsedRealtime();
+ return ((BatteryStatsImpl) mStats).mClock.elapsedRealtime();
} else {
return SystemClock.elapsedRealtime();
}
@@ -264,7 +264,7 @@
private long uptimeMillis() {
if (mStats instanceof BatteryStatsImpl) {
- return ((BatteryStatsImpl) mStats).mClocks.uptimeMillis();
+ return ((BatteryStatsImpl) mStats).mClock.uptimeMillis();
} else {
return SystemClock.uptimeMillis();
}
@@ -272,7 +272,7 @@
private long currentTimeMillis() {
if (mStats instanceof BatteryStatsImpl) {
- return ((BatteryStatsImpl) mStats).mClocks.currentTimeMillis();
+ return ((BatteryStatsImpl) mStats).mClock.currentTimeMillis();
} else {
return System.currentTimeMillis();
}
diff --git a/core/java/com/android/internal/os/Clock.java b/core/java/com/android/internal/os/Clock.java
new file mode 100644
index 0000000..45007c4
--- /dev/null
+++ b/core/java/com/android/internal/os/Clock.java
@@ -0,0 +1,57 @@
+/*
+ * 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.os;
+
+import android.os.SystemClock;
+
+/**
+ * A wrapper for SystemClock, intended for mocking in unit tests.
+ */
+public abstract class Clock {
+ /** Elapsed Realtime, see SystemClock.elapsedRealtime() */
+ public long elapsedRealtime() {
+ throw new UnsupportedOperationException();
+ }
+
+ /** Uptime, see SystemClock.uptimeMillis() */
+ public long uptimeMillis() {
+ throw new UnsupportedOperationException();
+ }
+
+ /** Wall-clock time as per System.currentTimeMillis() */
+ public long currentTimeMillis() {
+ throw new UnsupportedOperationException();
+ }
+
+ public static final Clock SYSTEM_CLOCK = new Clock() {
+
+ @Override
+ public long elapsedRealtime() {
+ return SystemClock.elapsedRealtime();
+ }
+
+ @Override
+ public long uptimeMillis() {
+ return SystemClock.uptimeMillis();
+ }
+
+ @Override
+ public long currentTimeMillis() {
+ return System.currentTimeMillis();
+ }
+ };
+}
diff --git a/core/java/com/android/internal/os/KernelCpuProcStringReader.java b/core/java/com/android/internal/os/KernelCpuProcStringReader.java
index b3aec0c..b04fd47 100644
--- a/core/java/com/android/internal/os/KernelCpuProcStringReader.java
+++ b/core/java/com/android/internal/os/KernelCpuProcStringReader.java
@@ -17,7 +17,6 @@
package com.android.internal.os;
import android.os.StrictMode;
-import android.os.SystemClock;
import android.util.Slog;
import java.io.BufferedReader;
@@ -89,6 +88,7 @@
private int mErrors = 0;
private final Path mFile;
+ private final Clock mClock;
private char[] mBuf;
private int mSize;
private long mLastReadTime = 0;
@@ -97,7 +97,12 @@
private final ReentrantReadWriteLock.WriteLock mWriteLock = mLock.writeLock();
public KernelCpuProcStringReader(String file) {
+ this(file, Clock.SYSTEM_CLOCK);
+ }
+
+ public KernelCpuProcStringReader(String file, Clock clock) {
mFile = Paths.get(file);
+ mClock = clock;
}
/**
@@ -168,7 +173,7 @@
}
}
mSize = total;
- mLastReadTime = SystemClock.elapsedRealtime();
+ mLastReadTime = mClock.elapsedRealtime();
// ReentrantReadWriteLock allows lock downgrading.
mReadLock.lock();
return new ProcFileIterator(total);
@@ -186,7 +191,7 @@
}
private boolean dataValid() {
- return mSize > 0 && (SystemClock.elapsedRealtime() - mLastReadTime < FRESHNESS);
+ return mSize > 0 && (mClock.elapsedRealtime() - mLastReadTime < FRESHNESS);
}
/**
diff --git a/core/java/com/android/internal/os/KernelCpuUidTimeReader.java b/core/java/com/android/internal/os/KernelCpuUidTimeReader.java
index 50df166..faeb8fc 100644
--- a/core/java/com/android/internal/os/KernelCpuUidTimeReader.java
+++ b/core/java/com/android/internal/os/KernelCpuUidTimeReader.java
@@ -21,7 +21,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.StrictMode;
-import android.os.SystemClock;
import android.util.IntArray;
import android.util.Slog;
import android.util.SparseArray;
@@ -60,6 +59,7 @@
final boolean mThrottle;
protected boolean mBpfTimesAvailable;
final KernelCpuUidBpfMapReader mBpfReader;
+ private final Clock mClock;
private long mMinTimeBetweenRead = DEFAULT_MIN_TIME_BETWEEN_READ;
private long mLastReadTimeMs = 0;
@@ -76,15 +76,17 @@
void onUidCpuTime(int uid, T time);
}
- KernelCpuUidTimeReader(KernelCpuProcStringReader reader, @Nullable KernelCpuUidBpfMapReader bpfReader, boolean throttle) {
+ KernelCpuUidTimeReader(KernelCpuProcStringReader reader,
+ @Nullable KernelCpuUidBpfMapReader bpfReader, boolean throttle, Clock clock) {
mReader = reader;
mThrottle = throttle;
mBpfReader = bpfReader;
+ mClock = clock;
mBpfTimesAvailable = (mBpfReader != null);
}
- KernelCpuUidTimeReader(KernelCpuProcStringReader reader, boolean throttle) {
- this(reader, null, throttle);
+ KernelCpuUidTimeReader(KernelCpuProcStringReader reader, boolean throttle, Clock clock) {
+ this(reader, null, throttle, clock);
}
/**
@@ -104,17 +106,17 @@
*/
public void readDelta(boolean force, @Nullable Callback<T> cb) {
if (!mThrottle) {
- readDeltaImpl(cb);
+ readDeltaImpl(cb, force);
return;
}
- final long currTimeMs = SystemClock.elapsedRealtime();
+ final long currTimeMs = mClock.elapsedRealtime();
if (!force && currTimeMs < mLastReadTimeMs + mMinTimeBetweenRead) {
if (DEBUG) {
Slog.d(mTag, "Throttle readDelta");
}
return;
}
- readDeltaImpl(cb);
+ readDeltaImpl(cb, force);
mLastReadTimeMs = currTimeMs;
}
@@ -128,7 +130,7 @@
readAbsoluteImpl(cb);
return;
}
- final long currTimeMs = SystemClock.elapsedRealtime();
+ final long currTimeMs = mClock.elapsedRealtime();
if (currTimeMs < mLastReadTimeMs + mMinTimeBetweenRead) {
if (DEBUG) {
Slog.d(mTag, "Throttle readAbsolute");
@@ -139,7 +141,7 @@
mLastReadTimeMs = currTimeMs;
}
- abstract void readDeltaImpl(@Nullable Callback<T> cb);
+ abstract void readDeltaImpl(@Nullable Callback<T> cb, boolean forceRead);
abstract void readAbsoluteImpl(Callback<T> callback);
@@ -216,17 +218,22 @@
private final long[] mUsrSysTime = new long[2];
public KernelCpuUidUserSysTimeReader(boolean throttle) {
- super(KernelCpuProcStringReader.getUserSysTimeReaderInstance(), throttle);
+ this(throttle, Clock.SYSTEM_CLOCK);
+ }
+
+ public KernelCpuUidUserSysTimeReader(boolean throttle, Clock clock) {
+ super(KernelCpuProcStringReader.getUserSysTimeReaderInstance(), throttle, clock);
}
@VisibleForTesting
- public KernelCpuUidUserSysTimeReader(KernelCpuProcStringReader reader, boolean throttle) {
- super(reader, throttle);
+ public KernelCpuUidUserSysTimeReader(KernelCpuProcStringReader reader, boolean throttle,
+ Clock clock) {
+ super(reader, throttle, clock);
}
@Override
- void readDeltaImpl(@Nullable Callback<long[]> cb) {
- try (ProcFileIterator iter = mReader.open(!mThrottle)) {
+ void readDeltaImpl(@Nullable Callback<long[]> cb, boolean forceRead) {
+ try (ProcFileIterator iter = mReader.open(!mThrottle || forceRead)) {
if (iter == null) {
return;
}
@@ -348,14 +355,23 @@
private boolean mAllUidTimesAvailable = true;
public KernelCpuUidFreqTimeReader(boolean throttle) {
+ this(throttle, Clock.SYSTEM_CLOCK);
+ }
+
+ public KernelCpuUidFreqTimeReader(boolean throttle, Clock clock) {
this(UID_TIMES_PROC_FILE, KernelCpuProcStringReader.getFreqTimeReaderInstance(),
- KernelCpuUidBpfMapReader.getFreqTimeReaderInstance(), throttle);
+ KernelCpuUidBpfMapReader.getFreqTimeReaderInstance(), throttle, clock);
}
@VisibleForTesting
public KernelCpuUidFreqTimeReader(String procFile, KernelCpuProcStringReader reader,
KernelCpuUidBpfMapReader bpfReader, boolean throttle) {
- super(reader, bpfReader, throttle);
+ this(procFile, reader, bpfReader, throttle, Clock.SYSTEM_CLOCK);
+ }
+
+ private KernelCpuUidFreqTimeReader(String procFile, KernelCpuProcStringReader reader,
+ KernelCpuUidBpfMapReader bpfReader, boolean throttle, Clock clock) {
+ super(reader, bpfReader, throttle, clock);
mProcFilePath = Paths.get(procFile);
}
@@ -496,7 +512,7 @@
}
@Override
- void readDeltaImpl(@Nullable Callback<long[]> cb) {
+ void readDeltaImpl(@Nullable Callback<long[]> cb, boolean forceRead) {
if (mBpfTimesAvailable) {
try (BpfMapIterator iter = mBpfReader.open(!mThrottle)) {
if (checkPrecondition(iter)) {
@@ -628,13 +644,18 @@
private long[] mBuffer;
public KernelCpuUidActiveTimeReader(boolean throttle) {
+ this(throttle, Clock.SYSTEM_CLOCK);
+ }
+
+ public KernelCpuUidActiveTimeReader(boolean throttle, Clock clock) {
super(KernelCpuProcStringReader.getActiveTimeReaderInstance(),
- KernelCpuUidBpfMapReader.getActiveTimeReaderInstance(), throttle);
+ KernelCpuUidBpfMapReader.getActiveTimeReaderInstance(), throttle, clock);
}
@VisibleForTesting
- public KernelCpuUidActiveTimeReader(KernelCpuProcStringReader reader, KernelCpuUidBpfMapReader bpfReader, boolean throttle) {
- super(reader, bpfReader, throttle);
+ public KernelCpuUidActiveTimeReader(KernelCpuProcStringReader reader,
+ KernelCpuUidBpfMapReader bpfReader, boolean throttle) {
+ super(reader, bpfReader, throttle, Clock.SYSTEM_CLOCK);
}
private void processUidDelta(@Nullable Callback<Long> cb) {
@@ -655,7 +676,7 @@
}
@Override
- void readDeltaImpl(@Nullable Callback<Long> cb) {
+ void readDeltaImpl(@Nullable Callback<Long> cb, boolean forceRead) {
if (mBpfTimesAvailable) {
try (BpfMapIterator iter = mBpfReader.open(!mThrottle)) {
if (checkPrecondition(iter)) {
@@ -800,14 +821,18 @@
private long[] mDeltaTime;
public KernelCpuUidClusterTimeReader(boolean throttle) {
+ this(throttle, Clock.SYSTEM_CLOCK);
+ }
+
+ public KernelCpuUidClusterTimeReader(boolean throttle, Clock clock) {
super(KernelCpuProcStringReader.getClusterTimeReaderInstance(),
- KernelCpuUidBpfMapReader.getClusterTimeReaderInstance(), throttle);
+ KernelCpuUidBpfMapReader.getClusterTimeReaderInstance(), throttle, clock);
}
@VisibleForTesting
public KernelCpuUidClusterTimeReader(KernelCpuProcStringReader reader,
- KernelCpuUidBpfMapReader bpfReader, boolean throttle) {
- super(reader, bpfReader, throttle);
+ KernelCpuUidBpfMapReader bpfReader, boolean throttle) {
+ super(reader, bpfReader, throttle, Clock.SYSTEM_CLOCK);
}
void processUidDelta(@Nullable Callback<long[]> cb) {
@@ -838,7 +863,7 @@
}
@Override
- void readDeltaImpl(@Nullable Callback<long[]> cb) {
+ void readDeltaImpl(@Nullable Callback<long[]> cb, boolean forceRead) {
if (mBpfTimesAvailable) {
try (BpfMapIterator iter = mBpfReader.open(!mThrottle)) {
if (checkPrecondition(iter)) {
diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java
index 9ae3ab2..fdbbf97 100644
--- a/core/java/com/android/internal/view/IInputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java
@@ -16,15 +16,14 @@
package com.android.internal.view;
+import android.annotation.AnyThread;
+import android.annotation.BinderThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
-import android.os.RemoteException;
import android.os.Trace;
import android.util.Log;
import android.util.proto.ProtoOutputStream;
@@ -43,14 +42,12 @@
import android.view.inputmethod.SurroundingText;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.inputmethod.IBooleanResultCallback;
-import com.android.internal.inputmethod.ICharSequenceResultCallback;
-import com.android.internal.inputmethod.IExtractedTextResultCallback;
-import com.android.internal.inputmethod.IIntResultCallback;
-import com.android.internal.inputmethod.ISurroundingTextResultCallback;
+import com.android.internal.inputmethod.CallbackUtils;
import com.android.internal.inputmethod.ImeTracing;
+import com.android.internal.inputmethod.InputConnectionCommand;
+import com.android.internal.inputmethod.InputConnectionCommandType;
import com.android.internal.inputmethod.InputConnectionProtoDumper;
-import com.android.internal.os.SomeArgs;
+import com.android.internal.inputmethod.InputMethodDebug;
import java.lang.ref.WeakReference;
@@ -58,43 +55,16 @@
private static final String TAG = "IInputConnectionWrapper";
private static final boolean DEBUG = false;
- private static final int DO_GET_TEXT_AFTER_CURSOR = 10;
- private static final int DO_GET_TEXT_BEFORE_CURSOR = 20;
- private static final int DO_GET_SELECTED_TEXT = 25;
- private static final int DO_GET_CURSOR_CAPS_MODE = 30;
- private static final int DO_GET_EXTRACTED_TEXT = 40;
- private static final int DO_COMMIT_TEXT = 50;
- private static final int DO_COMMIT_COMPLETION = 55;
- private static final int DO_COMMIT_CORRECTION = 56;
- private static final int DO_SET_SELECTION = 57;
- private static final int DO_PERFORM_EDITOR_ACTION = 58;
- private static final int DO_PERFORM_CONTEXT_MENU_ACTION = 59;
- private static final int DO_SET_COMPOSING_TEXT = 60;
- private static final int DO_SET_COMPOSING_REGION = 63;
- private static final int DO_FINISH_COMPOSING_TEXT = 65;
- private static final int DO_SEND_KEY_EVENT = 70;
- private static final int DO_DELETE_SURROUNDING_TEXT = 80;
- private static final int DO_DELETE_SURROUNDING_TEXT_IN_CODE_POINTS = 81;
- private static final int DO_BEGIN_BATCH_EDIT = 90;
- private static final int DO_END_BATCH_EDIT = 95;
- private static final int DO_PERFORM_SPELL_CHECK = 110;
- private static final int DO_PERFORM_PRIVATE_COMMAND = 120;
- private static final int DO_CLEAR_META_KEY_STATES = 130;
- private static final int DO_REQUEST_CURSOR_UPDATES = 140;
- private static final int DO_CLOSE_CONNECTION = 150;
- private static final int DO_COMMIT_CONTENT = 160;
- private static final int DO_GET_SURROUNDING_TEXT = 41;
- private static final int DO_SET_IME_CONSUMES_INPUT = 170;
-
+ private static final int DO_EDIT = 10;
+ private static final int DO_CLOSE_CONNECTION = 20;
@GuardedBy("mLock")
@Nullable
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private InputConnection mInputConnection;
private Looper mMainLooper;
private Handler mH;
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+
private final Object mLock = new Object();
@GuardedBy("mLock")
private boolean mFinished = false;
@@ -150,7 +120,7 @@
// reportFinish() will take effect.
return;
}
- closeConnection();
+ dispatchMessage(mH.obtainMessage(DO_CLOSE_CONNECTION));
// Notify the app that the InputConnection was closed.
final View servedView = mServedView.get();
@@ -195,146 +165,33 @@
}
}
- public void getTextAfterCursor(int length, int flags, ICharSequenceResultCallback callback) {
- dispatchMessage(mH.obtainMessage(DO_GET_TEXT_AFTER_CURSOR, length, flags, callback));
- }
-
- public void getTextBeforeCursor(int length, int flags, ICharSequenceResultCallback callback) {
- dispatchMessage(mH.obtainMessage(DO_GET_TEXT_BEFORE_CURSOR, length, flags, callback));
- }
-
- public void getSelectedText(int flags, ICharSequenceResultCallback callback) {
- dispatchMessage(mH.obtainMessage(DO_GET_SELECTED_TEXT, flags, 0 /* unused */, callback));
+ @BinderThread
+ @Override
+ public void doEdit(@Nullable InputConnectionCommand command) {
+ if (command == null) {
+ // As long as everything is working as expected, we should never see any null object
+ // here. If we are seeing null object, it means that either the sender or
+ // InputConnectionCommand.CREATOR#createFromParcel() returned null for whatever
+ // unexpected reasons. Note that InputConnectionCommand.CREATOR#createFromParcel() does
+ // some data verifications. Hence failing to pass the verification is one of the
+ // reasons to see null here.
+ Log.w(TAG, "Ignoring invalid InputConnectionCommand.");
+ return;
+ }
+ if (DEBUG) {
+ Log.d(TAG, "incoming: " + InputMethodDebug.dumpInputConnectionCommand(command));
+ }
+ dispatchMessage(mH.obtainMessage(DO_EDIT, command));
}
/**
- * Dispatches the request for retrieving surrounding text.
- *
- * <p>See {@link InputConnection#getSurroundingText(int, int, int)}.
+ * Exposed for {@link InputMethodManager} to trigger
+ * {@link InputConnection#finishComposingText()}.
*/
- public void getSurroundingText(int beforeLength, int afterLength, int flags,
- ISurroundingTextResultCallback callback) {
- final SomeArgs args = SomeArgs.obtain();
- args.arg1 = beforeLength;
- args.arg2 = afterLength;
- args.arg3 = flags;
- args.arg4 = callback;
- dispatchMessage(mH.obtainMessage(DO_GET_SURROUNDING_TEXT, flags, 0 /* unused */, args));
- }
-
- public void getCursorCapsMode(int reqModes, IIntResultCallback callback) {
- dispatchMessage(
- mH.obtainMessage(DO_GET_CURSOR_CAPS_MODE, reqModes, 0 /* unused */, callback));
- }
-
- public void getExtractedText(ExtractedTextRequest request, int flags,
- IExtractedTextResultCallback callback) {
- final SomeArgs args = SomeArgs.obtain();
- args.arg1 = request;
- args.arg2 = callback;
- dispatchMessage(mH.obtainMessage(DO_GET_EXTRACTED_TEXT, flags, 0 /* unused */, args));
- }
-
- public void commitText(CharSequence text, int newCursorPosition) {
- dispatchMessage(obtainMessageIO(DO_COMMIT_TEXT, newCursorPosition, text));
- }
-
- public void commitCompletion(CompletionInfo text) {
- dispatchMessage(obtainMessageO(DO_COMMIT_COMPLETION, text));
- }
-
- public void commitCorrection(CorrectionInfo info) {
- dispatchMessage(obtainMessageO(DO_COMMIT_CORRECTION, info));
- }
-
- public void setSelection(int start, int end) {
- dispatchMessage(obtainMessageII(DO_SET_SELECTION, start, end));
- }
-
- public void performEditorAction(int id) {
- dispatchMessage(obtainMessageII(DO_PERFORM_EDITOR_ACTION, id, 0));
- }
-
- public void performContextMenuAction(int id) {
- dispatchMessage(obtainMessageII(DO_PERFORM_CONTEXT_MENU_ACTION, id, 0));
- }
-
- public void setComposingRegion(int start, int end) {
- dispatchMessage(obtainMessageII(DO_SET_COMPOSING_REGION, start, end));
- }
-
- public void setComposingText(CharSequence text, int newCursorPosition) {
- dispatchMessage(obtainMessageIO(DO_SET_COMPOSING_TEXT, newCursorPosition, text));
- }
-
+ @AnyThread
public void finishComposingText() {
- dispatchMessage(obtainMessage(DO_FINISH_COMPOSING_TEXT));
- }
-
- public void sendKeyEvent(KeyEvent event) {
- dispatchMessage(obtainMessageO(DO_SEND_KEY_EVENT, event));
- }
-
- public void clearMetaKeyStates(int states) {
- dispatchMessage(obtainMessageII(DO_CLEAR_META_KEY_STATES, states, 0));
- }
-
- public void deleteSurroundingText(int beforeLength, int afterLength) {
- dispatchMessage(obtainMessageII(DO_DELETE_SURROUNDING_TEXT,
- beforeLength, afterLength));
- }
-
- public void deleteSurroundingTextInCodePoints(int beforeLength, int afterLength) {
- dispatchMessage(obtainMessageII(DO_DELETE_SURROUNDING_TEXT_IN_CODE_POINTS,
- beforeLength, afterLength));
- }
-
- public void beginBatchEdit() {
- dispatchMessage(obtainMessage(DO_BEGIN_BATCH_EDIT));
- }
-
- public void endBatchEdit() {
- dispatchMessage(obtainMessage(DO_END_BATCH_EDIT));
- }
-
- /**
- * Dispatches the request for performing spell check.
- *
- * @see InputConnection#performSpellCheck()
- */
- public void performSpellCheck() {
- dispatchMessage(obtainMessage(DO_PERFORM_SPELL_CHECK));
- }
-
- public void performPrivateCommand(String action, Bundle data) {
- dispatchMessage(obtainMessageOO(DO_PERFORM_PRIVATE_COMMAND, action, data));
- }
-
- public void requestCursorUpdates(int cursorUpdateMode, IBooleanResultCallback callback) {
- dispatchMessage(mH.obtainMessage(DO_REQUEST_CURSOR_UPDATES, cursorUpdateMode,
- 0 /* unused */, callback));
- }
-
- public void closeConnection() {
- dispatchMessage(obtainMessage(DO_CLOSE_CONNECTION));
- }
-
- public void commitContent(InputContentInfo inputContentInfo, int flags, Bundle opts,
- IBooleanResultCallback callback) {
- final SomeArgs args = SomeArgs.obtain();
- args.arg1 = inputContentInfo;
- args.arg2 = opts;
- args.arg3 = callback;
- dispatchMessage(mH.obtainMessage(DO_COMMIT_CONTENT, flags, 0 /* unused */, args));
- }
-
- /**
- * Dispatches the request for setting ime consumes input.
- *
- * <p>See {@link InputConnection#setImeConsumesInput(boolean)}.
- */
- public void setImeConsumesInput(boolean imeConsumesInput) {
- dispatchMessage(obtainMessageB(DO_SET_IME_CONSUMES_INPUT, imeConsumesInput));
+ dispatchMessage(mH.obtainMessage(DO_EDIT, InputConnectionCommand.create(
+ InputConnectionCommandType.FINISH_COMPOSING_TEXT)));
}
void dispatchMessage(Message msg) {
@@ -350,108 +207,131 @@
mH.sendMessage(msg);
}
- void executeMessage(Message msg) {
- byte[] icProto;
+ private void executeMessage(Message msg) {
switch (msg.what) {
- case DO_GET_TEXT_AFTER_CURSOR: {
+ case DO_EDIT:
+ doEditMain((InputConnectionCommand) msg.obj);
+ break;
+ case DO_CLOSE_CONNECTION:
+ // Note that we do not need to worry about race condition here, because 1) mFinished
+ // is updated only inside this block, and 2) the code here is running on a Handler
+ // hence we assume multiple DO_CLOSE_CONNECTION messages will not be handled at the
+ // same time.
+ if (isFinished()) {
+ return;
+ }
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#closeConnection");
+ try {
+ InputConnection ic = getInputConnection();
+ // Note we do NOT check isActive() here, because this is safe
+ // for an IME to call at any time, and we need to allow it
+ // through to clean up our state after the IME has switched to
+ // another client.
+ if (ic == null) {
+ return;
+ }
+ @MissingMethodFlags final int missingMethods =
+ InputConnectionInspector.getMissingMethodFlags(ic);
+ if ((missingMethods & MissingMethodFlags.CLOSE_CONNECTION) == 0) {
+ ic.closeConnection();
+ }
+ } finally {
+ synchronized (mLock) {
+ mInputConnection = null;
+ mFinished = true;
+ }
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+ }
+ break;
+ }
+ }
+
+ private void doEditMain(@NonNull InputConnectionCommand command) {
+ if (DEBUG) {
+ Log.d(TAG, "handling: " + InputMethodDebug.dumpInputConnectionCommand(command));
+ }
+ byte[] icProto;
+ switch (command.mCommandType) {
+ case InputConnectionCommandType.GET_TEXT_AFTER_CURSOR: {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getTextAfterCursor");
try {
- final ICharSequenceResultCallback callback =
- (ICharSequenceResultCallback) msg.obj;
+ final int n = command.mIntArg0;
+ final int flags = command.mFlags;
final InputConnection ic = getInputConnection();
final CharSequence result;
if (ic == null || !isActive()) {
Log.w(TAG, "getTextAfterCursor on inactive InputConnection");
result = null;
} else {
- result = ic.getTextAfterCursor(msg.arg1, msg.arg2);
+ result = ic.getTextAfterCursor(n, flags);
}
if (ImeTracing.getInstance().isEnabled()) {
- icProto = InputConnectionProtoDumper.buildGetTextAfterCursorProto(msg.arg1,
- msg.arg2, result);
+ icProto = InputConnectionProtoDumper.buildGetTextAfterCursorProto(n, flags,
+ result);
ImeTracing.getInstance().triggerClientDump(
TAG + "#getTextAfterCursor", mParentInputMethodManager, icProto);
}
- try {
- callback.onResult(result);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to return the result to getTextAfterCursor()."
- + " result=" + result, e);
- }
+ CallbackUtils.onResult(command, result, TAG);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
return;
}
- case DO_GET_TEXT_BEFORE_CURSOR: {
+ case InputConnectionCommandType.GET_TEXT_BEFORE_CURSOR: {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getTextBeforeCursor");
try {
- final ICharSequenceResultCallback callback =
- (ICharSequenceResultCallback) msg.obj;
+ final int n = command.mIntArg0;
+ final int flags = command.mFlags;
final InputConnection ic = getInputConnection();
final CharSequence result;
if (ic == null || !isActive()) {
Log.w(TAG, "getTextBeforeCursor on inactive InputConnection");
result = null;
} else {
- result = ic.getTextBeforeCursor(msg.arg1, msg.arg2);
+ result = ic.getTextBeforeCursor(n, flags);
}
if (ImeTracing.getInstance().isEnabled()) {
- icProto = InputConnectionProtoDumper.buildGetTextBeforeCursorProto(msg.arg1,
- msg.arg2, result);
+ icProto = InputConnectionProtoDumper.buildGetTextBeforeCursorProto(n, flags,
+ result);
ImeTracing.getInstance().triggerClientDump(
TAG + "#getTextBeforeCursor", mParentInputMethodManager, icProto);
}
- try {
- callback.onResult(result);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to return the result to getTextBeforeCursor()."
- + " result=" + result, e);
- }
+ CallbackUtils.onResult(command, result, TAG);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
return;
}
- case DO_GET_SELECTED_TEXT: {
+ case InputConnectionCommandType.GET_SELECTED_TEXT: {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getSelectedText");
try {
- final ICharSequenceResultCallback callback =
- (ICharSequenceResultCallback) msg.obj;
+ final int flags = command.mFlags;
final InputConnection ic = getInputConnection();
final CharSequence result;
if (ic == null || !isActive()) {
Log.w(TAG, "getSelectedText on inactive InputConnection");
result = null;
} else {
- result = ic.getSelectedText(msg.arg1);
+ result = ic.getSelectedText(flags);
}
if (ImeTracing.getInstance().isEnabled()) {
- icProto = InputConnectionProtoDumper.buildGetSelectedTextProto(msg.arg1,
+ icProto = InputConnectionProtoDumper.buildGetSelectedTextProto(flags,
result);
ImeTracing.getInstance().triggerClientDump(
TAG + "#getSelectedText", mParentInputMethodManager, icProto);
}
- try {
- callback.onResult(result);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to return the result to getSelectedText()."
- + " result=" + result, e);
- }
+ CallbackUtils.onResult(command, result, TAG);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
return;
}
- case DO_GET_SURROUNDING_TEXT: {
- final SomeArgs args = (SomeArgs) msg.obj;
+ case InputConnectionCommandType.GET_SURROUNDING_TEXT: {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getSurroundingText");
try {
- int beforeLength = (int) args.arg1;
- int afterLength = (int) args.arg2;
- int flags = (int) args.arg3;
- final ISurroundingTextResultCallback callback =
- (ISurroundingTextResultCallback) args.arg4;
+ final int beforeLength = command.mIntArg0;
+ final int afterLength = command.mIntArg1;
+ final int flags = command.mFlags;
final InputConnection ic = getInputConnection();
final SurroundingText result;
if (ic == null || !isActive()) {
@@ -466,193 +346,186 @@
ImeTracing.getInstance().triggerClientDump(
TAG + "#getSurroundingText", mParentInputMethodManager, icProto);
}
- try {
- callback.onResult(result);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to return the result to getSurroundingText()."
- + " result=" + result, e);
- }
+ CallbackUtils.onResult(command, result, TAG);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
- args.recycle();
}
return;
}
- case DO_GET_CURSOR_CAPS_MODE: {
+ case InputConnectionCommandType.GET_CURSOR_CAPS_MODE: {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getCursorCapsMode");
try {
- final IIntResultCallback callback = (IIntResultCallback) msg.obj;
+ final int reqModes = command.mIntArg0;
final InputConnection ic = getInputConnection();
final int result;
if (ic == null || !isActive()) {
Log.w(TAG, "getCursorCapsMode on inactive InputConnection");
result = 0;
} else {
- result = ic.getCursorCapsMode(msg.arg1);
+ result = ic.getCursorCapsMode(reqModes);
}
if (ImeTracing.getInstance().isEnabled()) {
- icProto = InputConnectionProtoDumper.buildGetCursorCapsModeProto(msg.arg1,
+ icProto = InputConnectionProtoDumper.buildGetCursorCapsModeProto(reqModes,
result);
ImeTracing.getInstance().triggerClientDump(
TAG + "#getCursorCapsMode", mParentInputMethodManager, icProto);
}
- try {
- callback.onResult(result);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to return the result to getCursorCapsMode()."
- + " result=" + result, e);
- }
+ CallbackUtils.onResult(command, result, TAG);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
return;
}
- case DO_GET_EXTRACTED_TEXT: {
- final SomeArgs args = (SomeArgs) msg.obj;
+ case InputConnectionCommandType.GET_EXTRACTED_TEXT: {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getExtractedText");
try {
- final ExtractedTextRequest request = (ExtractedTextRequest) args.arg1;
- final IExtractedTextResultCallback callback =
- (IExtractedTextResultCallback) args.arg2;
+ final ExtractedTextRequest request = (ExtractedTextRequest) command.mParcelable;
+ final int flags = command.mFlags;
final InputConnection ic = getInputConnection();
final ExtractedText result;
if (ic == null || !isActive()) {
Log.w(TAG, "getExtractedText on inactive InputConnection");
result = null;
} else {
- result = ic.getExtractedText(request, msg.arg1);
+ result = ic.getExtractedText(request, flags);
}
if (ImeTracing.getInstance().isEnabled()) {
icProto = InputConnectionProtoDumper.buildGetExtractedTextProto(request,
- msg.arg1, result);
+ flags, result);
ImeTracing.getInstance().triggerClientDump(
TAG + "#getExtractedText", mParentInputMethodManager, icProto);
}
- try {
- callback.onResult(result);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to return the result to getExtractedText()."
- + " result=" + result, e);
- }
+ CallbackUtils.onResult(command, result, TAG);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
- args.recycle();
}
return;
}
- case DO_COMMIT_TEXT: {
+ case InputConnectionCommandType.COMMIT_TEXT: {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#commitText");
try {
+ final CharSequence text = command.mCharSequence;
+ final int newCursorPosition = command.mIntArg0;
InputConnection ic = getInputConnection();
if (ic == null || !isActive()) {
Log.w(TAG, "commitText on inactive InputConnection");
return;
}
- ic.commitText((CharSequence) msg.obj, msg.arg1);
+ ic.commitText(text, newCursorPosition);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
return;
}
- case DO_SET_SELECTION: {
+ case InputConnectionCommandType.SET_SELECTION: {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#setSelection");
try {
+ final int start = command.mIntArg0;
+ final int end = command.mIntArg1;
InputConnection ic = getInputConnection();
if (ic == null || !isActive()) {
Log.w(TAG, "setSelection on inactive InputConnection");
return;
}
- ic.setSelection(msg.arg1, msg.arg2);
+ ic.setSelection(start, end);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
return;
}
- case DO_PERFORM_EDITOR_ACTION: {
+ case InputConnectionCommandType.PERFORM_EDITOR_ACTION: {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#performEditorAction");
try {
+ final int editorAction = command.mIntArg0;
InputConnection ic = getInputConnection();
if (ic == null || !isActive()) {
Log.w(TAG, "performEditorAction on inactive InputConnection");
return;
}
- ic.performEditorAction(msg.arg1);
+ ic.performEditorAction(editorAction);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
return;
}
- case DO_PERFORM_CONTEXT_MENU_ACTION: {
+ case InputConnectionCommandType.PERFORM_CONTEXT_MENU_ACTION: {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#performContextMenuAction");
try {
+ final int id = command.mIntArg0;
InputConnection ic = getInputConnection();
if (ic == null || !isActive()) {
Log.w(TAG, "performContextMenuAction on inactive InputConnection");
return;
}
- ic.performContextMenuAction(msg.arg1);
+ ic.performContextMenuAction(id);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
return;
}
- case DO_COMMIT_COMPLETION: {
+ case InputConnectionCommandType.COMMIT_COMPLETION: {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#commitCompletion");
try {
+ final CompletionInfo text = (CompletionInfo) command.mParcelable;
InputConnection ic = getInputConnection();
if (ic == null || !isActive()) {
Log.w(TAG, "commitCompletion on inactive InputConnection");
return;
}
- ic.commitCompletion((CompletionInfo) msg.obj);
+ ic.commitCompletion(text);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
return;
}
- case DO_COMMIT_CORRECTION: {
+ case InputConnectionCommandType.COMMIT_CORRECTION: {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#commitCorrection");
try {
+ final CorrectionInfo correctionInfo = (CorrectionInfo) command.mParcelable;
InputConnection ic = getInputConnection();
if (ic == null || !isActive()) {
Log.w(TAG, "commitCorrection on inactive InputConnection");
return;
}
- ic.commitCorrection((CorrectionInfo) msg.obj);
+ ic.commitCorrection(correctionInfo);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
return;
}
- case DO_SET_COMPOSING_TEXT: {
+ case InputConnectionCommandType.SET_COMPOSING_TEXT: {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#setComposingText");
try {
+ final CharSequence text = command.mCharSequence;
+ final int newCursorPosition = command.mIntArg0;
InputConnection ic = getInputConnection();
if (ic == null || !isActive()) {
Log.w(TAG, "setComposingText on inactive InputConnection");
return;
}
- ic.setComposingText((CharSequence) msg.obj, msg.arg1);
+ ic.setComposingText(text, newCursorPosition);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
return;
}
- case DO_SET_COMPOSING_REGION: {
+ case InputConnectionCommandType.SET_COMPOSING_REGION: {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#setComposingRegion");
try {
+ final int start = command.mIntArg0;
+ final int end = command.mIntArg1;
InputConnection ic = getInputConnection();
if (ic == null || !isActive()) {
Log.w(TAG, "setComposingRegion on inactive InputConnection");
return;
}
- ic.setComposingRegion(msg.arg1, msg.arg2);
+ ic.setComposingRegion(start, end);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
return;
}
- case DO_FINISH_COMPOSING_TEXT: {
+ case InputConnectionCommandType.FINISH_COMPOSING_TEXT: {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#finishComposingText");
try {
if (isFinished()) {
@@ -678,64 +551,70 @@
}
return;
}
- case DO_SEND_KEY_EVENT: {
+ case InputConnectionCommandType.SEND_KEY_EVENT: {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#sendKeyEvent");
try {
+ final KeyEvent event = (KeyEvent) command.mParcelable;
InputConnection ic = getInputConnection();
if (ic == null || !isActive()) {
Log.w(TAG, "sendKeyEvent on inactive InputConnection");
return;
}
- ic.sendKeyEvent((KeyEvent) msg.obj);
+ ic.sendKeyEvent(event);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
return;
}
- case DO_CLEAR_META_KEY_STATES: {
+ case InputConnectionCommandType.CLEAR_META_KEY_STATES: {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#clearMetaKeyStates");
try {
+ final int states = command.mIntArg0;
InputConnection ic = getInputConnection();
if (ic == null || !isActive()) {
Log.w(TAG, "clearMetaKeyStates on inactive InputConnection");
return;
}
- ic.clearMetaKeyStates(msg.arg1);
+ ic.clearMetaKeyStates(states);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
return;
}
- case DO_DELETE_SURROUNDING_TEXT: {
+ case InputConnectionCommandType.DELETE_SURROUNDING_TEXT: {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#deleteSurroundingText");
try {
+ final int beforeLength = command.mIntArg0;
+ final int afterLength = command.mIntArg1;
InputConnection ic = getInputConnection();
if (ic == null || !isActive()) {
Log.w(TAG, "deleteSurroundingText on inactive InputConnection");
return;
}
- ic.deleteSurroundingText(msg.arg1, msg.arg2);
+ ic.deleteSurroundingText(beforeLength, afterLength);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
return;
}
- case DO_DELETE_SURROUNDING_TEXT_IN_CODE_POINTS: {
+ case InputConnectionCommandType.DELETE_SURROUNDING_TEXT_IN_CODE_POINTS: {
Trace.traceBegin(Trace.TRACE_TAG_INPUT,
"InputConnection#deleteSurroundingTextInCodePoints");
try {
+ final int beforeLength = command.mIntArg0;
+ final int afterLength = command.mIntArg1;
InputConnection ic = getInputConnection();
if (ic == null || !isActive()) {
Log.w(TAG, "deleteSurroundingTextInCodePoints on inactive InputConnection");
return;
}
- ic.deleteSurroundingTextInCodePoints(msg.arg1, msg.arg2);
+ ic.deleteSurroundingTextInCodePoints(beforeLength, afterLength);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
return;
}
- case DO_BEGIN_BATCH_EDIT: {
+ case InputConnectionCommandType.BEGIN_BATCH_EDIT: {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#beginBatchEdit");
try {
InputConnection ic = getInputConnection();
@@ -749,7 +628,7 @@
}
return;
}
- case DO_END_BATCH_EDIT: {
+ case InputConnectionCommandType.END_BATCH_EDIT: {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#endBatchEdit");
try {
InputConnection ic = getInputConnection();
@@ -763,7 +642,7 @@
}
return;
}
- case DO_PERFORM_SPELL_CHECK: {
+ case InputConnectionCommandType.PERFORM_SPELL_CHECK: {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#performSpellCheck");
try {
InputConnection ic = getInputConnection();
@@ -777,12 +656,11 @@
}
return;
}
- case DO_PERFORM_PRIVATE_COMMAND: {
- final SomeArgs args = (SomeArgs) msg.obj;
+ case InputConnectionCommandType.PERFORM_PRIVATE_COMMAND: {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#performPrivateCommand");
try {
- final String action = (String) args.arg1;
- final Bundle data = (Bundle) args.arg2;
+ final String action = command.mString;
+ final Bundle data = command.mBundle;
InputConnection ic = getInputConnection();
if (ic == null || !isActive()) {
Log.w(TAG, "performPrivateCommand on inactive InputConnection");
@@ -791,142 +669,71 @@
ic.performPrivateCommand(action, data);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
- args.recycle();
}
return;
}
- case DO_REQUEST_CURSOR_UPDATES: {
+ case InputConnectionCommandType.REQUEST_CURSOR_UPDATES: {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#requestCursorUpdates");
try {
- final IBooleanResultCallback callback = (IBooleanResultCallback) msg.obj;
+ final int cursorUpdateMode = command.mIntArg0;
final InputConnection ic = getInputConnection();
final boolean result;
if (ic == null || !isActive()) {
Log.w(TAG, "requestCursorAnchorInfo on inactive InputConnection");
result = false;
} else {
- result = ic.requestCursorUpdates(msg.arg1);
+ result = ic.requestCursorUpdates(cursorUpdateMode);
}
- try {
- callback.onResult(result);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to return the result to requestCursorUpdates()."
- + " result=" + result, e);
- }
+ CallbackUtils.onResult(command, result, TAG);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
return;
}
- case DO_CLOSE_CONNECTION: {
- // Note that we do not need to worry about race condition here, because 1) mFinished
- // is updated only inside this block, and 2) the code here is running on a Handler
- // hence we assume multiple DO_CLOSE_CONNECTION messages will not be handled at the
- // same time.
- if (isFinished()) {
- return;
- }
- Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#closeConnection");
- try {
- InputConnection ic = getInputConnection();
- // Note we do NOT check isActive() here, because this is safe
- // for an IME to call at any time, and we need to allow it
- // through to clean up our state after the IME has switched to
- // another client.
- if (ic == null) {
- return;
- }
- @MissingMethodFlags
- final int missingMethods = InputConnectionInspector.getMissingMethodFlags(ic);
- if ((missingMethods & MissingMethodFlags.CLOSE_CONNECTION) == 0) {
- ic.closeConnection();
- }
- } finally {
- synchronized (mLock) {
- mInputConnection = null;
- mFinished = true;
- }
- Trace.traceEnd(Trace.TRACE_TAG_INPUT);
- }
- return;
- }
- case DO_COMMIT_CONTENT: {
- final int flags = msg.arg1;
- SomeArgs args = (SomeArgs) msg.obj;
+ case InputConnectionCommandType.COMMIT_CONTENT: {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#commitContent");
try {
- final IBooleanResultCallback callback = (IBooleanResultCallback) args.arg3;
+ final InputContentInfo inputContentInfo =
+ (InputContentInfo) command.mParcelable;
+ final int flags = command.mFlags;
+ final Bundle opts = command.mBundle;
final InputConnection ic = getInputConnection();
final boolean result;
if (ic == null || !isActive()) {
Log.w(TAG, "commitContent on inactive InputConnection");
result = false;
} else {
- final InputContentInfo inputContentInfo = (InputContentInfo) args.arg1;
if (inputContentInfo == null || !inputContentInfo.validate()) {
Log.w(TAG, "commitContent with invalid inputContentInfo="
+ inputContentInfo);
result = false;
} else {
- result = ic.commitContent(inputContentInfo, flags, (Bundle) args.arg2);
+ result = ic.commitContent(inputContentInfo, flags, opts);
}
}
- try {
- callback.onResult(result);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to return the result to commitContent()."
- + " result=" + result, e);
- }
+ CallbackUtils.onResult(command, result, TAG);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
- args.recycle();
}
return;
}
- case DO_SET_IME_CONSUMES_INPUT: {
+ case InputConnectionCommandType.SET_IME_CONSUMES_INPUT: {
Trace.traceBegin(Trace.TRACE_TAG_INPUT,
"InputConnection#setImeConsumesInput");
try {
+ final boolean imeConsumesInput = (command.mIntArg0 != 0);
InputConnection ic = getInputConnection();
if (ic == null || !isActive()) {
Log.w(TAG,
"setImeConsumesInput on inactive InputConnection");
return;
}
- ic.setImeConsumesInput(msg.arg1 == 1);
+ ic.setImeConsumesInput(imeConsumesInput);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
return;
}
}
- Log.w(TAG, "Unhandled message code: " + msg.what);
- }
-
- Message obtainMessage(int what) {
- return mH.obtainMessage(what);
- }
-
- Message obtainMessageII(int what, int arg1, int arg2) {
- return mH.obtainMessage(what, arg1, arg2);
- }
-
- Message obtainMessageO(int what, Object arg1) {
- return mH.obtainMessage(what, 0, 0, arg1);
- }
-
- Message obtainMessageIO(int what, int arg1, Object arg2) {
- return mH.obtainMessage(what, arg1, 0, arg2);
- }
-
- Message obtainMessageOO(int what, Object arg1, Object arg2) {
- final SomeArgs args = SomeArgs.obtain();
- args.arg1 = arg1;
- args.arg2 = arg2;
- return mH.obtainMessage(what, 0, 0, args);
- }
-
- Message obtainMessageB(int what, boolean arg1) {
- return mH.obtainMessage(what, arg1 ? 1 : 0, 0);
}
}
diff --git a/core/java/com/android/internal/view/IInputContext.aidl b/core/java/com/android/internal/view/IInputContext.aidl
index dd42c40e..095c0b4 100644
--- a/core/java/com/android/internal/view/IInputContext.aidl
+++ b/core/java/com/android/internal/view/IInputContext.aidl
@@ -16,76 +16,13 @@
package com.android.internal.view;
-import android.os.Bundle;
-import android.view.KeyEvent;
-import android.view.inputmethod.CompletionInfo;
-import android.view.inputmethod.CorrectionInfo;
-import android.view.inputmethod.ExtractedTextRequest;
-import android.view.inputmethod.InputContentInfo;
-
-import com.android.internal.inputmethod.IBooleanResultCallback;
-import com.android.internal.inputmethod.ICharSequenceResultCallback;
-import com.android.internal.inputmethod.IExtractedTextResultCallback;
-import com.android.internal.inputmethod.IIntResultCallback;
-import com.android.internal.inputmethod.ISurroundingTextResultCallback;
+import com.android.internal.inputmethod.InputConnectionCommand;
/**
* Interface from an input method to the application, allowing it to perform
* edits on the current input field and other interactions with the application.
* {@hide}
*/
- oneway interface IInputContext {
- void getTextBeforeCursor(int length, int flags, ICharSequenceResultCallback callback);
-
- void getTextAfterCursor(int length, int flags, ICharSequenceResultCallback callback);
-
- void getCursorCapsMode(int reqModes, IIntResultCallback callback);
-
- void getExtractedText(in ExtractedTextRequest request, int flags,
- IExtractedTextResultCallback callback);
-
- void deleteSurroundingText(int beforeLength, int afterLength);
- void deleteSurroundingTextInCodePoints(int beforeLength, int afterLength);
-
- void setComposingText(CharSequence text, int newCursorPosition);
-
- void finishComposingText();
-
- void commitText(CharSequence text, int newCursorPosition);
-
- void commitCompletion(in CompletionInfo completion);
-
- void commitCorrection(in CorrectionInfo correction);
-
- void setSelection(int start, int end);
-
- void performEditorAction(int actionCode);
-
- void performContextMenuAction(int id);
-
- void beginBatchEdit();
-
- void endBatchEdit();
-
- void sendKeyEvent(in KeyEvent event);
-
- void clearMetaKeyStates(int states);
-
- void performSpellCheck();
-
- void performPrivateCommand(String action, in Bundle data);
-
- void setComposingRegion(int start, int end);
-
- void getSelectedText(int flags, ICharSequenceResultCallback callback);
-
- void requestCursorUpdates(int cursorUpdateMode, IBooleanResultCallback callback);
-
- void commitContent(in InputContentInfo inputContentInfo, int flags, in Bundle opts,
- IBooleanResultCallback callback);
-
- void getSurroundingText(int beforeLength, int afterLength, int flags,
- ISurroundingTextResultCallback callback);
-
- void setImeConsumesInput(boolean imeConsumesInput);
+oneway interface IInputContext {
+ void doEdit(in InputConnectionCommand command);
}
diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java
index fd6038f..4fc135c 100644
--- a/core/java/com/android/internal/widget/PointerLocationView.java
+++ b/core/java/com/android/internal/widget/PointerLocationView.java
@@ -19,6 +19,7 @@
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.graphics.Canvas;
+import android.graphics.Insets;
import android.graphics.Paint;
import android.graphics.Paint.FontMetricsInt;
import android.graphics.Path;
@@ -136,6 +137,7 @@
private final FontMetricsInt mTextMetrics = new FontMetricsInt();
private int mHeaderBottom;
private int mHeaderPaddingTop = 0;
+ private Insets mWaterfallInsets = Insets.NONE;
@UnsupportedAppUsage
private boolean mCurDown;
@UnsupportedAppUsage
@@ -229,8 +231,10 @@
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
if (insets.getDisplayCutout() != null) {
mHeaderPaddingTop = insets.getDisplayCutout().getSafeInsetTop();
+ mWaterfallInsets = insets.getDisplayCutout().getWaterfallInsets();
} else {
mHeaderPaddingTop = 0;
+ mWaterfallInsets = Insets.NONE;
}
return super.onApplyWindowInsets(insets);
}
@@ -266,11 +270,6 @@
@Override
protected void onDraw(Canvas canvas) {
- final int w = getWidth();
- final int itemW = w/7;
- final int base = mHeaderPaddingTop-mTextMetrics.ascent+1;
- final int bottom = mHeaderBottom;
-
final int NP = mPointers.size();
if (!mSystemGestureExclusion.isEmpty()) {
@@ -286,71 +285,7 @@
}
// Labels
- if (mActivePointerId >= 0) {
- final PointerState ps = mPointers.get(mActivePointerId);
-
- canvas.drawRect(0, mHeaderPaddingTop, itemW-1, bottom,mTextBackgroundPaint);
- canvas.drawText(mText.clear()
- .append("P: ").append(mCurNumPointers)
- .append(" / ").append(mMaxNumPointers)
- .toString(), 1, base, mTextPaint);
-
- final int N = ps.mTraceCount;
- if ((mCurDown && ps.mCurDown) || N == 0) {
- canvas.drawRect(itemW, mHeaderPaddingTop, (itemW * 2) - 1, bottom,
- mTextBackgroundPaint);
- canvas.drawText(mText.clear()
- .append("X: ").append(ps.mCoords.x, 1)
- .toString(), 1 + itemW, base, mTextPaint);
- canvas.drawRect(itemW * 2, mHeaderPaddingTop, (itemW * 3) - 1, bottom,
- mTextBackgroundPaint);
- canvas.drawText(mText.clear()
- .append("Y: ").append(ps.mCoords.y, 1)
- .toString(), 1 + itemW * 2, base, mTextPaint);
- } else {
- float dx = ps.mTraceX[N - 1] - ps.mTraceX[0];
- float dy = ps.mTraceY[N - 1] - ps.mTraceY[0];
- canvas.drawRect(itemW, mHeaderPaddingTop, (itemW * 2) - 1, bottom,
- Math.abs(dx) < mVC.getScaledTouchSlop()
- ? mTextBackgroundPaint : mTextLevelPaint);
- canvas.drawText(mText.clear()
- .append("dX: ").append(dx, 1)
- .toString(), 1 + itemW, base, mTextPaint);
- canvas.drawRect(itemW * 2, mHeaderPaddingTop, (itemW * 3) - 1, bottom,
- Math.abs(dy) < mVC.getScaledTouchSlop()
- ? mTextBackgroundPaint : mTextLevelPaint);
- canvas.drawText(mText.clear()
- .append("dY: ").append(dy, 1)
- .toString(), 1 + itemW * 2, base, mTextPaint);
- }
-
- canvas.drawRect(itemW * 3, mHeaderPaddingTop, (itemW * 4) - 1, bottom,
- mTextBackgroundPaint);
- canvas.drawText(mText.clear()
- .append("Xv: ").append(ps.mXVelocity, 3)
- .toString(), 1 + itemW * 3, base, mTextPaint);
-
- canvas.drawRect(itemW * 4, mHeaderPaddingTop, (itemW * 5) - 1, bottom,
- mTextBackgroundPaint);
- canvas.drawText(mText.clear()
- .append("Yv: ").append(ps.mYVelocity, 3)
- .toString(), 1 + itemW * 4, base, mTextPaint);
-
- canvas.drawRect(itemW * 5, mHeaderPaddingTop, (itemW * 6) - 1, bottom,
- mTextBackgroundPaint);
- canvas.drawRect(itemW * 5, mHeaderPaddingTop,
- (itemW * 5) + (ps.mCoords.pressure * itemW) - 1, bottom, mTextLevelPaint);
- canvas.drawText(mText.clear()
- .append("Prs: ").append(ps.mCoords.pressure, 2)
- .toString(), 1 + itemW * 5, base, mTextPaint);
-
- canvas.drawRect(itemW * 6, mHeaderPaddingTop, w, bottom, mTextBackgroundPaint);
- canvas.drawRect(itemW * 6, mHeaderPaddingTop,
- (itemW * 6) + (ps.mCoords.size * itemW) - 1, bottom, mTextLevelPaint);
- canvas.drawText(mText.clear()
- .append("Size: ").append(ps.mCoords.size, 2)
- .toString(), 1 + itemW * 6, base, mTextPaint);
- }
+ drawLabels(canvas);
// Pointer trace.
for (int p = 0; p < NP; p++) {
@@ -463,6 +398,84 @@
}
}
+ private void drawLabels(Canvas canvas) {
+ if (mActivePointerId < 0) {
+ return;
+ }
+
+ final int w = getWidth() - mWaterfallInsets.left - mWaterfallInsets.right;
+ final int itemW = w / 7;
+ final int base = mHeaderPaddingTop - mTextMetrics.ascent + 1;
+ final int bottom = mHeaderBottom;
+
+ canvas.save();
+ canvas.translate(mWaterfallInsets.left, 0);
+ final PointerState ps = mPointers.get(mActivePointerId);
+
+ canvas.drawRect(0, mHeaderPaddingTop, itemW - 1, bottom, mTextBackgroundPaint);
+ canvas.drawText(mText.clear()
+ .append("P: ").append(mCurNumPointers)
+ .append(" / ").append(mMaxNumPointers)
+ .toString(), 1, base, mTextPaint);
+
+ final int count = ps.mTraceCount;
+ if ((mCurDown && ps.mCurDown) || count == 0) {
+ canvas.drawRect(itemW, mHeaderPaddingTop, (itemW * 2) - 1, bottom,
+ mTextBackgroundPaint);
+ canvas.drawText(mText.clear()
+ .append("X: ").append(ps.mCoords.x, 1)
+ .toString(), 1 + itemW, base, mTextPaint);
+ canvas.drawRect(itemW * 2, mHeaderPaddingTop, (itemW * 3) - 1, bottom,
+ mTextBackgroundPaint);
+ canvas.drawText(mText.clear()
+ .append("Y: ").append(ps.mCoords.y, 1)
+ .toString(), 1 + itemW * 2, base, mTextPaint);
+ } else {
+ float dx = ps.mTraceX[count - 1] - ps.mTraceX[0];
+ float dy = ps.mTraceY[count - 1] - ps.mTraceY[0];
+ canvas.drawRect(itemW, mHeaderPaddingTop, (itemW * 2) - 1, bottom,
+ Math.abs(dx) < mVC.getScaledTouchSlop()
+ ? mTextBackgroundPaint : mTextLevelPaint);
+ canvas.drawText(mText.clear()
+ .append("dX: ").append(dx, 1)
+ .toString(), 1 + itemW, base, mTextPaint);
+ canvas.drawRect(itemW * 2, mHeaderPaddingTop, (itemW * 3) - 1, bottom,
+ Math.abs(dy) < mVC.getScaledTouchSlop()
+ ? mTextBackgroundPaint : mTextLevelPaint);
+ canvas.drawText(mText.clear()
+ .append("dY: ").append(dy, 1)
+ .toString(), 1 + itemW * 2, base, mTextPaint);
+ }
+
+ canvas.drawRect(itemW * 3, mHeaderPaddingTop, (itemW * 4) - 1, bottom,
+ mTextBackgroundPaint);
+ canvas.drawText(mText.clear()
+ .append("Xv: ").append(ps.mXVelocity, 3)
+ .toString(), 1 + itemW * 3, base, mTextPaint);
+
+ canvas.drawRect(itemW * 4, mHeaderPaddingTop, (itemW * 5) - 1, bottom,
+ mTextBackgroundPaint);
+ canvas.drawText(mText.clear()
+ .append("Yv: ").append(ps.mYVelocity, 3)
+ .toString(), 1 + itemW * 4, base, mTextPaint);
+
+ canvas.drawRect(itemW * 5, mHeaderPaddingTop, (itemW * 6) - 1, bottom,
+ mTextBackgroundPaint);
+ canvas.drawRect(itemW * 5, mHeaderPaddingTop,
+ (itemW * 5) + (ps.mCoords.pressure * itemW) - 1, bottom, mTextLevelPaint);
+ canvas.drawText(mText.clear()
+ .append("Prs: ").append(ps.mCoords.pressure, 2)
+ .toString(), 1 + itemW * 5, base, mTextPaint);
+
+ canvas.drawRect(itemW * 6, mHeaderPaddingTop, w, bottom, mTextBackgroundPaint);
+ canvas.drawRect(itemW * 6, mHeaderPaddingTop,
+ (itemW * 6) + (ps.mCoords.size * itemW) - 1, bottom, mTextLevelPaint);
+ canvas.drawText(mText.clear()
+ .append("Size: ").append(ps.mCoords.size, 2)
+ .toString(), 1 + itemW * 6, base, mTextPaint);
+ canvas.restore();
+ }
+
private void logMotionEvent(String type, MotionEvent event) {
final int action = event.getAction();
final int N = event.getHistorySize();
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index a8dcbaf..6cbace4 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -241,7 +241,11 @@
private final ArraySet<String> mRollbackWhitelistedPackages = new ArraySet<>();
private final ArraySet<String> mWhitelistedStagedInstallers = new ArraySet<>();
- private final ArraySet<String> mAllowedVendorApexes = new ArraySet<>();
+ // A map from package name of vendor APEXes that can be updated to an installer package name
+ // allowed to install updates for it.
+ private final ArrayMap<String, String> mAllowedVendorApexes = new ArrayMap<>();
+
+ private String mModulesInstallerPackageName;
/**
* Map of system pre-defined, uniquely named actors; keys are namespace,
@@ -412,10 +416,14 @@
return mWhitelistedStagedInstallers;
}
- public Set<String> getAllowedVendorApexes() {
+ public Map<String, String> getAllowedVendorApexes() {
return mAllowedVendorApexes;
}
+ public String getModulesInstallerPackageName() {
+ return mModulesInstallerPackageName;
+ }
+
public ArraySet<String> getAppDataIsolationWhitelistedApps() {
return mAppDataIsolationWhitelistedApps;
}
@@ -1210,12 +1218,21 @@
case "whitelisted-staged-installer": {
if (allowAppConfigs) {
String pkgname = parser.getAttributeValue(null, "package");
+ boolean isModulesInstaller = XmlUtils.readBooleanAttribute(
+ parser, "isModulesInstaller", false);
if (pkgname == null) {
Slog.w(TAG, "<" + name + "> without package in " + permFile
+ " at " + parser.getPositionDescription());
} else {
mWhitelistedStagedInstallers.add(pkgname);
}
+ if (isModulesInstaller) {
+ if (mModulesInstallerPackageName != null) {
+ throw new IllegalStateException(
+ "Multiple modules installers");
+ }
+ mModulesInstallerPackageName = pkgname;
+ }
} else {
logNotAllowedInPartition(name, permFile, parser);
}
@@ -1224,11 +1241,18 @@
case "allowed-vendor-apex": {
if (allowVendorApex) {
String pkgName = parser.getAttributeValue(null, "package");
+ String installerPkgName = parser.getAttributeValue(
+ null, "installerPackage");
if (pkgName == null) {
Slog.w(TAG, "<" + name + "> without package in " + permFile
+ " at " + parser.getPositionDescription());
- } else {
- mAllowedVendorApexes.add(pkgName);
+ }
+ if (installerPkgName == null) {
+ Slog.w(TAG, "<" + name + "> without installerPackage in " + permFile
+ + " at " + parser.getPositionDescription());
+ }
+ if (pkgName != null && installerPkgName != null) {
+ mAllowedVendorApexes.put(pkgName, installerPkgName);
}
} else {
logNotAllowedInPartition(name, permFile, parser);
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index e274595..ce6101f 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -146,6 +146,7 @@
"android_os_MemoryFile.cpp",
"android_os_MessageQueue.cpp",
"android_os_Parcel.cpp",
+ "android_os_PerformanceHintManager.cpp",
"android_os_SELinux.cpp",
"android_os_ServiceManager.cpp",
"android_os_SharedMemory.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 09d7ef0..97cac29 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -144,6 +144,7 @@
extern int register_android_os_ServiceManager(JNIEnv *env);
extern int register_android_os_MessageQueue(JNIEnv* env);
extern int register_android_os_Parcel(JNIEnv* env);
+extern int register_android_os_PerformanceHintManager(JNIEnv* env);
extern int register_android_os_SELinux(JNIEnv* env);
extern int register_android_os_VintfObject(JNIEnv *env);
extern int register_android_os_VintfRuntimeInfo(JNIEnv *env);
@@ -1523,6 +1524,7 @@
REG_JNI(register_android_os_SystemProperties),
REG_JNI(register_android_os_Binder),
REG_JNI(register_android_os_Parcel),
+ REG_JNI(register_android_os_PerformanceHintManager),
REG_JNI(register_android_os_HidlMemory),
REG_JNI(register_android_os_HidlSupport),
REG_JNI(register_android_os_HwBinder),
diff --git a/core/jni/android_os_PerformanceHintManager.cpp b/core/jni/android_os_PerformanceHintManager.cpp
new file mode 100644
index 0000000..d05a24f
--- /dev/null
+++ b/core/jni/android_os_PerformanceHintManager.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "PerfHint-jni"
+
+#include "jni.h"
+
+#include <dlfcn.h>
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/ScopedPrimitiveArray.h>
+#include <utils/Log.h>
+#include <vector>
+
+#include "core_jni_helpers.h"
+
+namespace android {
+
+namespace {
+
+struct APerformanceHintManager;
+struct APerformanceHintSession;
+
+typedef APerformanceHintManager* (*APH_getManager)();
+typedef APerformanceHintSession* (*APH_createSession)(APerformanceHintManager*, const int32_t*,
+ size_t, int64_t);
+typedef int64_t (*APH_getPreferredUpdateRateNanos)(APerformanceHintManager* manager);
+typedef void (*APH_updateTargetWorkDuration)(APerformanceHintSession*, int64_t);
+typedef void (*APH_reportActualWorkDuration)(APerformanceHintSession*, int64_t);
+typedef void (*APH_closeSession)(APerformanceHintSession* session);
+
+bool gAPerformanceHintBindingInitialized = false;
+APH_getManager gAPH_getManagerFn = nullptr;
+APH_createSession gAPH_createSessionFn = nullptr;
+APH_getPreferredUpdateRateNanos gAPH_getPreferredUpdateRateNanosFn = nullptr;
+APH_updateTargetWorkDuration gAPH_updateTargetWorkDurationFn = nullptr;
+APH_reportActualWorkDuration gAPH_reportActualWorkDurationFn = nullptr;
+APH_closeSession gAPH_closeSessionFn = nullptr;
+
+void ensureAPerformanceHintBindingInitialized() {
+ if (gAPerformanceHintBindingInitialized) return;
+
+ void* handle_ = dlopen("libandroid.so", RTLD_NOW | RTLD_NODELETE);
+ LOG_ALWAYS_FATAL_IF(handle_ == nullptr, "Failed to dlopen libandroid.so!");
+
+ gAPH_getManagerFn = (APH_getManager)dlsym(handle_, "APerformanceHint_getManager");
+ LOG_ALWAYS_FATAL_IF(gAPH_getManagerFn == nullptr,
+ "Failed to find required symbol APerformanceHint_getManager!");
+
+ gAPH_createSessionFn = (APH_createSession)dlsym(handle_, "APerformanceHint_createSession");
+ LOG_ALWAYS_FATAL_IF(gAPH_createSessionFn == nullptr,
+ "Failed to find required symbol APerformanceHint_createSession!");
+
+ gAPH_getPreferredUpdateRateNanosFn =
+ (APH_getPreferredUpdateRateNanos)dlsym(handle_,
+ "APerformanceHint_getPreferredUpdateRateNanos");
+ LOG_ALWAYS_FATAL_IF(gAPH_getPreferredUpdateRateNanosFn == nullptr,
+ "Failed to find required symbol "
+ "APerformanceHint_getPreferredUpdateRateNanos!");
+
+ gAPH_updateTargetWorkDurationFn =
+ (APH_updateTargetWorkDuration)dlsym(handle_,
+ "APerformanceHint_updateTargetWorkDuration");
+ LOG_ALWAYS_FATAL_IF(gAPH_updateTargetWorkDurationFn == nullptr,
+ "Failed to find required symbol "
+ "APerformanceHint_updateTargetWorkDuration!");
+
+ gAPH_reportActualWorkDurationFn =
+ (APH_reportActualWorkDuration)dlsym(handle_,
+ "APerformanceHint_reportActualWorkDuration");
+ LOG_ALWAYS_FATAL_IF(gAPH_reportActualWorkDurationFn == nullptr,
+ "Failed to find required symbol "
+ "APerformanceHint_reportActualWorkDuration!");
+
+ gAPH_closeSessionFn = (APH_closeSession)dlsym(handle_, "APerformanceHint_closeSession");
+ LOG_ALWAYS_FATAL_IF(gAPH_closeSessionFn == nullptr,
+ "Failed to find required symbol APerformanceHint_closeSession!");
+
+ gAPerformanceHintBindingInitialized = true;
+}
+
+} // namespace
+
+static jlong nativeAcquireManager(JNIEnv* env, jclass clazz) {
+ ensureAPerformanceHintBindingInitialized();
+ return reinterpret_cast<jlong>(gAPH_getManagerFn());
+}
+
+static jlong nativeGetPreferredUpdateRateNanos(JNIEnv* env, jclass clazz, jlong nativeManagerPtr) {
+ ensureAPerformanceHintBindingInitialized();
+ return gAPH_getPreferredUpdateRateNanosFn(
+ reinterpret_cast<APerformanceHintManager*>(nativeManagerPtr));
+}
+
+static jlong nativeCreateSession(JNIEnv* env, jclass clazz, jlong nativeManagerPtr, jintArray tids,
+ jlong initialTargetWorkDurationNanos) {
+ ensureAPerformanceHintBindingInitialized();
+ if (tids == nullptr) return 0;
+ std::vector<int32_t> tidsVector;
+ ScopedIntArrayRO tidsArray(env, tids);
+ for (size_t i = 0; i < tidsArray.size(); ++i) {
+ tidsVector.push_back(static_cast<int32_t>(tidsArray[i]));
+ }
+ return reinterpret_cast<jlong>(
+ gAPH_createSessionFn(reinterpret_cast<APerformanceHintManager*>(nativeManagerPtr),
+ tidsVector.data(), tidsVector.size(),
+ initialTargetWorkDurationNanos));
+}
+
+static void nativeUpdateTargetWorkDuration(JNIEnv* env, jclass clazz, jlong nativeSessionPtr,
+ jlong targetDurationNanos) {
+ ensureAPerformanceHintBindingInitialized();
+ gAPH_updateTargetWorkDurationFn(reinterpret_cast<APerformanceHintSession*>(nativeSessionPtr),
+ targetDurationNanos);
+}
+
+static void nativeReportActualWorkDuration(JNIEnv* env, jclass clazz, jlong nativeSessionPtr,
+ jlong actualDurationNanos) {
+ ensureAPerformanceHintBindingInitialized();
+ gAPH_reportActualWorkDurationFn(reinterpret_cast<APerformanceHintSession*>(nativeSessionPtr),
+ actualDurationNanos);
+}
+
+static void nativeCloseSession(JNIEnv* env, jclass clazz, jlong nativeSessionPtr) {
+ ensureAPerformanceHintBindingInitialized();
+ gAPH_closeSessionFn(reinterpret_cast<APerformanceHintSession*>(nativeSessionPtr));
+}
+
+static const JNINativeMethod gPerformanceHintMethods[] = {
+ {"nativeAcquireManager", "()J", (void*)nativeAcquireManager},
+ {"nativeGetPreferredUpdateRateNanos", "(J)J", (void*)nativeGetPreferredUpdateRateNanos},
+ {"nativeCreateSession", "(J[IJ)J", (void*)nativeCreateSession},
+ {"nativeUpdateTargetWorkDuration", "(JJ)V", (void*)nativeUpdateTargetWorkDuration},
+ {"nativeReportActualWorkDuration", "(JJ)V", (void*)nativeReportActualWorkDuration},
+ {"nativeCloseSession", "(J)V", (void*)nativeCloseSession},
+};
+
+int register_android_os_PerformanceHintManager(JNIEnv* env) {
+ return RegisterMethodsOrDie(env, "android/os/PerformanceHintManager", gPerformanceHintMethods,
+ NELEM(gPerformanceHintMethods));
+}
+
+} // namespace android
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 1955ec5..f63c0e5 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -825,6 +825,14 @@
transaction->setShadowRadius(ctrl, shadowRadius);
}
+static void nativeSetTrustedOverlay(JNIEnv* env, jclass clazz, jlong transactionObj,
+ jlong nativeObject, jboolean isTrustedOverlay) {
+ auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+
+ SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+ transaction->setTrustedOverlay(ctrl, isTrustedOverlay);
+}
+
static void nativeSetFrameRate(JNIEnv* env, jclass clazz, jlong transactionObj, jlong nativeObject,
jfloat frameRate, jint compatibility, jint changeFrameRateStrategy) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
@@ -2000,6 +2008,8 @@
(void*)nativeSetTransformHint },
{"nativeGetTransformHint", "(J)I",
(void*)nativeGetTransformHint },
+ {"nativeSetTrustedOverlay", "(JJZ)V",
+ (void*)nativeSetTrustedOverlay },
// clang-format on
};
diff --git a/core/res/res/layout-car/car_alert_dialog.xml b/core/res/res/layout-car/car_alert_dialog.xml
index 569e594..2e7b62c 100644
--- a/core/res/res/layout-car/car_alert_dialog.xml
+++ b/core/res/res/layout-car/car_alert_dialog.xml
@@ -54,7 +54,7 @@
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/text_view_start_margin"
android:layout_marginEnd="@dimen/text_view_end_margin"
- style="@style/CarBody2"/>
+ style="@style/CarBody4"/>
<!-- we don't need this spacer, but the id needs to be here for compatibility -->
<Space
diff --git a/core/res/res/layout-car/car_alert_dialog_button_bar.xml b/core/res/res/layout-car/car_alert_dialog_button_bar.xml
index 277b0dc..4f815b8 100644
--- a/core/res/res/layout-car/car_alert_dialog_button_bar.xml
+++ b/core/res/res/layout-car/car_alert_dialog_button_bar.xml
@@ -36,6 +36,9 @@
<Button
android:id="@+id/button3"
style="@style/CarAction1"
+ android:minWidth="@dimen/car_touch_target_size"
+ android:paddingStart="@dimen/car_padding_2"
+ android:paddingEnd="@dimen/car_padding_2"
android:background="@drawable/car_dialog_button_background"
android:layout_marginRight="@dimen/button_end_margin"
android:layout_width="wrap_content"
@@ -44,6 +47,9 @@
<Button
android:id="@+id/button2"
style="@style/CarAction1"
+ android:minWidth="@dimen/car_touch_target_size"
+ android:paddingStart="@dimen/car_padding_2"
+ android:paddingEnd="@dimen/car_padding_2"
android:background="@drawable/car_dialog_button_background"
android:layout_marginRight="@dimen/button_end_margin"
android:layout_width="wrap_content"
@@ -52,6 +58,9 @@
<Button
android:id="@+id/button1"
style="@style/CarAction1"
+ android:minWidth="@dimen/car_touch_target_size"
+ android:paddingStart="@dimen/car_padding_2"
+ android:paddingEnd="@dimen/car_padding_2"
android:background="@drawable/car_dialog_button_background"
android:layout_width="wrap_content"
android:layout_height="@dimen/button_layout_height" />
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 1fd1f18..a4726cf 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1249,9 +1249,9 @@
<string name="whichImageCaptureApplication" msgid="2737413019463215284">"Зрабіць здымак з дапамогай"</string>
<string name="whichImageCaptureApplicationNamed" msgid="8820702441847612202">"Зрабіць здымак з дапамогай %1$s"</string>
<string name="whichImageCaptureApplicationLabel" msgid="6505433734824988277">"Зрабіць здымак"</string>
- <string name="alwaysUse" msgid="3153558199076112903">"Выкарыстоўваць па змаўчанні для гэтага дзеяння."</string>
+ <string name="alwaysUse" msgid="3153558199076112903">"Выкарыстоўваць стандартна для гэтага дзеяння."</string>
<string name="use_a_different_app" msgid="4987790276170972776">"Выкарыстоўваць іншую праграму"</string>
- <string name="clearDefaultHintMsg" msgid="1325866337702524936">"Ачысціць па змаўчанні ў раздзеле \"Налады сістэмы > Прыкладанні > Спампаваныя\"."</string>
+ <string name="clearDefaultHintMsg" msgid="1325866337702524936">"Ачысціць стандартныя налады ў раздзеле \"Налады сістэмы > Праграмы > Спампаваныя\"."</string>
<string name="chooseActivity" msgid="8563390197659779956">"Выберыце дзеянне"</string>
<string name="chooseUsbActivity" msgid="2096269989990986612">"Выберыце прыкладанне для USB-прылады"</string>
<string name="noApplications" msgid="1186909265235544019">"Няма прыкладанняў, якія могуць выконваць гэты працэс."</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index bb26e6c..13725de 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -700,8 +700,8 @@
<string name="permdesc_bindConditionProviderService" msgid="6106018791256120258">"Allows the holder to bind to the top-level interface of a condition provider service. Should never be needed for normal apps."</string>
<string name="permlab_bindDreamService" msgid="4776175992848982706">"bind to a dream service"</string>
<string name="permdesc_bindDreamService" msgid="9129615743300572973">"Allows the holder to bind to the top-level interface of a dream service. Should never be needed for normal apps."</string>
- <string name="permlab_invokeCarrierSetup" msgid="5098810760209818140">"invoke the carrier-provided configuration app"</string>
- <string name="permdesc_invokeCarrierSetup" msgid="4790845896063237887">"Allows the holder to invoke the carrier-provided configuration app. Should never be needed for normal apps."</string>
+ <string name="permlab_invokeCarrierSetup" msgid="5098810760209818140">"invoke the operator-provided configuration app"</string>
+ <string name="permdesc_invokeCarrierSetup" msgid="4790845896063237887">"Allows the holder to invoke the operator-provided configuration app. Should never be needed for normal apps."</string>
<string name="permlab_accessNetworkConditions" msgid="1270732533356286514">"listen for observations on network conditions"</string>
<string name="permdesc_accessNetworkConditions" msgid="2959269186741956109">"Allows an application to listen for observations on network conditions. Should never be needed for normal apps."</string>
<string name="permlab_setInputCalibration" msgid="932069700285223434">"change input device calibration"</string>
@@ -712,8 +712,8 @@
<string name="permdesc_handoverStatus" msgid="3842269451732571070">"Allows this application to receive information about current Android Beam transfers"</string>
<string name="permlab_removeDrmCertificates" msgid="710576248717404416">"remove DRM certificates"</string>
<string name="permdesc_removeDrmCertificates" msgid="4068445390318355716">"Allows an application to remove DRM certficates. Should never be needed for normal apps."</string>
- <string name="permlab_bindCarrierMessagingService" msgid="3363450860593096967">"bind to a carrier messaging service"</string>
- <string name="permdesc_bindCarrierMessagingService" msgid="6316457028173478345">"Allows the holder to bind to the top-level interface of a carrier messaging service. Should never be needed for normal apps."</string>
+ <string name="permlab_bindCarrierMessagingService" msgid="3363450860593096967">"bind to an operator messaging service"</string>
+ <string name="permdesc_bindCarrierMessagingService" msgid="6316457028173478345">"Allows the holder to bind to the top-level interface of an operator messaging service. Should never be needed for normal apps."</string>
<string name="permlab_bindCarrierServices" msgid="2395596978626237474">"bind to operator services"</string>
<string name="permdesc_bindCarrierServices" msgid="9185614481967262900">"Allows the holder to bind to operator services. Should never be needed for normal apps."</string>
<string name="permlab_access_notification_policy" msgid="5524112842876975537">"access Do Not Disturb"</string>
@@ -1656,7 +1656,7 @@
<string name="kg_sim_pin_instructions" msgid="6479401489471690359">"Enter SIM PIN"</string>
<string name="kg_pin_instructions" msgid="7355933174673539021">"Enter PIN"</string>
<string name="kg_password_instructions" msgid="7179782578809398050">"Enter Password"</string>
- <string name="kg_puk_enter_puk_hint" msgid="6696187482616360994">"SIM is now disabled. Enter PUK code to continue. Contact carrier for details."</string>
+ <string name="kg_puk_enter_puk_hint" msgid="6696187482616360994">"SIM is now disabled. Enter PUK code to continue. Contact operator for details."</string>
<string name="kg_puk_enter_pin_hint" msgid="8190982314659429770">"Enter desired PIN code"</string>
<string name="kg_enter_confirm_pin_hint" msgid="6372557107414074580">"Confirm desired PIN code"</string>
<string name="kg_sim_unlock_progress_dialog_message" msgid="8871937892678885545">"Unlocking SIM card…"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 9dd378c..9205763 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -700,8 +700,8 @@
<string name="permdesc_bindConditionProviderService" msgid="6106018791256120258">"Allows the holder to bind to the top-level interface of a condition provider service. Should never be needed for normal apps."</string>
<string name="permlab_bindDreamService" msgid="4776175992848982706">"bind to a dream service"</string>
<string name="permdesc_bindDreamService" msgid="9129615743300572973">"Allows the holder to bind to the top-level interface of a dream service. Should never be needed for normal apps."</string>
- <string name="permlab_invokeCarrierSetup" msgid="5098810760209818140">"invoke the carrier-provided configuration app"</string>
- <string name="permdesc_invokeCarrierSetup" msgid="4790845896063237887">"Allows the holder to invoke the carrier-provided configuration app. Should never be needed for normal apps."</string>
+ <string name="permlab_invokeCarrierSetup" msgid="5098810760209818140">"invoke the operator-provided configuration app"</string>
+ <string name="permdesc_invokeCarrierSetup" msgid="4790845896063237887">"Allows the holder to invoke the operator-provided configuration app. Should never be needed for normal apps."</string>
<string name="permlab_accessNetworkConditions" msgid="1270732533356286514">"listen for observations on network conditions"</string>
<string name="permdesc_accessNetworkConditions" msgid="2959269186741956109">"Allows an application to listen for observations on network conditions. Should never be needed for normal apps."</string>
<string name="permlab_setInputCalibration" msgid="932069700285223434">"change input device calibration"</string>
@@ -712,8 +712,8 @@
<string name="permdesc_handoverStatus" msgid="3842269451732571070">"Allows this application to receive information about current Android Beam transfers"</string>
<string name="permlab_removeDrmCertificates" msgid="710576248717404416">"remove DRM certificates"</string>
<string name="permdesc_removeDrmCertificates" msgid="4068445390318355716">"Allows an application to remove DRM certficates. Should never be needed for normal apps."</string>
- <string name="permlab_bindCarrierMessagingService" msgid="3363450860593096967">"bind to a carrier messaging service"</string>
- <string name="permdesc_bindCarrierMessagingService" msgid="6316457028173478345">"Allows the holder to bind to the top-level interface of a carrier messaging service. Should never be needed for normal apps."</string>
+ <string name="permlab_bindCarrierMessagingService" msgid="3363450860593096967">"bind to an operator messaging service"</string>
+ <string name="permdesc_bindCarrierMessagingService" msgid="6316457028173478345">"Allows the holder to bind to the top-level interface of an operator messaging service. Should never be needed for normal apps."</string>
<string name="permlab_bindCarrierServices" msgid="2395596978626237474">"bind to operator services"</string>
<string name="permdesc_bindCarrierServices" msgid="9185614481967262900">"Allows the holder to bind to operator services. Should never be needed for normal apps."</string>
<string name="permlab_access_notification_policy" msgid="5524112842876975537">"access Do Not Disturb"</string>
@@ -1656,7 +1656,7 @@
<string name="kg_sim_pin_instructions" msgid="6479401489471690359">"Enter SIM PIN"</string>
<string name="kg_pin_instructions" msgid="7355933174673539021">"Enter PIN"</string>
<string name="kg_password_instructions" msgid="7179782578809398050">"Enter Password"</string>
- <string name="kg_puk_enter_puk_hint" msgid="6696187482616360994">"SIM is now disabled. Enter PUK code to continue. Contact carrier for details."</string>
+ <string name="kg_puk_enter_puk_hint" msgid="6696187482616360994">"SIM is now disabled. Enter PUK code to continue. Contact operator for details."</string>
<string name="kg_puk_enter_pin_hint" msgid="8190982314659429770">"Enter desired PIN code"</string>
<string name="kg_enter_confirm_pin_hint" msgid="6372557107414074580">"Confirm desired PIN code"</string>
<string name="kg_sim_unlock_progress_dialog_message" msgid="8871937892678885545">"Unlocking SIM card…"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 81f49ce..45709f0 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -700,8 +700,8 @@
<string name="permdesc_bindConditionProviderService" msgid="6106018791256120258">"Allows the holder to bind to the top-level interface of a condition provider service. Should never be needed for normal apps."</string>
<string name="permlab_bindDreamService" msgid="4776175992848982706">"bind to a dream service"</string>
<string name="permdesc_bindDreamService" msgid="9129615743300572973">"Allows the holder to bind to the top-level interface of a dream service. Should never be needed for normal apps."</string>
- <string name="permlab_invokeCarrierSetup" msgid="5098810760209818140">"invoke the carrier-provided configuration app"</string>
- <string name="permdesc_invokeCarrierSetup" msgid="4790845896063237887">"Allows the holder to invoke the carrier-provided configuration app. Should never be needed for normal apps."</string>
+ <string name="permlab_invokeCarrierSetup" msgid="5098810760209818140">"invoke the operator-provided configuration app"</string>
+ <string name="permdesc_invokeCarrierSetup" msgid="4790845896063237887">"Allows the holder to invoke the operator-provided configuration app. Should never be needed for normal apps."</string>
<string name="permlab_accessNetworkConditions" msgid="1270732533356286514">"listen for observations on network conditions"</string>
<string name="permdesc_accessNetworkConditions" msgid="2959269186741956109">"Allows an application to listen for observations on network conditions. Should never be needed for normal apps."</string>
<string name="permlab_setInputCalibration" msgid="932069700285223434">"change input device calibration"</string>
@@ -712,8 +712,8 @@
<string name="permdesc_handoverStatus" msgid="3842269451732571070">"Allows this application to receive information about current Android Beam transfers"</string>
<string name="permlab_removeDrmCertificates" msgid="710576248717404416">"remove DRM certificates"</string>
<string name="permdesc_removeDrmCertificates" msgid="4068445390318355716">"Allows an application to remove DRM certficates. Should never be needed for normal apps."</string>
- <string name="permlab_bindCarrierMessagingService" msgid="3363450860593096967">"bind to a carrier messaging service"</string>
- <string name="permdesc_bindCarrierMessagingService" msgid="6316457028173478345">"Allows the holder to bind to the top-level interface of a carrier messaging service. Should never be needed for normal apps."</string>
+ <string name="permlab_bindCarrierMessagingService" msgid="3363450860593096967">"bind to an operator messaging service"</string>
+ <string name="permdesc_bindCarrierMessagingService" msgid="6316457028173478345">"Allows the holder to bind to the top-level interface of an operator messaging service. Should never be needed for normal apps."</string>
<string name="permlab_bindCarrierServices" msgid="2395596978626237474">"bind to operator services"</string>
<string name="permdesc_bindCarrierServices" msgid="9185614481967262900">"Allows the holder to bind to operator services. Should never be needed for normal apps."</string>
<string name="permlab_access_notification_policy" msgid="5524112842876975537">"access Do Not Disturb"</string>
@@ -1656,7 +1656,7 @@
<string name="kg_sim_pin_instructions" msgid="6479401489471690359">"Enter SIM PIN"</string>
<string name="kg_pin_instructions" msgid="7355933174673539021">"Enter PIN"</string>
<string name="kg_password_instructions" msgid="7179782578809398050">"Enter Password"</string>
- <string name="kg_puk_enter_puk_hint" msgid="6696187482616360994">"SIM is now disabled. Enter PUK code to continue. Contact carrier for details."</string>
+ <string name="kg_puk_enter_puk_hint" msgid="6696187482616360994">"SIM is now disabled. Enter PUK code to continue. Contact operator for details."</string>
<string name="kg_puk_enter_pin_hint" msgid="8190982314659429770">"Enter desired PIN code"</string>
<string name="kg_enter_confirm_pin_hint" msgid="6372557107414074580">"Confirm desired PIN code"</string>
<string name="kg_sim_unlock_progress_dialog_message" msgid="8871937892678885545">"Unlocking SIM card…"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index ddbcfb8..8749d05 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -700,8 +700,8 @@
<string name="permdesc_bindConditionProviderService" msgid="6106018791256120258">"Allows the holder to bind to the top-level interface of a condition provider service. Should never be needed for normal apps."</string>
<string name="permlab_bindDreamService" msgid="4776175992848982706">"bind to a dream service"</string>
<string name="permdesc_bindDreamService" msgid="9129615743300572973">"Allows the holder to bind to the top-level interface of a dream service. Should never be needed for normal apps."</string>
- <string name="permlab_invokeCarrierSetup" msgid="5098810760209818140">"invoke the carrier-provided configuration app"</string>
- <string name="permdesc_invokeCarrierSetup" msgid="4790845896063237887">"Allows the holder to invoke the carrier-provided configuration app. Should never be needed for normal apps."</string>
+ <string name="permlab_invokeCarrierSetup" msgid="5098810760209818140">"invoke the operator-provided configuration app"</string>
+ <string name="permdesc_invokeCarrierSetup" msgid="4790845896063237887">"Allows the holder to invoke the operator-provided configuration app. Should never be needed for normal apps."</string>
<string name="permlab_accessNetworkConditions" msgid="1270732533356286514">"listen for observations on network conditions"</string>
<string name="permdesc_accessNetworkConditions" msgid="2959269186741956109">"Allows an application to listen for observations on network conditions. Should never be needed for normal apps."</string>
<string name="permlab_setInputCalibration" msgid="932069700285223434">"change input device calibration"</string>
@@ -712,8 +712,8 @@
<string name="permdesc_handoverStatus" msgid="3842269451732571070">"Allows this application to receive information about current Android Beam transfers"</string>
<string name="permlab_removeDrmCertificates" msgid="710576248717404416">"remove DRM certificates"</string>
<string name="permdesc_removeDrmCertificates" msgid="4068445390318355716">"Allows an application to remove DRM certficates. Should never be needed for normal apps."</string>
- <string name="permlab_bindCarrierMessagingService" msgid="3363450860593096967">"bind to a carrier messaging service"</string>
- <string name="permdesc_bindCarrierMessagingService" msgid="6316457028173478345">"Allows the holder to bind to the top-level interface of a carrier messaging service. Should never be needed for normal apps."</string>
+ <string name="permlab_bindCarrierMessagingService" msgid="3363450860593096967">"bind to an operator messaging service"</string>
+ <string name="permdesc_bindCarrierMessagingService" msgid="6316457028173478345">"Allows the holder to bind to the top-level interface of an operator messaging service. Should never be needed for normal apps."</string>
<string name="permlab_bindCarrierServices" msgid="2395596978626237474">"bind to operator services"</string>
<string name="permdesc_bindCarrierServices" msgid="9185614481967262900">"Allows the holder to bind to operator services. Should never be needed for normal apps."</string>
<string name="permlab_access_notification_policy" msgid="5524112842876975537">"access Do Not Disturb"</string>
@@ -1656,7 +1656,7 @@
<string name="kg_sim_pin_instructions" msgid="6479401489471690359">"Enter SIM PIN"</string>
<string name="kg_pin_instructions" msgid="7355933174673539021">"Enter PIN"</string>
<string name="kg_password_instructions" msgid="7179782578809398050">"Enter Password"</string>
- <string name="kg_puk_enter_puk_hint" msgid="6696187482616360994">"SIM is now disabled. Enter PUK code to continue. Contact carrier for details."</string>
+ <string name="kg_puk_enter_puk_hint" msgid="6696187482616360994">"SIM is now disabled. Enter PUK code to continue. Contact operator for details."</string>
<string name="kg_puk_enter_pin_hint" msgid="8190982314659429770">"Enter desired PIN code"</string>
<string name="kg_enter_confirm_pin_hint" msgid="6372557107414074580">"Confirm desired PIN code"</string>
<string name="kg_sim_unlock_progress_dialog_message" msgid="8871937892678885545">"Unlocking SIM card…"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 3ce014c..e0deab1 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -244,7 +244,7 @@
<string name="global_actions" product="default" msgid="6410072189971495460">"Opciones del teléfono"</string>
<string name="global_action_lock" msgid="6949357274257655383">"Bloqueo de pantalla"</string>
<string name="global_action_power_off" msgid="4404936470711393203">"Apagar"</string>
- <string name="global_action_power_options" msgid="1185286119330160073">"Encender o apagar"</string>
+ <string name="global_action_power_options" msgid="1185286119330160073">"Apagar o reiniciar"</string>
<string name="global_action_restart" msgid="4678451019561687074">"Reiniciar"</string>
<string name="global_action_emergency" msgid="1387617624177105088">"Emergencia"</string>
<string name="global_action_bug_report" msgid="5127867163044170003">"Informe de errores"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 3290919..710e943 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -34,7 +34,7 @@
<string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
<string name="mmiError" msgid="2862759606579822246">"કનેક્શન સમસ્યા અથવા અમાન્ય MMI કોડ."</string>
<string name="mmiFdnError" msgid="3975490266767565852">"ઑપરેશન ફક્ત સ્થિર ડાયલિંગ નંબર્સ પર પ્રતિબંધિત છે."</string>
- <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"તમે રોમિંગમાં હોવ તે વખતે તમારા ફોન પરથી કૉલ ફોરવર્ડિગ સેટિંગ્સ બદલી શકતાં નથી."</string>
+ <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"તમે રોમિંગમાં હો તે વખતે તમારા ફોન પરથી કૉલ ફૉરવર્ડિગ સેટિંગ બદલી શકતાં નથી."</string>
<string name="serviceEnabled" msgid="7549025003394765639">"સેવા સક્ષમ હતી."</string>
<string name="serviceEnabledFor" msgid="1463104778656711613">"સેવા આ માટે સક્ષમ હતી:"</string>
<string name="serviceDisabled" msgid="641878791205871379">"સેવા અક્ષમ કરવામાં આવી છે."</string>
@@ -124,7 +124,7 @@
<string name="roamingTextSearching" msgid="5323235489657753486">"સેવા શોધી રહ્યું છે"</string>
<string name="wfcRegErrorTitle" msgid="3193072971584858020">"વાઇ-ફાઇ કૉલિંગ સેટ કરી શકાયું નથી"</string>
<string-array name="wfcOperatorErrorAlertMessages">
- <item msgid="468830943567116703">"વાઇ-ફાઇ પરથી કૉલ કરવા અને સંદેશા મોકલવા માટે પહેલાં તમારા કૅરિઅરને આ સેવા સેટ કરવા માટે કહો. પછી સેટિંગ્સમાંથી વાઇ-ફાઇ કૉલિંગ ફરીથી ચાલુ કરો. (ભૂલ કોડ: <xliff:g id="CODE">%1$s</xliff:g>)"</item>
+ <item msgid="468830943567116703">"વાઇ-ફાઇ પરથી કૉલ કરવા અને સંદેશા મોકલવા માટે પહેલાં તમારા કૅરિઅરને આ સેવા સેટ કરવા માટે કહો. પછી સેટિંગમાંથી વાઇ-ફાઇ કૉલિંગ ફરીથી ચાલુ કરો. (ભૂલ કોડ: <xliff:g id="CODE">%1$s</xliff:g>)"</item>
</string-array>
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="4795145070505729156">"તમારા કૅરિઅરમાં વાઇ-ફાઇ કૉલિંગ રજિસ્ટર કરવામાં સમસ્યા આવી: <xliff:g id="CODE">%1$s</xliff:g>"</item>
@@ -401,7 +401,7 @@
<string name="permlab_getPackageSize" msgid="375391550792886641">"ઍપ્લિકેશન સંગ્રહ સ્થાન માપો"</string>
<string name="permdesc_getPackageSize" msgid="742743530909966782">"એપ્લિકેશનને તેનો કોડ, ડેટા અને કેશ કદ પુનઃપ્રાપ્ત કરવાની મંજૂરી આપે છે."</string>
<string name="permlab_writeSettings" msgid="8057285063719277394">"સિસ્ટમ સેટિંગમાં ફેરફાર કરો"</string>
- <string name="permdesc_writeSettings" msgid="8293047411196067188">"એપ્લિકેશનને તમારા સિસ્ટમના સેટિંગ્સ ડેટાને સંશોધિત કરવાની મંજૂરી આપે છે. દુર્ભાવનાપૂર્ણ ઍપ્લિકેશનો તમારા સિસ્ટમની ગોઠવણીને દૂષિત કરી શકે છે."</string>
+ <string name="permdesc_writeSettings" msgid="8293047411196067188">"ઍપને તમારા સિસ્ટમના સેટિંગ ડેટાને સંશોધિત કરવાની મંજૂરી આપે છે. દુર્ભાવનાપૂર્ણ ઍપ તમારા સિસ્ટમની ગોઠવણીને દૂષિત કરી શકે છે."</string>
<string name="permlab_receiveBootCompleted" msgid="6643339400247325379">"સ્ટાર્ટઅપ પર શરૂ કરો"</string>
<string name="permdesc_receiveBootCompleted" product="tablet" msgid="5565659082718177484">"એપ્લિકેશનને સિસ્ટમ બૂટ થવાનું સમાપ્ત કરી લે કે તરત જ પોતાની જાતે પ્રારંભ થવાની મંજૂરી આપે છે. આનાથી ટેબ્લેટને પ્રારંભ થવામાં વધુ લાંબો સમય લાગી શકે છે અને એપ્લિકેશનને હંમેશા ચાલુ રહીને ટેબ્લેટને એકંદર ધીમું કરવાની મંજૂરી આપી શકે છે."</string>
<string name="permdesc_receiveBootCompleted" product="tv" msgid="4900842256047614307">"ઍપને સિસ્ટમ બૂટ થવાનું સમાપ્ત કરી લે કે તરત જ પોતાની જાતે પ્રારંભ થવાની મંજૂરી આપે છે. આનાથી તમારા Android TV ડિવાઇસને શરૂ થવામાં વધુ સમય લાગી શકે છે અને ઍપને હંમેશાં ચાલુ રહીને ડિવાઇસને એકંદર ધીમું કરવાની મંજૂરી આપે છે."</string>
@@ -442,8 +442,8 @@
<string name="permdesc_accessCoarseLocation" msgid="778521847873199160">"ઍપ ઉપયોગમાં હોય તે વખતે સ્થાન સેવાઓમાંથી આ ઍપ તમારું અંદાજિત સ્થાન મેળવી શકે છે. ઍપ સ્થાન મેળવી શકે તે માટે તમારા ડિવાઇસમાં સ્થાન સેવાઓ ચાલુ કરેલી હોવી જરૂરી છે."</string>
<string name="permlab_accessBackgroundLocation" msgid="1721164702777366138">"બૅકગ્રાઉન્ડમાં સ્થાન ઍક્સેસ કરો"</string>
<string name="permdesc_accessBackgroundLocation" msgid="8264885066095638105">"આ ઍપ કોઈપણ સમયે સ્થાનને ઍક્સેસ કરી શકે છે, પછી ભલેને આ ઍપ ઉપયોગમાં ન હોય."</string>
- <string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"તમારી ઑડિઓ સેટિંગ્સ બદલો"</string>
- <string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"એપ્લિકેશનને વૈશ્વિક ઑડિઓ સેટિંગ્સને સંશોધિત કરવાની મંજૂરી આપે છે, જેમ કે વૉલ્યૂમ અને આઉટપુટ માટે કયા સ્પીકરનો ઉપયોગ કરવો."</string>
+ <string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"તમારા ઑડિયો સેટિંગ બદલો"</string>
+ <string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"ઍપને વૈશ્વિક ઑડિયો સેટિંગમાં ફેરફાર કરવાની મંજૂરી આપે છે, જેમ કે વૉલ્યૂમ અને આઉટપુટ માટે કયા સ્પીકરનો ઉપયોગ કરવો."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"ઑડિઓ રેકોર્ડ કરવાની"</string>
<string name="permdesc_recordAudio" msgid="5857246765327514062">"આ ઍપ ઉપયોગમાં હોય ત્યારે તે માઇક્રોફોનનો ઉપયોગ કરીને ઑડિયો રેકોર્ડ કરી શકે છે."</string>
<string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"બૅકગ્રાઉન્ડમાં ઑડિયો રેકોર્ડ કરો"</string>
@@ -519,7 +519,7 @@
<string name="permdesc_changeWifiMulticastState" product="tablet" msgid="191079868596433554">"એપ્લિકેશનને ફક્ત તમારા ટેબ્લેટ પર નહીં, પણ મલ્ટિકાસ્ટ સરનામાંનો ઉપયોગ કરીને વાઇ-ફાઇ નેટવર્ક પરના તમામ ઉપકરણોને મોકલાયેલ પૅકેટ્સ પ્રાપ્ત કરવાની મંજૂરી આપે છે. તે બિન-મલ્ટિકાસ્ટ મોડ કરતાં વધુ પાવર વાપરે છે."</string>
<string name="permdesc_changeWifiMulticastState" product="tv" msgid="1336952358450652595">"ઍપને ફક્ત તમારા Android TV ડિવાઇસ પર નહીં, પણ મલ્ટિકાસ્ટ ઍડ્રેસનો ઉપયોગ કરીને વાઇ-ફાઇ નેટવર્ક પરના તમામ ડિવાઇસને મોકલાયેલા પૅકેટ પ્રાપ્ત કરવાની મંજૂરી આપે છે. તે બિન-મલ્ટિકાસ્ટ મોડ કરતાં વધુ પાવર વાપરે છે."</string>
<string name="permdesc_changeWifiMulticastState" product="default" msgid="8296627590220222740">"એપ્લિકેશનને ફક્ત તમારા ફોન પર નહીં, પણ મલ્ટિકાસ્ટ સરનામાંનો ઉપયોગ કરીને વાઇ-ફાઇ નેટવર્ક પર તમામ ઉપકરણોને મોકલાયેલ પૅકેટ્સ પ્રાપ્ત કરવાની મંજૂરી આપે છે. તે બિન-મલ્ટિકાસ્ટ મોડ કરતાં વધુ પાવર વાપરે છે."</string>
- <string name="permlab_bluetoothAdmin" msgid="6490373569441946064">"બ્લૂટૂથ સેટિંગ્સ ઍક્સેસ કરો"</string>
+ <string name="permlab_bluetoothAdmin" msgid="6490373569441946064">"બ્લૂટૂથ સેટિંગ ઍક્સેસ કરો"</string>
<string name="permdesc_bluetoothAdmin" product="tablet" msgid="5370837055438574863">"એપ્લિકેશનને સ્થાનિક બ્લૂટૂથ ટેબ્લેટ ગોઠવવાની અને રિમોટ ઉપકરણો શોધવા અને તેમની સાથે જોડી કરવાની મંજૂરી આપે છે."</string>
<string name="permdesc_bluetoothAdmin" product="tv" msgid="1623992984547014588">"ઍપને તમારા Android TV ડિવાઇસ પર બ્લૂટૂથને ગોઠવવાની અને રિમોટ ડિવાઇસ શોધવા અને તેમની સાથે જોડાણ કરવાની મંજૂરી આપે છે."</string>
<string name="permdesc_bluetoothAdmin" product="default" msgid="7381341743021234863">"એપ્લિકેશનને સ્થાનિક બ્લૂટૂથ ફોન ગોઠવવાની અને રિમોટ ઉપકરણો શોધવા અને તેમની સાથે જોડી કરવાની મંજૂરી આપે છે."</string>
@@ -662,10 +662,10 @@
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"ચહેરા આઇકન"</string>
- <string name="permlab_readSyncSettings" msgid="6250532864893156277">"સમન્વયન સેટિંગ્સ વાંચો"</string>
- <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"ઍપ્લિકેશનને એકાઉન્ટ માટે સમન્વયન સેટિંગ્સને વાંચવાની મંજૂરી આપે છે. ઉદાહરણ તરીકે, આ એકાઉન્ટ સાથે લોકો ઍપ્લિકેશન સમન્વયિત થઈ છે કે કેમ તે નિર્ધારિત કરી શકે છે."</string>
+ <string name="permlab_readSyncSettings" msgid="6250532864893156277">"સિંક સેટિંગ વાંચો"</string>
+ <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"ઍપને એકાઉન્ટ માટે સિંક સેટિંગને વાંચવાની મંજૂરી આપે છે. ઉદાહરણ તરીકે, આ એકાઉન્ટ સાથે લોકો ઍપ સિંક થઈ છે કે કેમ તે નિર્ધારિત કરી શકે છે."</string>
<string name="permlab_writeSyncSettings" msgid="6583154300780427399">"સમન્વયન ચાલુ અને બંધ ટોગલ કરો"</string>
- <string name="permdesc_writeSyncSettings" msgid="6029151549667182687">"એપ્લિકેશનને એકાઉન્ટ માટે સમન્વયન સેટિંગ્સ સંશોધિત કરવાની મંજૂરી આપે છે. ઉદાહરણ તરીકે, આનો ઉપયોગ એકાઉન્ટ સાથે લોકો એપ્લિકેશનના સમન્વયનને સક્ષમ કરવા માટે થઈ શકે છે."</string>
+ <string name="permdesc_writeSyncSettings" msgid="6029151549667182687">"ઍપને એકાઉન્ટ માટે સિંક સેટિંગમાં ફેરફાર કરવાની મંજૂરી આપે છે. ઉદાહરણ તરીકે, આનો ઉપયોગ એકાઉન્ટ સાથે લોકો ઍપના સિંકને ચાલુ કરવા માટે થઈ શકે છે."</string>
<string name="permlab_readSyncStats" msgid="3747407238320105332">"સમન્વયન આંકડા વાંચો"</string>
<string name="permdesc_readSyncStats" msgid="3867809926567379434">"એપ્લિકેશનને સમન્વયન ઇવેન્ટ્સનો ઇતિહાસ અને કેટલો ડેટા સમન્વયિત થયો છે તે સહિત કોઈ એકાઉન્ટ માટેનાં સમન્વયન આંકડા વાંચવાની મંજૂરી આપે છે."</string>
<string name="permlab_sdcardRead" msgid="5791467020950064920">"તમારા શેર કરેલા સ્ટોરેજના કન્ટેન્ટને વાંચો"</string>
@@ -1211,7 +1211,7 @@
<string name="whichImageCaptureApplicationLabel" msgid="6505433734824988277">"છબી કૅપ્ચર કરો"</string>
<string name="alwaysUse" msgid="3153558199076112903">"આ ક્રિયા માટે ડિફોલ્ટ તરીકે ઉપયોગમાં લો."</string>
<string name="use_a_different_app" msgid="4987790276170972776">"અલગ એપ્લિકેશનનો ઉપયોગ કરો"</string>
- <string name="clearDefaultHintMsg" msgid="1325866337702524936">"સિસ્ટમ સેટિંગ્સ > ઍપ્લિકેશનો > ડાઉનલોડ કરેલમાં ડિફોલ્ટ સાફ કરો."</string>
+ <string name="clearDefaultHintMsg" msgid="1325866337702524936">"સિસ્ટમ સેટિંગ > ઍપ > ડાઉનલોડ કરેલામાં ડિફૉલ્ટ સાફ કરો."</string>
<string name="chooseActivity" msgid="8563390197659779956">"એક ક્રિયા પસંદ કરો"</string>
<string name="chooseUsbActivity" msgid="2096269989990986612">"USB ઉપકરણ માટે ઍપ્લિકેશન પસંદ કરો"</string>
<string name="noApplications" msgid="1186909265235544019">"કોઈ ઍપ્લિકેશન આ ક્રિયા કરી શકતી નથી."</string>
@@ -1239,8 +1239,8 @@
<string name="launch_warning_original" msgid="3332206576800169626">"<xliff:g id="APP_NAME">%1$s</xliff:g> મૂળરૂપે લોંચ થઈ હતી."</string>
<string name="screen_compat_mode_scale" msgid="8627359598437527726">"સ્કેલ"</string>
<string name="screen_compat_mode_show" msgid="5080361367584709857">"હંમેશા બતાવો"</string>
- <string name="screen_compat_mode_hint" msgid="4032272159093750908">"આને સિસ્ટમ સેટિંગ્સ > ઍપ્લિકેશનો > ડાઉનલોડ કરેલમાં ફરીથી સક્ષમ કરો."</string>
- <string name="unsupported_display_size_message" msgid="7265211375269394699">"<xliff:g id="APP_NAME">%1$s</xliff:g> વર્તમાન પ્રદર્શન કદની સેટિંગનું સમર્થન કરતું નથી અને અનપેક્ષિત રીતે વર્તી શકે છે."</string>
+ <string name="screen_compat_mode_hint" msgid="4032272159093750908">"આને સિસ્ટમ સેટિંગ > ઍપ > ડાઉનલોડ કરેલામાં ફરીથી ચાલુ કરો."</string>
+ <string name="unsupported_display_size_message" msgid="7265211375269394699">"<xliff:g id="APP_NAME">%1$s</xliff:g> વર્તમાન ડિસ્પ્લે કદની સેટિંગને સપોર્ટ કરતું નથી અને અનપેક્ષિત રીતે વર્તી શકે છે."</string>
<string name="unsupported_display_size_show" msgid="980129850974919375">"હંમેશાં બતાવો"</string>
<string name="unsupported_compile_sdk_message" msgid="7326293500707890537">"<xliff:g id="APP_NAME">%1$s</xliff:g>ને Android OSના અસંગત વર્ઝન માટે બનાવવામાં આવ્યું હતું અને તે અનપેક્ષિત રીતે કાર્ય કરી શકે છે. ઍપનું અપડેટ કરેલ વર્ઝન ઉપલબ્ધ હોઈ શકે છે."</string>
<string name="unsupported_compile_sdk_show" msgid="1601210057960312248">"હંમેશાં બતાવો"</string>
@@ -1336,7 +1336,7 @@
<string name="sms_short_code_confirm_allow" msgid="920477594325526691">"મોકલો"</string>
<string name="sms_short_code_confirm_deny" msgid="1356917469323768230">"રદ કરો"</string>
<string name="sms_short_code_remember_choice" msgid="1374526438647744862">"મારી પસંદગી યાદ રાખો"</string>
- <string name="sms_short_code_remember_undo_instruction" msgid="2620984439143080410">"તમે પછીથી આને સેટિંગ્સ > એપ્લિકેશન્સમાં બદલી શકો છો"</string>
+ <string name="sms_short_code_remember_undo_instruction" msgid="2620984439143080410">"તમે પછીથી આને સેટિંગ > ઍપમાં બદલી શકો છો"</string>
<string name="sms_short_code_confirm_always_allow" msgid="2223014893129755950">"હંમેશા મંજૂરી આપો"</string>
<string name="sms_short_code_confirm_never_allow" msgid="2688828813521652079">"ક્યારેય મંજૂરી આપશો નહીં"</string>
<string name="sim_removed_title" msgid="5387212933992546283">"સિમ કાર્ડ કાઢી નાખ્યો"</string>
@@ -1503,7 +1503,7 @@
<string name="vpn_lockdown_connected" msgid="2853127976590658469">"હંમેશા-ચાલુ VPN કનેક્ટ થયું"</string>
<string name="vpn_lockdown_disconnected" msgid="5573611651300764955">"હંમેશાં-ચાલુ VPN થી ડિસ્કનેક્ટ થયું"</string>
<string name="vpn_lockdown_error" msgid="4453048646854247947">"હંમેશાં-ચાલુ VPN સાથે કનેક્ટ કરી શકાયું નથી"</string>
- <string name="vpn_lockdown_config" msgid="8331697329868252169">"નેટવર્ક અથવા VPN સેટિંગ્સ બદલો"</string>
+ <string name="vpn_lockdown_config" msgid="8331697329868252169">"નેટવર્ક અથવા VPN સેટિંગ બદલો"</string>
<string name="upload_file" msgid="8651942222301634271">"ફાઇલ પસંદ કરો"</string>
<string name="no_file_chosen" msgid="4146295695162318057">"કોઈ ફાઇલ પસંદ કરેલી નથી"</string>
<string name="reset" msgid="3865826612628171429">"ફરીથી સેટ કરો"</string>
@@ -1617,7 +1617,7 @@
<string name="SetupCallDefault" msgid="5581740063237175247">"કૉલ સ્વીકારીએ?"</string>
<string name="activity_resolver_use_always" msgid="5575222334666843269">"હંમેશાં"</string>
<string name="activity_resolver_use_once" msgid="948462794469672658">"ફક્ત એક વાર"</string>
- <string name="activity_resolver_work_profiles_support" msgid="4071345609235361269">"%1$s કાર્ય પ્રોફાઇલનું સમર્થન કરતું નથી"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="4071345609235361269">"%1$s ઑફિસની પ્રોફાઇલને સપોર્ટ કરતું નથી"</string>
<string name="default_audio_route_name" product="tablet" msgid="367936735632195517">"ટેબ્લેટ"</string>
<string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
<string name="default_audio_route_name" product="default" msgid="9213546147739983977">"ફોન"</string>
@@ -2068,7 +2068,7 @@
<string name="popup_window_default_title" msgid="6907717596694826919">"પૉપઅપ વિંડો"</string>
<string name="slice_more_content" msgid="3377367737876888459">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="9206301954024286063">"આ ઍપનું વર્ઝન ડાઉનગ્રેડ કરવામાં આવ્યું છે અથવા આ શૉર્ટકટ સાથે સુસંગત નથી"</string>
- <string name="shortcut_restore_not_supported" msgid="4763198938588468400">"શૉર્ટકટ ફરી મેળવી શકાયો નથી કારણ કે ઍપ બૅકઅપ અને ફરી મેળવવાનું સમર્થન કરતી નથી"</string>
+ <string name="shortcut_restore_not_supported" msgid="4763198938588468400">"શૉર્ટકટ ફરી મેળવી શકાયો નથી કારણ કે ઍપ બૅકઅપ અને ફરી મેળવવાને સપોર્ટ કરતી નથી"</string>
<string name="shortcut_restore_signature_mismatch" msgid="579345304221605479">"શૉર્ટકટ ફરી મેળવી શકાયો નથી કારણ કે ઍપમાં છે તે સહી મેળ ખાતી નથી"</string>
<string name="shortcut_restore_unknown_issue" msgid="2478146134395982154">"શૉર્ટકટ પાછો મેળવી શકાયો નથી"</string>
<string name="shortcut_disabled_reason_unknown" msgid="753074793553599166">"શૉર્ટકટને બંધ કરવામાં આવ્યો છે"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index b66d5f6..414d0bd 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -434,7 +434,7 @@
<string name="permdesc_bodySensors" product="default" msgid="2365357960407973997">"Aplikaciji omogoča dostop do podatkov tipal, ki nadzirajo vaše fizično stanje, med drugim vaš srčni utrip."</string>
<string name="permlab_readCalendar" msgid="6408654259475396200">"Branje dogodkov v koledarjih in podrobnosti koledarjev"</string>
<string name="permdesc_readCalendar" product="tablet" msgid="515452384059803326">"Ta aplikacija lahko prebere vse dogodke v koledarju, ki so shranjeni v tabličnem računalniku, ter shrani podatke koledarja ali jih deli z drugimi."</string>
- <string name="permdesc_readCalendar" product="tv" msgid="5811726712981647628">"Ta aplikacija lahko prebere vse dogodke v koledarju, ki so shranjeni v napravi Android TV, ter shrani podatke koledarja ali jih da v skupno rabo z drugimi."</string>
+ <string name="permdesc_readCalendar" product="tv" msgid="5811726712981647628">"Ta aplikacija lahko prebere vse dogodke v koledarju, ki so shranjeni v napravi Android TV, ter shrani podatke koledarja ali jih deli z drugimi."</string>
<string name="permdesc_readCalendar" product="default" msgid="9118823807655829957">"Ta aplikacija lahko prebere vse dogodke v koledarju, ki so shranjeni v telefonu, ter shrani podatke koledarja ali jih deli z drugimi."</string>
<string name="permlab_writeCalendar" msgid="6422137308329578076">"dodajanje ali spreminjanje dogodkov v koledarju in pošiljanje e-pošte gostom brez vedenja lastnikov"</string>
<string name="permdesc_writeCalendar" product="tablet" msgid="8722230940717092850">"Ta aplikacija lahko dodaja, odstranjuje in spreminja dogodke v koledarju, ki so shranjeni v tabličnem računalniku. Ta aplikacija lahko pošilja sporočila, ki bodo morda videti, kot da prihajajo od lastnikov koledarjev, ali spreminja dogodke brez vednosti lastnikov."</string>
@@ -932,7 +932,7 @@
<string name="lockscreen_forgot_pattern_button_text" msgid="8362442730606839031">"Ali ste pozabili vzorec?"</string>
<string name="lockscreen_glogin_forgot_pattern" msgid="9218940117797602518">"Odklepanje računa"</string>
<string name="lockscreen_glogin_too_many_attempts" msgid="3775904917743034195">"Preveč poskusov vzorca"</string>
- <string name="lockscreen_glogin_instructions" msgid="4695162942525531700">"Če želite odkleniti telefon, se prijavite z Google Računom."</string>
+ <string name="lockscreen_glogin_instructions" msgid="4695162942525531700">"Če želite odkleniti telefon, se prijavite z računom Google."</string>
<string name="lockscreen_glogin_username_hint" msgid="6916101478673157045">"Uporabniško ime (e-pošta)"</string>
<string name="lockscreen_glogin_password_hint" msgid="3031027901286812848">"Geslo"</string>
<string name="lockscreen_glogin_submit_button" msgid="3590556636347843733">"Prijava"</string>
@@ -1238,8 +1238,8 @@
<string name="whichEditApplicationNamed" msgid="8096494987978521514">"Urejanje z aplikacijo %1$s"</string>
<string name="whichEditApplicationLabel" msgid="1463288652070140285">"Urejanje"</string>
<string name="whichSendApplication" msgid="4143847974460792029">"Deljenje z drugimi"</string>
- <string name="whichSendApplicationNamed" msgid="4470386782693183461">"Skupna raba z aplikacijo %1$s"</string>
- <string name="whichSendApplicationLabel" msgid="7467813004769188515">"Skupna raba"</string>
+ <string name="whichSendApplicationNamed" msgid="4470386782693183461">"Deljenje z aplikacijo %1$s"</string>
+ <string name="whichSendApplicationLabel" msgid="7467813004769188515">"Deljenje"</string>
<string name="whichSendToApplication" msgid="77101541959464018">"Pošiljanje z aplikacijo"</string>
<string name="whichSendToApplicationNamed" msgid="3385686512014670003">"Pošiljanje z aplikacijo %1$s"</string>
<string name="whichSendToApplicationLabel" msgid="3543240188816513303">"Pošiljanje"</string>
@@ -1401,14 +1401,14 @@
<string name="perm_costs_money" msgid="749054595022779685">"to je lahko plačljivo"</string>
<string name="dlg_ok" msgid="5103447663504839312">"V redu"</string>
<string name="usb_charging_notification_title" msgid="1674124518282666955">"Polnjenje naprave prek USB-ja"</string>
- <string name="usb_supplying_notification_title" msgid="5378546632408101811">"Polnjenje akumulatorja v povezani napravi prek USB-ja"</string>
+ <string name="usb_supplying_notification_title" msgid="5378546632408101811">"Polnjenje baterije v povezani napravi prek USB-ja"</string>
<string name="usb_mtp_notification_title" msgid="1065989144124499810">"Vklopljen je prenos datotek prek USB-ja"</string>
<string name="usb_ptp_notification_title" msgid="5043437571863443281">"Vklopljen je način PTP prek USB-ja"</string>
<string name="usb_tether_notification_title" msgid="8828527870612663771">"Vklopljen je internet prek USB-ja"</string>
<string name="usb_midi_notification_title" msgid="7404506788950595557">"Vklopljen je način MIDI prek USB-ja"</string>
<string name="usb_accessory_notification_title" msgid="1385394660861956980">"Dodatek USB je priključen"</string>
<string name="usb_notification_message" msgid="4715163067192110676">"Dotaknite se za več možnosti."</string>
- <string name="usb_power_notification_message" msgid="7284765627437897702">"Polnjenje akumulatorja v povezani napravi. Dotaknite se za več možnosti."</string>
+ <string name="usb_power_notification_message" msgid="7284765627437897702">"Polnjenje baterije v povezani napravi. Dotaknite se za več možnosti."</string>
<string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"Zaznana je analogna dodatna zvočna oprema"</string>
<string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"Priključena naprava ni združljiva s tem telefonom. Dotaknite se za več informacij."</string>
<string name="adb_active_notification_title" msgid="408390247354560331">"Iskanje napak prek USB-ja je povezano"</string>
@@ -1428,8 +1428,8 @@
<string name="taking_remote_bugreport_notification_title" msgid="1582531382166919850">"Zajemanje poročila o napakah …"</string>
<string name="share_remote_bugreport_notification_title" msgid="6708897723753334999">"Želite poslati poročilo o napakah?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="3077385149217638550">"Pošiljanje poročila o napakah …"</string>
- <string name="share_remote_bugreport_notification_message_finished" msgid="7325635795739260135">"Skrbnik je zahteval poročilo o napakah za pomoč pri odpravljanju napak v tej napravi. Aplikacije in podatki bodo morda dani v skupno rabo."</string>
- <string name="share_remote_bugreport_action" msgid="7630880678785123682">"SKUPNA RABA"</string>
+ <string name="share_remote_bugreport_notification_message_finished" msgid="7325635795739260135">"Skrbnik je zahteval poročilo o napakah za pomoč pri odpravljanju napak v tej napravi. Aplikacije in podatki bodo morda deljeni."</string>
+ <string name="share_remote_bugreport_action" msgid="7630880678785123682">"DELJENJE"</string>
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"NE SPREJMEM"</string>
<string name="select_input_method" msgid="3971267998568587025">"Izberite način vnosa"</string>
<string name="show_ime" msgid="6406112007347443383">"Ohrani na zaslonu, dokler je aktivna fizična tipkovnica"</string>
@@ -1617,7 +1617,7 @@
<string name="action_menu_overflow_description" msgid="4579536843510088170">"Več možnosti"</string>
<string name="action_bar_home_description_format" msgid="5087107531331621803">"%1$s, %2$s"</string>
<string name="action_bar_home_subtitle_description_format" msgid="4346835454749569826">"%1$s, %2$s, %3$s"</string>
- <string name="storage_internal" msgid="8490227947584914460">"Notranja shramba v skupni rabi"</string>
+ <string name="storage_internal" msgid="8490227947584914460">"Notranja deljena shramba"</string>
<string name="storage_sd_card" msgid="3404740277075331881">"Kartica SD"</string>
<string name="storage_sd_card_label" msgid="7526153141147470509">"Kartica SD <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb_drive" msgid="448030813201444573">"Pogon USB"</string>
@@ -1710,7 +1710,7 @@
<string name="kg_invalid_puk" msgid="4809502818518963344">"Vnovič vnesite pravilno kodo PUK. Večkratni poskusi bodo trajno onemogočili kartico SIM."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="4705368340409816254">"Kodi PIN se ne ujemata"</string>
<string name="kg_login_too_many_attempts" msgid="699292728290654121">"Preveč poskusov vzorca"</string>
- <string name="kg_login_instructions" msgid="3619844310339066827">"Če želite odkleniti napravo, se prijavite z Google Računom."</string>
+ <string name="kg_login_instructions" msgid="3619844310339066827">"Če želite odkleniti napravo, se prijavite z računom Google."</string>
<string name="kg_login_username_hint" msgid="1765453775467133251">"Uporabniško ime (e-pošta)"</string>
<string name="kg_login_password_hint" msgid="3330530727273164402">"Geslo"</string>
<string name="kg_login_submit_button" msgid="893611277617096870">"Prijava"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index bf04c0e..16edb81 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -1198,7 +1198,7 @@
<string name="whichEditApplicationNamed" msgid="8096494987978521514">"Redakto me %1$s"</string>
<string name="whichEditApplicationLabel" msgid="1463288652070140285">"Redakto"</string>
<string name="whichSendApplication" msgid="4143847974460792029">"Ndaj"</string>
- <string name="whichSendApplicationNamed" msgid="4470386782693183461">"Shpërnda publikisht me %1$s"</string>
+ <string name="whichSendApplicationNamed" msgid="4470386782693183461">"Shpërndaj me %1$s"</string>
<string name="whichSendApplicationLabel" msgid="7467813004769188515">"Ndaj"</string>
<string name="whichSendToApplication" msgid="77101541959464018">"Dërgo me"</string>
<string name="whichSendToApplicationNamed" msgid="3385686512014670003">"Dërgo me %1$s"</string>
@@ -1566,8 +1566,8 @@
<string name="keyboardview_keycode_enter" msgid="168054869339091055">"Enter"</string>
<string name="activitychooserview_choose_application" msgid="3500574466367891463">"Zgjidh një aplikacion"</string>
<string name="activitychooserview_choose_application_error" msgid="6937782107559241734">"Nuk mundi ta hapte <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
- <string name="shareactionprovider_share_with" msgid="2753089758467748982">"Shpërnda publikisht me"</string>
- <string name="shareactionprovider_share_with_application" msgid="4902832247173666973">"Shpërnda me <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
+ <string name="shareactionprovider_share_with" msgid="2753089758467748982">"Shpërndaj me"</string>
+ <string name="shareactionprovider_share_with_application" msgid="4902832247173666973">"Shpërndaj me <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="content_description_sliding_handle" msgid="982510275422590757">"Dorezë me rrëshqitje. Preke dhe mbaje të shtypur."</string>
<string name="description_target_unlock_tablet" msgid="7431571180065859551">"Rrëshqit për të shkyçur."</string>
<string name="action_bar_home_description" msgid="1501655419158631974">"Orientohu për në shtëpi"</string>
@@ -1611,7 +1611,7 @@
<string name="sha1_fingerprint" msgid="2339915142825390774">"Gjurma e gishtit SHA-1:"</string>
<string name="activity_chooser_view_see_all" msgid="3917045206812726099">"Shikoji të gjitha"</string>
<string name="activity_chooser_view_dialog_title_default" msgid="8880731437191978314">"Zgjidh aktivitetin"</string>
- <string name="share_action_provider_share_with" msgid="1904096863622941880">"Shpërnda publikisht me"</string>
+ <string name="share_action_provider_share_with" msgid="1904096863622941880">"Shpërndaj me"</string>
<string name="sending" msgid="206925243621664438">"Po dërgon…"</string>
<string name="launchBrowserDefault" msgid="6328349989932924119">"Të hapet shfletuesi?"</string>
<string name="SetupCallDefault" msgid="5581740063237175247">"Dëshiron ta pranosh telefonatën?"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 1b54981..e494ef0 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -572,7 +572,7 @@
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autentiseringen avbröts"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Identifierades inte"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Autentiseringen avbröts"</string>
- <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Pinkod, grafiskt lösenord eller lösenord har inte angetts"</string>
+ <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Pinkod, mönster eller lösenord har inte angetts"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Ett fel uppstod vid autentiseringen"</string>
<string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Använd skärmlåset"</string>
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Fortsätt med hjälp av ditt skärmlås"</string>
@@ -881,7 +881,7 @@
<string name="lockscreen_screen_locked" msgid="7364905540516041817">"Skärmen har låsts."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Tryck på Menu för att låsa upp eller ringa nödsamtal."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Tryck på Menu för att låsa upp."</string>
- <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Rita grafiskt lösenord för att låsa upp"</string>
+ <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Rita mönster för att låsa upp"</string>
<string name="lockscreen_emergency_call" msgid="7549683825868928636">"Nödsamtal"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Tillbaka till samtal"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Korrekt!"</string>
@@ -925,7 +925,7 @@
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6807200118164539589">"Försök igen om <xliff:g id="NUMBER">%d</xliff:g> sekunder."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="8362442730606839031">"Glömt ditt grafiska lösenord?"</string>
<string name="lockscreen_glogin_forgot_pattern" msgid="9218940117797602518">"Lås upp konto"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="3775904917743034195">"För många försök med grafiskt lösenord"</string>
+ <string name="lockscreen_glogin_too_many_attempts" msgid="3775904917743034195">"För många försök med mönster"</string>
<string name="lockscreen_glogin_instructions" msgid="4695162942525531700">"Logga in med ditt Google-konto om du vill låsa upp."</string>
<string name="lockscreen_glogin_username_hint" msgid="6916101478673157045">"Användarnamn (e-post)"</string>
<string name="lockscreen_glogin_password_hint" msgid="3031027901286812848">"Lösenord"</string>
@@ -936,12 +936,12 @@
<string name="lockscreen_unlock_label" msgid="4648257878373307582">"Lås upp"</string>
<string name="lockscreen_sound_on_label" msgid="1660281470535492430">"Ljud på"</string>
<string name="lockscreen_sound_off_label" msgid="2331496559245450053">"Ljud av"</string>
- <string name="lockscreen_access_pattern_start" msgid="3778502525702613399">"Skriver grafiskt lösenord"</string>
- <string name="lockscreen_access_pattern_cleared" msgid="7493849102641167049">"Grafiskt lösenord har tagits bort"</string>
+ <string name="lockscreen_access_pattern_start" msgid="3778502525702613399">"Ritar mönster"</string>
+ <string name="lockscreen_access_pattern_cleared" msgid="7493849102641167049">"Mönster har tagits bort"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6746676335293144163">"En cell har lagts till"</string>
<string name="lockscreen_access_pattern_cell_added_verbose" msgid="2931364927622563465">"Cell <xliff:g id="CELL_INDEX">%1$s</xliff:g> har lagts till"</string>
- <string name="lockscreen_access_pattern_detected" msgid="3931150554035194012">"Grafiskt lösenord har slutförts"</string>
- <string name="lockscreen_access_pattern_area" msgid="1288780416685002841">"Fält för grafiskt lösenord."</string>
+ <string name="lockscreen_access_pattern_detected" msgid="3931150554035194012">"Mönster har slutförts"</string>
+ <string name="lockscreen_access_pattern_area" msgid="1288780416685002841">"Fält för mönster."</string>
<string name="keyguard_accessibility_widget_changed" msgid="7298011259508200234">"%1$s. Widget %2$d av %3$d."</string>
<string name="keyguard_accessibility_add_widget" msgid="8245795023551343672">"Lägg till en widget."</string>
<string name="keyguard_accessibility_widget_empty_slot" msgid="544239307077644480">"Tom"</string>
@@ -957,13 +957,13 @@
<string name="keyguard_accessibility_widget_deleted" msgid="1509738950119878705">"Widgeten <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> har tagits bort."</string>
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Expandera upplåsningsytan."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Lås upp genom att dra."</string>
- <string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Lås upp med grafiskt lösenord."</string>
+ <string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Lås upp med mönster."</string>
<string name="keyguard_accessibility_face_unlock" msgid="4533832120787386728">"Ansiktslås."</string>
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Lås upp med PIN-kod."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Lås upp med SIM-kortets pinkod."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Lås upp med SIM-kortets PUK-kod."</string>
<string name="keyguard_accessibility_password_unlock" msgid="6130186108581153265">"Lås upp med lösenord."</string>
- <string name="keyguard_accessibility_pattern_area" msgid="1419570880512350689">"Fält för grafiskt lösenord."</string>
+ <string name="keyguard_accessibility_pattern_area" msgid="1419570880512350689">"Fält för mönster."</string>
<string name="keyguard_accessibility_slide_area" msgid="4331399051142520176">"Fält med dragreglage."</string>
<string name="password_keyboard_label_symbol_key" msgid="2716255580853511949">"?123"</string>
<string name="password_keyboard_label_alpha_key" msgid="5294837425652726684">"ABC"</string>
@@ -1645,7 +1645,7 @@
<string name="display_manager_overlay_display_title" msgid="1480158037150469170">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="2810034719482834679">", säker"</string>
<string name="kg_forgot_pattern_button_text" msgid="406145459223122537">"Har du glömt ditt grafiska lösenord?"</string>
- <string name="kg_wrong_pattern" msgid="1342812634464179931">"Fel grafiskt lösenord"</string>
+ <string name="kg_wrong_pattern" msgid="1342812634464179931">"Fel mönster"</string>
<string name="kg_wrong_password" msgid="2384677900494439426">"Fel lösenord"</string>
<string name="kg_wrong_pin" msgid="3680925703673166482">"Fel PIN-kod"</string>
<plurals name="kg_too_many_failed_attempts_countdown" formatted="false" msgid="236717428673283568">
@@ -1665,7 +1665,7 @@
<string name="kg_invalid_sim_puk_hint" msgid="2539364558870734339">"PUK-koden ska vara åtta siffror."</string>
<string name="kg_invalid_puk" msgid="4809502818518963344">"Ange rätt PUK-kod igen. Om försöken upprepas inaktiveras SIM-kortet permanent."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="4705368340409816254">"PIN-koderna stämmer inte överens"</string>
- <string name="kg_login_too_many_attempts" msgid="699292728290654121">"För många försök med grafiskt lösenord"</string>
+ <string name="kg_login_too_many_attempts" msgid="699292728290654121">"För många försök med mönster"</string>
<string name="kg_login_instructions" msgid="3619844310339066827">"Logga in med ditt Google-konto om du vill låsa upp."</string>
<string name="kg_login_username_hint" msgid="1765453775467133251">"Användarnamn (e-post)"</string>
<string name="kg_login_password_hint" msgid="3330530727273164402">"Lösenord"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 01d0226..9a4d41b 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -815,7 +815,7 @@
<string name="phoneTypeTtyTdd" msgid="532038552105328779">"TTY TDD"</string>
<string name="phoneTypeWorkMobile" msgid="7522314392003565121">"కార్యాలయ మొబైల్"</string>
<string name="phoneTypeWorkPager" msgid="3748332310638505234">"కార్యాలయ పేజర్"</string>
- <string name="phoneTypeAssistant" msgid="757550783842231039">"Assistant"</string>
+ <string name="phoneTypeAssistant" msgid="757550783842231039">"అసిస్టెంట్"</string>
<string name="phoneTypeMms" msgid="1799747455131365989">"MMS"</string>
<string name="eventTypeCustom" msgid="3257367158986466481">"అనుకూలం"</string>
<string name="eventTypeBirthday" msgid="7770026752793912283">"పుట్టినరోజు"</string>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 441aa2d..73dfab6 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1190,7 +1190,7 @@
<code>dalvik.system.DelegateLastClassLoader</code>. If unspecified,
the default value of this attribute is <code>dalvik.system.PathClassLoader</code>.
- If an unknown classloader is provided, a PackageParserException with cause
+ If an unknown classloader is provided, a PackageManagerException with cause
<code>PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED</code> will be
thrown and the app will not be installed.
-->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 9433a71..f99cb19 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -657,6 +657,9 @@
<!-- Indicate the display area rect for foldable devices in folded state. -->
<string name="config_foldedArea"></string>
+ <!-- Indicates whether to enable an animation when unfolding a device or not -->
+ <bool name="config_unfoldTransitionEnabled">false</bool>
+
<!-- Indicates that the device supports having more than one internal display on at the same
time. Only applicable to devices with more than one internal display. If this option is
set to false, DisplayManager will make additional effort to ensure no more than 1 internal
@@ -3740,6 +3743,7 @@
<string-array translatable="false" name="config_nonBlockableNotificationPackages">
<item>com.android.dialer</item>
<item>com.android.messaging</item>
+ <item>com.android.cellbroadcastreceiver.module</item>
</string-array>
<!-- An array of packages that can make sound on the ringer stream in priority-only DND
diff --git a/core/res/res/values/dimens_car.xml b/core/res/res/values/dimens_car.xml
index 0ef60c4..36f1edb 100644
--- a/core/res/res/values/dimens_car.xml
+++ b/core/res/res/values/dimens_car.xml
@@ -110,10 +110,10 @@
<dimen name="car_textview_fading_edge_length">40dp</dimen>
<!-- Dialog start padding for button bar layout -->
- <dimen name="button_bar_layout_start_padding">@*android:dimen/car_keyline_1</dimen>
+ <dimen name="button_bar_layout_start_padding">@dimen/car_padding_2</dimen>
<!-- Dialog end padding for button bar layout -->
- <dimen name="button_bar_layout_end_padding">@*android:dimen/car_keyline_1</dimen>
+ <dimen name="button_bar_layout_end_padding">@dimen/car_padding_2</dimen>
<!-- Dialog top padding for button bar layout -->
<dimen name="button_bar_layout_top_padding">@*android:dimen/car_padding_2</dimen>
@@ -122,7 +122,7 @@
<dimen name="button_layout_height">@*android:dimen/car_card_action_bar_height</dimen>
<!-- Dialog button end margin -->
- <dimen name="button_end_margin">@*android:dimen/car_padding_4</dimen>
+ <dimen name="button_end_margin">@*android:dimen/car_padding_2</dimen>
<!-- Dialog top padding when there is no title -->
<dimen name="dialog_no_title_padding_top">@*android:dimen/car_padding_4</dimen>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 70bbc35..1084963 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3838,6 +3838,7 @@
<java-symbol type="array" name="config_foldedDeviceStates" />
<java-symbol type="string" name="config_foldedArea" />
<java-symbol type="bool" name="config_supportsConcurrentInternalDisplays" />
+ <java-symbol type="bool" name="config_unfoldTransitionEnabled" />
<java-symbol type="array" name="config_disableApksUnlessMatchedSku_apk_list" />
<java-symbol type="array" name="config_disableApkUnlessMatchedSku_skus_list" />
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index 6f17ea9..fb820cb 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -286,6 +286,7 @@
}
@Test
+ @FlakyTest(bugId = 194242735)
public void testHandleActivityConfigurationChanged_EnsureUpdatesProcessedInOrder()
throws Exception {
final TestActivity activity = mActivityTestRule.launchActivity(new Intent());
diff --git a/core/tests/coretests/src/android/app/appsearch/AppSearchSessionUnitTest.java b/core/tests/coretests/src/android/app/appsearch/AppSearchSessionUnitTest.java
index d51004c..07e4333 100644
--- a/core/tests/coretests/src/android/app/appsearch/AppSearchSessionUnitTest.java
+++ b/core/tests/coretests/src/android/app/appsearch/AppSearchSessionUnitTest.java
@@ -16,6 +16,8 @@
package android.app.appsearch;
+import static android.app.appsearch.SearchSpec.TERM_MATCH_PREFIX;
+
import static com.google.common.truth.Truth.assertThat;
import static org.testng.Assert.expectThrows;
@@ -30,6 +32,8 @@
import org.junit.Before;
import org.junit.Test;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
@@ -100,4 +104,127 @@
.isEqualTo(AppSearchResult.RESULT_INTERNAL_ERROR);
assertThat(appSearchException.getMessage()).startsWith("NullPointerException");
}
+
+ @Test
+ public void testGetEmptyNextPage() throws Exception {
+ // Set the schema.
+ CompletableFuture<AppSearchResult<SetSchemaResponse>> schemaFuture =
+ new CompletableFuture<>();
+ mSearchSession.setSchema(
+ new SetSchemaRequest.Builder()
+ .addSchemas(new AppSearchSchema.Builder("schema1").build())
+ .setForceOverride(true).build(),
+ mExecutor, mExecutor, schemaFuture::complete);
+ schemaFuture.get().getResultValue();
+
+ // Create a document and index it.
+ GenericDocument document1 = new GenericDocument.Builder<>("namespace", "id1",
+ "schema1").build();
+ CompletableFuture<AppSearchBatchResult<String, Void>> putDocumentsFuture =
+ new CompletableFuture<>();
+ mSearchSession.put(
+ new PutDocumentsRequest.Builder().addGenericDocuments(document1).build(),
+ mExecutor, new BatchResultCallback<String, Void>() {
+ @Override
+ public void onResult(AppSearchBatchResult<String, Void> result) {
+ putDocumentsFuture.complete(result);
+ }
+
+ @Override
+ public void onSystemError(Throwable throwable) {
+ putDocumentsFuture.completeExceptionally(throwable);
+ }
+ });
+ putDocumentsFuture.get();
+
+ // Search and get the first page.
+ SearchSpec searchSpec = new SearchSpec.Builder()
+ .setTermMatch(TERM_MATCH_PREFIX)
+ .setResultCountPerPage(1)
+ .build();
+ SearchResults searchResults = mSearchSession.search("", searchSpec);
+
+ CompletableFuture<AppSearchResult<List<SearchResult>>> getNextPageFuture =
+ new CompletableFuture<>();
+ searchResults.getNextPage(mExecutor, getNextPageFuture::complete);
+ List<SearchResult> results = getNextPageFuture.get().getResultValue();
+ assertThat(results).hasSize(1);
+ assertThat(results.get(0).getGenericDocument()).isEqualTo(document1);
+
+ // We get all documents, and it shouldn't fail if we keep calling getNextPage().
+ getNextPageFuture = new CompletableFuture<>();
+ searchResults.getNextPage(mExecutor, getNextPageFuture::complete);
+ results = getNextPageFuture.get().getResultValue();
+ assertThat(results).isEmpty();
+ }
+
+ @Test
+ public void testGetEmptyNextPage_multiPages() throws Exception {
+ // Set the schema.
+ CompletableFuture<AppSearchResult<SetSchemaResponse>> schemaFuture =
+ new CompletableFuture<>();
+ mSearchSession.setSchema(
+ new SetSchemaRequest.Builder()
+ .addSchemas(new AppSearchSchema.Builder("schema1").build())
+ .setForceOverride(true).build(),
+ mExecutor, mExecutor, schemaFuture::complete);
+ schemaFuture.get().getResultValue();
+
+ // Create a document and insert 3 package1 documents
+ GenericDocument document1 = new GenericDocument.Builder<>("namespace", "id1",
+ "schema1").build();
+ GenericDocument document2 = new GenericDocument.Builder<>("namespace", "id2",
+ "schema1").build();
+ GenericDocument document3 = new GenericDocument.Builder<>("namespace", "id3",
+ "schema1").build();
+ CompletableFuture<AppSearchBatchResult<String, Void>> putDocumentsFuture =
+ new CompletableFuture<>();
+ mSearchSession.put(
+ new PutDocumentsRequest.Builder()
+ .addGenericDocuments(document1, document2, document3).build(),
+ mExecutor, new BatchResultCallback<String, Void>() {
+ @Override
+ public void onResult(AppSearchBatchResult<String, Void> result) {
+ putDocumentsFuture.complete(result);
+ }
+
+ @Override
+ public void onSystemError(Throwable throwable) {
+ putDocumentsFuture.completeExceptionally(throwable);
+ }
+ });
+ putDocumentsFuture.get();
+
+ // Search for only 2 result per page
+ SearchSpec searchSpec = new SearchSpec.Builder()
+ .setTermMatch(TERM_MATCH_PREFIX)
+ .setResultCountPerPage(2)
+ .build();
+ SearchResults searchResults = mSearchSession.search("", searchSpec);
+
+ // Get the first page, it contains 2 results.
+ List<GenericDocument> outDocs = new ArrayList<>();
+ CompletableFuture<AppSearchResult<List<SearchResult>>> getNextPageFuture =
+ new CompletableFuture<>();
+ searchResults.getNextPage(mExecutor, getNextPageFuture::complete);
+ List<SearchResult> results = getNextPageFuture.get().getResultValue();
+ assertThat(results).hasSize(2);
+ outDocs.add(results.get(0).getGenericDocument());
+ outDocs.add(results.get(1).getGenericDocument());
+
+ // Get the second page, it contains only 1 result.
+ getNextPageFuture = new CompletableFuture<>();
+ searchResults.getNextPage(mExecutor, getNextPageFuture::complete);
+ results = getNextPageFuture.get().getResultValue();
+ assertThat(results).hasSize(1);
+ outDocs.add(results.get(0).getGenericDocument());
+
+ assertThat(outDocs).containsExactly(document1, document2, document3);
+
+ // We get all documents, and it shouldn't fail if we keep calling getNextPage().
+ getNextPageFuture = new CompletableFuture<>();
+ searchResults.getNextPage(mExecutor, getNextPageFuture::complete);
+ results = getNextPageFuture.get().getResultValue();
+ assertThat(results).isEmpty();
+ }
}
diff --git a/core/tests/coretests/src/android/app/appsearch/external/app/GenericDocumentTest.java b/core/tests/coretests/src/android/app/appsearch/external/app/GenericDocumentTest.java
index 6884f13d..3d820ac 100644
--- a/core/tests/coretests/src/android/app/appsearch/external/app/GenericDocumentTest.java
+++ b/core/tests/coretests/src/android/app/appsearch/external/app/GenericDocumentTest.java
@@ -62,4 +62,18 @@
assertThat(outDoc.getPropertyDocument("propDocument").getPropertyBytesArray("propBytes"))
.isEqualTo(new byte[][] {{3, 4}});
}
+
+ @Test
+ public void testPutLargeDocument_exceedLimit() throws Exception {
+ // Create a String property that has a very large property.
+ char[] chars = new char[10_000_000];
+ String property = new StringBuilder().append(chars).append("the end.").toString();
+
+ GenericDocument doc =
+ new GenericDocument.Builder<>("namespace", "id1", "schema1")
+ .setPropertyString("propString", property)
+ .build();
+
+ assertThat(doc.getPropertyString("propString")).isEqualTo(property);
+ }
}
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index 5d75d9b..7f53776 100644
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -34,7 +34,6 @@
import android.content.IntentSender;
import android.content.pm.PackageInstaller.SessionParams;
import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.parsing.ParsingPackage;
import android.content.pm.parsing.ParsingPackageUtils;
import android.content.pm.parsing.result.ParseResult;
@@ -574,7 +573,7 @@
ParsingPackage pkg;
- InstallParams(String outFileName, int rawResId) throws PackageParserException {
+ InstallParams(String outFileName, int rawResId) {
this.pkg = getParsedPackage(outFileName, rawResId);
this.packageURI = Uri.fromFile(new File(pkg.getPath()));
}
diff --git a/core/tests/coretests/src/android/os/PerformanceHintManagerTest.java b/core/tests/coretests/src/android/os/PerformanceHintManagerTest.java
index 7dea82d..69eb13f 100644
--- a/core/tests/coretests/src/android/os/PerformanceHintManagerTest.java
+++ b/core/tests/coretests/src/android/os/PerformanceHintManagerTest.java
@@ -22,12 +22,6 @@
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeNotNull;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
import android.os.PerformanceHintManager.Session;
@@ -120,92 +114,9 @@
}
@Test
- public void testRateLimitWithDurationFastEnough() throws Exception {
- FakeClock fakeClock = new FakeClock();
- Session s = new Session(mIHintSessionMock, fakeClock, RATE_1000, TARGET_166);
-
- reset(mIHintSessionMock);
- fakeClock.setNow(0);
- s.updateTargetWorkDuration(TARGET_166);
-
- s.reportActualWorkDuration(TARGET_166 - 1);
- s.reportActualWorkDuration(TARGET_166);
- // we should not see update as the rate should be 10X for over-perform case.
- verify(mIHintSessionMock, never()).reportActualWorkDuration(any(), any());
- fakeClock.incrementClock(10 * RATE_1000);
- s.reportActualWorkDuration(TARGET_166);
- verify(mIHintSessionMock, never()).reportActualWorkDuration(any(), any());
- fakeClock.incrementClock(1);
- s.reportActualWorkDuration(TARGET_166);
- // we should see update after rate limit
- verify(mIHintSessionMock, times(1)).reportActualWorkDuration(
- eq(new long[] {TARGET_166 - 1, TARGET_166, TARGET_166, TARGET_166}),
- eq(new long[] {0, 0, 10 * RATE_1000, 10 * RATE_1000 + 1}));
-
- reset(mIHintSessionMock);
- s.reportActualWorkDuration(TARGET_166);
- s.reportActualWorkDuration(TARGET_166 - 1);
- s.reportActualWorkDuration(TARGET_166 - 2);
- // we should not see update as the rate should be 10X for over-perform case.
- verify(mIHintSessionMock, never()).reportActualWorkDuration(any(), any());
- fakeClock.incrementClock(10 * RATE_1000 + 1);
- s.reportActualWorkDuration(TARGET_166);
- s.reportActualWorkDuration(TARGET_166 - 1);
- // we should see update now
- verify(mIHintSessionMock, times(1)).reportActualWorkDuration(
- eq(new long[] {TARGET_166, TARGET_166 - 1, TARGET_166 - 2, TARGET_166}),
- eq(new long[] {10 * RATE_1000 + 1, 10 * RATE_1000 + 1, 10 * RATE_1000 + 1,
- (10 * RATE_1000 + 1) * 2}));
- }
-
- @Test
- public void testRateLimitWithDurationTooSlow() throws Exception {
- FakeClock fakeClock = new FakeClock();
- Session s = new Session(mIHintSessionMock, fakeClock, RATE_1000, TARGET_166);
-
- reset(mIHintSessionMock);
- fakeClock.setNow(0);
- s.updateTargetWorkDuration(TARGET_166);
-
- verify(mIHintSessionMock, times(1)).updateTargetWorkDuration(eq(TARGET_166));
- // shouldn't update before rate limit
- s.reportActualWorkDuration(TARGET_166 + 1);
- verify(mIHintSessionMock, never()).reportActualWorkDuration(any(), any());
-
- // shouldn't update when the time is exactly at rate limit
- fakeClock.incrementClock(RATE_1000);
- s.reportActualWorkDuration(TARGET_166 + 1);
- verify(mIHintSessionMock, never()).reportActualWorkDuration(any(), any());
-
- // should be ready for sending hint
- fakeClock.incrementClock(1);
- s.reportActualWorkDuration(TARGET_166 + 1);
- verify(mIHintSessionMock, times(1)).reportActualWorkDuration(
- eq(new long[] {TARGET_166 + 1, TARGET_166 + 1, TARGET_166 + 1}),
- eq(new long[] {0 , RATE_1000, RATE_1000 + 1}));
- }
-
- @Test
public void testCloseHintSession() {
Session s = createSession();
assumeNotNull(s);
s.close();
}
-
- private static class FakeClock implements PerformanceHintManager.NanoClock {
- private long mCurrentTime = 0L;
-
- @Override
- public long nanos() {
- return mCurrentTime;
- }
-
- public void setNow(long nanos) {
- mCurrentTime = nanos;
- }
-
- public void incrementClock(long nanos) {
- mCurrentTime += nanos;
- }
- }
}
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodDebugTest.java b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodDebugTest.java
index 32bfdcb..9de09d6 100644
--- a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodDebugTest.java
+++ b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodDebugTest.java
@@ -73,4 +73,13 @@
InputMethodDebug.softInputDisplayReasonToString(
SoftInputShowHideReason.HIDE_REMOVE_CLIENT));
}
+
+ @Test
+ public void testDumpInputConnectionCommand() {
+ // TODO: add more tests
+ assertEquals("null", InputMethodDebug.dumpInputConnectionCommand(null));
+ assertEquals("endBatchEdit()",
+ InputMethodDebug.dumpInputConnectionCommand(
+ InputConnectionCommand.create(InputConnectionCommandType.END_BATCH_EDIT)));
+ }
}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsBackgroundStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsBackgroundStatsTest.java
index b687801..25bc1ee 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsBackgroundStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsBackgroundStatsTest.java
@@ -38,7 +38,7 @@
/** Test that BatteryStatsImpl.Uid.mOnBatteryBackgroundTimeBase works correctly. */
@SmallTest
public void testBgTimeBase() throws Exception {
- final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
+ final MockClock clocks = new MockClock(); // holds realtime and uptime in ms
MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
long cur = 0; // realtime in us
@@ -106,7 +106,7 @@
/** Test that BatteryStatsImpl.Uid.mOnBatteryScreenOffBackgroundTimeBase works correctly. */
@SmallTest
public void testScreenOffBgTimeBase() throws Exception {
- final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
+ final MockClock clocks = new MockClock(); // holds realtime and uptime in ms
MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
long cur = 0; // realtime in us
@@ -154,7 +154,7 @@
@SmallTest
public void testWifiScan() throws Exception {
- final MockClocks clocks = new MockClocks();
+ final MockClock clocks = new MockClock();
MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
long curr = 0; // realtime in us
@@ -207,7 +207,7 @@
}
private void doTestAppBluetoothScanInternal(WorkSource ws) throws Exception {
- final MockClocks clocks = new MockClocks();
+ final MockClock clocks = new MockClock();
MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
long curr = 0; // realtime in us
@@ -276,7 +276,7 @@
@SmallTest
public void testJob() throws Exception {
- final MockClocks clocks = new MockClocks();
+ final MockClock clocks = new MockClock();
MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
final String jobName = "job_name";
long curr = 0; // realtime in us
@@ -337,7 +337,7 @@
@SmallTest
public void testSyncs() throws Exception {
- final MockClocks clocks = new MockClocks();
+ final MockClock clocks = new MockClock();
MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
final String syncName = "sync_name";
long curr = 0; // realtime in us
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsBinderCallStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsBinderCallStatsTest.java
index 85f9c97..8ca0da0 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsBinderCallStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsBinderCallStatsTest.java
@@ -46,7 +46,7 @@
*/
@Test
public void testNoteBinderCallStats() throws Exception {
- final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
+ final MockClock clocks = new MockClock(); // holds realtime and uptime in ms
MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
int callingUid = Process.FIRST_APPLICATION_UID + 1;
@@ -89,7 +89,7 @@
@Test
public void testProportionalSystemServiceUsage_noStatsForSomeMethods() throws Exception {
- final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
+ final MockClock clocks = new MockClock(); // holds realtime and uptime in ms
MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
int callingUid = Process.FIRST_APPLICATION_UID + 1;
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsCounterTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsCounterTest.java
index ade3a99..6ff2b64 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsCounterTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsCounterTest.java
@@ -30,7 +30,7 @@
@SmallTest
public void testCounter() throws Exception {
- final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
+ final MockClock clocks = new MockClock(); // holds realtime and uptime in ms
final BatteryStatsImpl.TimeBase timeBase = new BatteryStatsImpl.TimeBase();
timeBase.init(clocks.uptimeMillis(), clocks.elapsedRealtime());
@@ -70,7 +70,7 @@
@SmallTest
public void testParceling() throws Exception {
- final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
+ final MockClock clocks = new MockClock(); // holds realtime and uptime in ms
final BatteryStatsImpl.TimeBase timeBase = new BatteryStatsImpl.TimeBase();
timeBase.init(clocks.uptimeMillis(), clocks.elapsedRealtime());
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
index 54d8701..1ac89ea 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
@@ -96,7 +96,7 @@
@Mock
PowerProfile mPowerProfile;
- private MockClocks mClocks;
+ private MockClock mClocks;
private MockBatteryStatsImpl mBatteryStatsImpl;
private KernelCpuSpeedReader[] mKernelCpuSpeedReaders;
@@ -104,7 +104,7 @@
public void setUp() {
MockitoAnnotations.initMocks(this);
- mClocks = new MockClocks();
+ mClocks = new MockClock();
mBatteryStatsImpl = new MockBatteryStatsImpl(mClocks)
.setKernelCpuUidUserSysTimeReader(mCpuUidUserSysTimeReader)
.setKernelCpuUidFreqTimeReader(mCpuUidFreqTimeReader)
@@ -1263,21 +1263,21 @@
mBatteryStatsImpl.new UidToRemove(1, mClocks.elapsedRealtime()));
mBatteryStatsImpl.getPendingRemovedUids().add(
mBatteryStatsImpl.new UidToRemove(5, 10, mClocks.elapsedRealtime()));
- mBatteryStatsImpl.clearPendingRemovedUids();
+ mBatteryStatsImpl.clearPendingRemovedUidsLocked();
assertEquals(2, mBatteryStatsImpl.getPendingRemovedUids().size());
mClocks.realtime = mClocks.uptime = 100_000;
- mBatteryStatsImpl.clearPendingRemovedUids();
+ mBatteryStatsImpl.clearPendingRemovedUidsLocked();
assertEquals(2, mBatteryStatsImpl.getPendingRemovedUids().size());
mClocks.realtime = mClocks.uptime = 200_000;
mBatteryStatsImpl.getPendingRemovedUids().add(
mBatteryStatsImpl.new UidToRemove(100, mClocks.elapsedRealtime()));
- mBatteryStatsImpl.clearPendingRemovedUids();
+ mBatteryStatsImpl.clearPendingRemovedUidsLocked();
assertEquals(3, mBatteryStatsImpl.getPendingRemovedUids().size());
mClocks.realtime = mClocks.uptime = 400_000;
- mBatteryStatsImpl.clearPendingRemovedUids();
+ mBatteryStatsImpl.clearPendingRemovedUidsLocked();
assertEquals(1, mBatteryStatsImpl.getPendingRemovedUids().size());
verify(mCpuUidActiveTimeReader).removeUid(1);
verify(mCpuUidActiveTimeReader).removeUidsInRange(5, 10);
@@ -1289,7 +1289,7 @@
verify(mCpuUidUserSysTimeReader).removeUidsInRange(5, 10);
mClocks.realtime = mClocks.uptime = 800_000;
- mBatteryStatsImpl.clearPendingRemovedUids();
+ mBatteryStatsImpl.clearPendingRemovedUidsLocked();
assertEquals(0, mBatteryStatsImpl.getPendingRemovedUids().size());
verify(mCpuUidActiveTimeReader).removeUid(100);
verify(mCpuUidClusterTimeReader).removeUid(100);
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsDualTimerTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsDualTimerTest.java
index efb8710..678d3ee 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsDualTimerTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsDualTimerTest.java
@@ -29,7 +29,7 @@
@SmallTest
public void testResetDetach() throws Exception {
- final MockClocks clocks = new MockClocks();
+ final MockClock clocks = new MockClock();
clocks.realtime = clocks.uptime = 100;
final BatteryStatsImpl.TimeBase timeBase = new BatteryStatsImpl.TimeBase();
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsDurationTimerTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsDurationTimerTest.java
index 78fa3fb..b7edb17 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsDurationTimerTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsDurationTimerTest.java
@@ -33,7 +33,7 @@
@SmallTest
public void testStartStop() throws Exception {
- final MockClocks clocks = new MockClocks();
+ final MockClock clocks = new MockClock();
final BatteryStatsImpl.TimeBase timeBase = new BatteryStatsImpl.TimeBase();
timeBase.init(clocks.uptimeMillis(), clocks.elapsedRealtime());
@@ -105,7 +105,7 @@
*/
@SmallTest
public void testReset() throws Exception {
- final MockClocks clocks = new MockClocks();
+ final MockClock clocks = new MockClock();
final BatteryStatsImpl.TimeBase timeBase = new BatteryStatsImpl.TimeBase();
timeBase.init(clocks.uptimeMillis(), clocks.elapsedRealtime());
@@ -141,7 +141,7 @@
*/
@SmallTest
public void testResetAndDetach() throws Exception {
- final MockClocks clocks = new MockClocks();
+ final MockClock clocks = new MockClock();
final BatteryStatsImpl.TimeBase timeBase = new BatteryStatsImpl.TimeBase();
timeBase.init(clocks.uptimeMillis(), clocks.elapsedRealtime());
@@ -168,7 +168,7 @@
@SmallTest
public void testParceling() throws Exception {
- final MockClocks clocks = new MockClocks();
+ final MockClock clocks = new MockClock();
final BatteryStatsImpl.TimeBase timeBase = new BatteryStatsImpl.TimeBase();
timeBase.init(clocks.uptimeMillis(), clocks.elapsedRealtime());
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
index 464412f..7a84201 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
@@ -60,7 +60,7 @@
*/
@SmallTest
public void testNoteBluetoothScanResultLocked() throws Exception {
- MockBatteryStatsImpl bi = new MockBatteryStatsImpl(new MockClocks());
+ MockBatteryStatsImpl bi = new MockBatteryStatsImpl(new MockClock());
bi.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_TOP);
@@ -89,7 +89,7 @@
*/
@SmallTest
public void testNoteStartWakeLocked() throws Exception {
- final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
+ final MockClock clocks = new MockClock(); // holds realtime and uptime in ms
MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
int pid = 10;
@@ -120,7 +120,7 @@
*/
@SmallTest
public void testNoteUidProcessStateLocked() throws Exception {
- final MockClocks clocks = new MockClocks();
+ final MockClock clocks = new MockClock();
MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
// map of ActivityManager process states and how long to simulate run time in each state
@@ -205,7 +205,7 @@
*/
@SmallTest
public void testUpdateTimeBasesLocked() throws Exception {
- final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
+ final MockClock clocks = new MockClock(); // holds realtime and uptime in ms
MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
bi.updateTimeBasesLocked(false, Display.STATE_OFF, 0, 0);
@@ -229,7 +229,7 @@
*/
@SmallTest
public void testNoteScreenStateLocked() throws Exception {
- final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
+ final MockClock clocks = new MockClock(); // holds realtime and uptime in ms
MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
bi.updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
@@ -258,7 +258,7 @@
*/
@SmallTest
public void testNoteScreenStateTimersLocked() throws Exception {
- final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
+ final MockClock clocks = new MockClock(); // holds realtime and uptime in ms
MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
clocks.realtime = clocks.uptime = 100;
@@ -297,7 +297,7 @@
@SmallTest
@SkipPresubmit("b/180015146")
public void testAlarmStartAndFinishLocked() throws Exception {
- final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
+ final MockClock clocks = new MockClock(); // holds realtime and uptime in ms
MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
bi.setRecordAllHistoryLocked(true);
bi.forceRecordAllHistory();
@@ -335,7 +335,7 @@
@SmallTest
@SkipPresubmit("b/180015146")
public void testAlarmStartAndFinishLocked_workSource() throws Exception {
- final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
+ final MockClock clocks = new MockClock(); // holds realtime and uptime in ms
MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
bi.setRecordAllHistoryLocked(true);
bi.forceRecordAllHistory();
@@ -379,7 +379,7 @@
@SmallTest
public void testNoteWakupAlarmLocked() {
- final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
+ final MockClock clocks = new MockClock(); // holds realtime and uptime in ms
MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
bi.setRecordAllHistoryLocked(true);
bi.forceRecordAllHistory();
@@ -397,7 +397,7 @@
@SmallTest
public void testNoteWakupAlarmLocked_workSource_uid() {
- final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
+ final MockClock clocks = new MockClock(); // holds realtime and uptime in ms
MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
bi.setRecordAllHistoryLocked(true);
bi.forceRecordAllHistory();
@@ -430,7 +430,7 @@
@SmallTest
public void testNoteWakupAlarmLocked_workSource_workChain() {
- final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
+ final MockClock clocks = new MockClock(); // holds realtime and uptime in ms
MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
bi.setRecordAllHistoryLocked(true);
bi.forceRecordAllHistory();
@@ -456,7 +456,7 @@
@SmallTest
public void testNoteGpsChanged() {
- final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
+ final MockClock clocks = new MockClock(); // holds realtime and uptime in ms
MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
bi.setRecordAllHistoryLocked(true);
bi.forceRecordAllHistory();
@@ -480,7 +480,7 @@
@SmallTest
public void testNoteGpsChanged_workSource() {
- final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
+ final MockClock clocks = new MockClock(); // holds realtime and uptime in ms
MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
bi.setRecordAllHistoryLocked(true);
bi.forceRecordAllHistory();
@@ -504,7 +504,7 @@
@SmallTest
public void testUpdateDisplayMeasuredEnergyStatsLocked() {
- final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
+ final MockClock clocks = new MockClock(); // holds realtime and uptime in ms
final MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
bi.initMeasuredEnergyStats();
@@ -589,7 +589,7 @@
@SmallTest
public void testUpdateCustomMeasuredEnergyStatsLocked_neverCalled() {
- final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
+ final MockClock clocks = new MockClock(); // holds realtime and uptime in ms
final MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
bi.initMeasuredEnergyStats();
bi.setOnBatteryInternal(true);
@@ -603,7 +603,7 @@
@SmallTest
public void testUpdateCustomMeasuredEnergyStatsLocked() {
- final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
+ final MockClock clocks = new MockClock(); // holds realtime and uptime in ms
final MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
bi.initMeasuredEnergyStats();
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsSamplingTimerTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSamplingTimerTest.java
index dd814e6..0d2249f 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsSamplingTimerTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSamplingTimerTest.java
@@ -30,7 +30,7 @@
@SmallTest
public void testSettingStalePreservesData() throws Exception {
- final MockClocks clocks = new MockClocks();
+ final MockClock clocks = new MockClock();
final BatteryStatsImpl.SamplingTimer timer = new BatteryStatsImpl.SamplingTimer(clocks,
Mockito.mock(BatteryStatsImpl.TimeBase.class));
@@ -56,9 +56,8 @@
}
@SmallTest
- @SkipPresubmit("b/180015146")
public void testEndSampleAndContinueWhenTimeOrCountDecreases() throws Exception {
- final MockClocks clocks = new MockClocks();
+ final MockClock clocks = new MockClock();
final BatteryStatsImpl.TimeBase timeBase = Mockito.mock(BatteryStatsImpl.TimeBase.class);
final BatteryStatsImpl.SamplingTimer timer = new BatteryStatsImpl.SamplingTimer(clocks,
timeBase);
@@ -72,7 +71,10 @@
assertEquals(0, timer.getTotalTimeLocked(200, BatteryStats.STATS_SINCE_CHARGED));
// This is less than we currently have, so we will end the sample. Time isn't running, so
- // nothing should happen.
+ // nothing should happen, except that tracking will stop.
+ timer.update(0, 0, SystemClock.elapsedRealtime() * 1000);
+
+ // Start tracking again
timer.update(0, 0, SystemClock.elapsedRealtime() * 1000);
assertEquals(0, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
@@ -86,9 +88,13 @@
assertEquals(100, timer.getTotalTimeLocked(200, BatteryStats.STATS_SINCE_CHARGED));
assertEquals(10, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
- // This is less than we currently have, so we should end our sample and continue with the
- // entire amount updated here.
- timer.update(50, 5, SystemClock.elapsedRealtime() * 1000);
+ // This is less than we currently have, so we should end our sample.
+ timer.update(30, 3, SystemClock.elapsedRealtime() * 1000);
+
+ // Restart tracking
+ timer.update(30, 3, SystemClock.elapsedRealtime() * 1000);
+
+ timer.add(50, 5);
assertEquals(150, timer.getTotalTimeLocked(200, BatteryStats.STATS_SINCE_CHARGED));
assertEquals(15, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
@@ -101,7 +107,7 @@
@SmallTest
public void testFirstUpdateIsAbsorbed() throws Exception {
- final MockClocks clocks = new MockClocks();
+ final MockClock clocks = new MockClock();
final BatteryStatsImpl.TimeBase timeBase = Mockito.mock(BatteryStatsImpl.TimeBase.class);
BatteryStatsImpl.SamplingTimer timer = new BatteryStatsImpl.SamplingTimer(clocks, timeBase);
@@ -140,7 +146,7 @@
@SmallTest
public void testSampleTimerSummaryParceling() throws Exception {
- final MockClocks clocks = new MockClocks();
+ final MockClock clocks = new MockClock();
clocks.realtime = 0;
clocks.uptime = 0;
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java
index b851f0a..f833981 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java
@@ -34,7 +34,7 @@
@SmallTest
public void testSensorStartStop() throws Exception {
- final MockClocks clocks = new MockClocks();
+ final MockClock clocks = new MockClock();
MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
bi.mForceOnBattery = true;
clocks.realtime = 100;
@@ -71,7 +71,7 @@
@SmallTest
public void testCountingWhileOffBattery() throws Exception {
- final MockClocks clocks = new MockClocks();
+ final MockClock clocks = new MockClock();
MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
long curr = 0; // realtime in us
@@ -107,7 +107,7 @@
@SmallTest
public void testCountingWhileOnBattery() throws Exception {
- final MockClocks clocks = new MockClocks();
+ final MockClock clocks = new MockClock();
MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
long curr = 0; // realtime in us
@@ -142,7 +142,7 @@
@SmallTest
public void testBatteryStatusOnToOff() throws Exception {
- final MockClocks clocks = new MockClocks();
+ final MockClock clocks = new MockClock();
MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
long curr = 0; // realtime in us
@@ -188,7 +188,7 @@
@SmallTest
public void testBatteryStatusOffToOn() throws Exception {
- final MockClocks clocks = new MockClocks();
+ final MockClock clocks = new MockClock();
MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
long curr = 0; // realtime in us
@@ -240,7 +240,7 @@
@SmallTest
public void testPooledBackgroundUsage() throws Exception {
final int UID_2 = 20000; // second uid for testing pool usage
- final MockClocks clocks = new MockClocks();
+ final MockClock clocks = new MockClock();
MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
bi.mForceOnBattery = true;
long curr = 0; // realtime in us
@@ -377,7 +377,7 @@
@SmallTest
public void testSensorReset() throws Exception {
- final MockClocks clocks = new MockClocks();
+ final MockClock clocks = new MockClock();
MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
bi.mForceOnBattery = true;
clocks.realtime = 100;
@@ -421,7 +421,7 @@
@SmallTest
public void testSensorResetTimes() throws Exception {
- final MockClocks clocks = new MockClocks();
+ final MockClock clocks = new MockClock();
MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
final int which = BatteryStats.STATS_SINCE_CHARGED;
bi.mForceOnBattery = true;
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsStopwatchTimerTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsStopwatchTimerTest.java
index f76f316..94092f1 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsStopwatchTimerTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsStopwatchTimerTest.java
@@ -31,7 +31,7 @@
// negative values of count.
@SmallTest
public void testCount() throws Exception {
- final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
+ final MockClock clocks = new MockClock(); // holds realtime and uptime in ms
final BatteryStatsImpl.TimeBase timeBase = new BatteryStatsImpl.TimeBase();
timeBase.init(clocks.uptimeMillis(), clocks.elapsedRealtime());
final BatteryStatsImpl.StopwatchTimer timer = new BatteryStatsImpl.StopwatchTimer(clocks,
@@ -142,7 +142,7 @@
assertEquals(expectedCount, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
}
- private static long updateTime(MockClocks clocks, long time) {
+ private static long updateTime(MockClock clocks, long time) {
return clocks.realtime = clocks.uptime = time;
}
}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimerTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimerTest.java
index 11a01b3..be3fc8a 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimerTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimerTest.java
@@ -22,7 +22,6 @@
import androidx.test.filters.SmallTest;
-import com.android.internal.os.BatteryStatsImpl.Clocks;
import com.android.internal.os.BatteryStatsImpl.TimeBase;
import com.android.internal.os.BatteryStatsImpl.Timer;
@@ -41,12 +40,12 @@
int nextComputeCurrentCount;
- TestTimer(Clocks clocks, int type, TimeBase timeBase, Parcel in) {
- super(clocks, type, timeBase, in);
+ TestTimer(Clock clock, int type, TimeBase timeBase, Parcel in) {
+ super(clock, type, timeBase, in);
}
- TestTimer(Clocks clocks, int type, TimeBase timeBase) {
- super(clocks, type, timeBase);
+ TestTimer(Clock clock, int type, TimeBase timeBase) {
+ super(clock, type, timeBase);
}
@Override
@@ -91,7 +90,7 @@
@SmallTest
public void testRunning() throws Exception {
TimeBase timeBase = new TimeBase();
- MockClocks clocks = new MockClocks();
+ MockClock clocks = new MockClock();
TestTimer timer = new TestTimer(clocks, 0, timeBase);
timer.nextComputeCurrentCount = 3000;
@@ -112,7 +111,7 @@
@SmallTest
public void testParceling() throws Exception {
TimeBase timeBase = new TimeBase();
- MockClocks clocks = new MockClocks();
+ MockClock clocks = new MockClock();
// Test write then read
TestTimer timer1 = new TestTimer(clocks, 0, timeBase);
@@ -157,7 +156,7 @@
@SmallTest
public void testResetNoDetach() throws Exception {
TimeBase timeBase = new TimeBase();
- MockClocks clocks = new MockClocks();
+ MockClock clocks = new MockClock();
TestTimer timer = new TestTimer(clocks, 0, timeBase);
timer.setCount(1);
@@ -180,7 +179,7 @@
@SmallTest
public void testResetDetach() throws Exception {
TimeBase timeBase = new TimeBase();
- MockClocks clocks = new MockClocks();
+ MockClock clocks = new MockClock();
TestTimer timer = new TestTimer(clocks, 0, timeBase);
timer.setCount(1);
@@ -208,7 +207,7 @@
Assert.assertEquals(40, timeBase.getRealtime(200));
// the past uptime is 35 and the past runtime is 40
- MockClocks clocks = new MockClocks();
+ MockClock clocks = new MockClock();
TestTimer timer1 = new TestTimer(clocks, 0, timeBase);
timer1.setCount(1);
@@ -250,7 +249,7 @@
timeBase.setRunning(false, 45, 60);
Assert.assertEquals(40, timeBase.getRealtime(200));
- MockClocks clocks = new MockClocks();
+ MockClock clocks = new MockClock();
TestTimer timer = new TestTimer(clocks, 0, timeBase);
timer.setCount(1);
@@ -275,7 +274,7 @@
timeBase.setRunning(false, 45, 60);
Assert.assertEquals(40, timeBase.getRealtime(200));
- MockClocks clocks = new MockClocks();
+ MockClock clocks = new MockClock();
TestTimer timer = new TestTimer(clocks, 0, timeBase);
timer.setCount(1);
@@ -296,7 +295,7 @@
timeBase.setRunning(false, 45, 60);
Assert.assertEquals(40, timeBase.getRealtime(200));
- MockClocks clocks = new MockClocks();
+ MockClock clocks = new MockClock();
TestTimer timer = new TestTimer(clocks, 0, timeBase);
timer.setCount(1);
@@ -313,7 +312,7 @@
@SmallTest
public void testLogState() throws Exception {
TimeBase timeBase = new TimeBase();
- MockClocks clocks = new MockClocks();
+ MockClock clocks = new MockClock();
TestTimer timer = new TestTimer(clocks, 0, timeBase);
timer.setTotalTime(100);
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsUidTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsUidTest.java
index 4df3190..9270346 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsUidTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsUidTest.java
@@ -27,7 +27,7 @@
private static final String TAG = "BatteryStatsTimeBaseTest";
static class TestBsi extends BatteryStatsImpl {
- TestBsi(MockClocks clocks) {
+ TestBsi(MockClock clocks) {
super(clocks);
}
}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsUserLifecycleTests.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsUserLifecycleTests.java
index e90bcb7..de50dcb 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsUserLifecycleTests.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsUserLifecycleTests.java
@@ -51,6 +51,7 @@
private static final long POLL_INTERVAL_MS = 500;
private static final long USER_REMOVE_TIMEOUT_MS = 5_000;
private static final long STOP_USER_TIMEOUT_MS = 10_000;
+ private static final long USER_UIDS_REMOVE_TIMEOUT_MS = 15_000;
private static final long BATTERYSTATS_POLLING_TIMEOUT_MS = 5_000;
private static final String CPU_DATA_TAG = "cpu";
@@ -78,7 +79,6 @@
}
@Test
- @SkipPresubmit("b/180015146")
public void testNoCpuDataForRemovedUser() throws Exception {
mIam.startUserInBackground(mTestUserId);
waitUntilTrue("No uids for started user " + mTestUserId,
@@ -108,7 +108,7 @@
return true;
}, USER_REMOVE_TIMEOUT_MS);
waitUntilTrue("Uids still found for removed user " + mTestUserId,
- () -> getNumberOfUidsInBatteryStats() == 0, BATTERYSTATS_POLLING_TIMEOUT_MS);
+ () -> getNumberOfUidsInBatteryStats() == 0, USER_UIDS_REMOVE_TIMEOUT_MS);
}
@After
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 083090c..e7fa656 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java
@@ -50,7 +50,7 @@
.build();
private final PowerProfile mPowerProfile;
- private final MockClocks mMockClocks = new MockClocks();
+ private final MockClock mMockClock = new MockClock();
private final MockBatteryStatsImpl mBatteryStats;
private BatteryUsageStats mBatteryUsageStats;
@@ -63,8 +63,8 @@
public BatteryUsageStatsRule(long currentTime) {
Context context = InstrumentationRegistry.getContext();
mPowerProfile = spy(new PowerProfile(context, true /* forTest */));
- mMockClocks.currentTime = currentTime;
- mBatteryStats = new MockBatteryStatsImpl(mMockClocks);
+ mMockClock.currentTime = currentTime;
+ mBatteryStats = new MockBatteryStatsImpl(mMockClock);
mBatteryStats.setPowerProfile(mPowerProfile);
mBatteryStats.onSystemReady();
}
@@ -166,12 +166,12 @@
}
public void setTime(long realtimeMs, long uptimeMs) {
- mMockClocks.realtime = realtimeMs;
- mMockClocks.uptime = uptimeMs;
+ mMockClock.realtime = realtimeMs;
+ mMockClock.uptime = uptimeMs;
}
public void setCurrentTime(long currentTimeMs) {
- mMockClocks.currentTime = currentTimeMs;
+ mMockClock.currentTime = currentTimeMs;
}
BatteryUsageStats apply(PowerCalculator... calculators) {
@@ -191,7 +191,7 @@
}
for (PowerCalculator calculator : calculators) {
- calculator.calculate(builder, mBatteryStats, mMockClocks.realtime, mMockClocks.uptime,
+ calculator.calculate(builder, mBatteryStats, mMockClock.realtime, mMockClock.uptime,
query);
}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsStoreTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsStoreTest.java
index e478cd7..51f20f3 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsStoreTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsStoreTest.java
@@ -47,7 +47,7 @@
public class BatteryUsageStatsStoreTest {
private static final long MAX_BATTERY_STATS_SNAPSHOT_STORAGE_BYTES = 2 * 1024;
- private final MockClocks mMockClocks = new MockClocks();
+ private final MockClock mMockClock = new MockClock();
private MockBatteryStatsImpl mBatteryStats;
private BatteryUsageStatsStore mBatteryUsageStatsStore;
private BatteryUsageStatsProvider mBatteryUsageStatsProvider;
@@ -55,8 +55,8 @@
@Before
public void setup() {
- mMockClocks.currentTime = 123;
- mBatteryStats = new MockBatteryStatsImpl(mMockClocks);
+ mMockClock.currentTime = 123;
+ mBatteryStats = new MockBatteryStatsImpl(mMockClock);
mBatteryStats.setNoAutoReset(true);
mBatteryStats.setPowerProfile(mock(PowerProfile.class));
mBatteryStats.onSystemReady();
@@ -75,7 +75,7 @@
@Test
public void testStoreSnapshot() {
- mMockClocks.currentTime = 1_600_000;
+ mMockClock.currentTime = 1_600_000;
prepareBatteryStats();
mBatteryStats.resetAllStatsCmdLocked();
@@ -99,9 +99,9 @@
public void testGarbageCollectOldSnapshots() throws Exception {
prepareBatteryStats();
- mMockClocks.realtime = 10_000_000;
- mMockClocks.uptime = 10_000_000;
- mMockClocks.currentTime = 10_000_000;
+ mMockClock.realtime = 10_000_000;
+ mMockClock.uptime = 10_000_000;
+ mMockClock.currentTime = 10_000_000;
final int snapshotFileSize = getSnapshotFileSize();
final int numberOfSnapshots =
@@ -109,9 +109,9 @@
for (int i = 0; i < numberOfSnapshots + 2; i++) {
mBatteryStats.resetAllStatsCmdLocked();
- mMockClocks.realtime += 10_000_000;
- mMockClocks.uptime += 10_000_000;
- mMockClocks.currentTime += 10_000_000;
+ mMockClock.realtime += 10_000_000;
+ mMockClock.uptime += 10_000_000;
+ mMockClock.currentTime += 10_000_000;
prepareBatteryStats();
}
@@ -137,11 +137,11 @@
private void prepareBatteryStats() {
mBatteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING, 100,
/* plugType */ 0, 90, 72, 3700, 3_600_000, 4_000_000, 0,
- mMockClocks.realtime, mMockClocks.uptime, mMockClocks.currentTime);
+ mMockClock.realtime, mMockClock.uptime, mMockClock.currentTime);
mBatteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING, 100,
/* plugType */ 0, 85, 72, 3700, 3_000_000, 4_000_000, 0,
- mMockClocks.realtime + 500_000, mMockClocks.uptime + 500_000,
- mMockClocks.currentTime + 500_000);
+ mMockClock.realtime + 500_000, mMockClock.uptime + 500_000,
+ mMockClock.currentTime + 500_000);
}
private void clearDirectory(File dir) {
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 fedbf7a..c58df4e 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java
@@ -228,7 +228,7 @@
}
private BatteryUsageStats.Builder buildBatteryUsageStats1(boolean includeUserBatteryConsumer) {
- final MockClocks clocks = new MockClocks();
+ final MockClock clocks = new MockClock();
final MockBatteryStatsImpl batteryStats = new MockBatteryStatsImpl(clocks);
final BatteryUsageStats.Builder builder =
@@ -267,7 +267,7 @@
}
private BatteryUsageStats.Builder buildBatteryUsageStats2(String[] customPowerComponentNames) {
- final MockClocks clocks = new MockClocks();
+ final MockClock clocks = new MockClock();
final MockBatteryStatsImpl batteryStats = new MockBatteryStatsImpl(clocks);
final BatteryUsageStats.Builder builder =
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidUserSysTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidUserSysTimeReaderTest.java
index 177f348..1da1a90 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidUserSysTimeReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidUserSysTimeReaderTest.java
@@ -23,7 +23,6 @@
import android.content.Context;
import android.os.FileUtils;
-import android.os.SystemClock;
import android.util.SparseArray;
import androidx.test.InstrumentationRegistry;
@@ -56,7 +55,7 @@
private KernelCpuUidTimeReader.KernelCpuUidUserSysTimeReader mReader;
private VerifiableCallback mCallback;
- private Random mRand = new Random(12345);
+ private final Random mRand = new Random(12345);
private final int[] mUids = {0, 1, 22, 333, 4444, 55555};
private final long[][] mInitialTimes = new long[][]{
{15334000, 310964000},
@@ -67,6 +66,8 @@
{47000, 17000}
};
+ private final MockClock mMockClock = new MockClock();
+
private Context getContext() {
return InstrumentationRegistry.getContext();
}
@@ -76,7 +77,8 @@
mTestDir = getContext().getDir("test", Context.MODE_PRIVATE);
mTestFile = new File(mTestDir, "test.file");
mReader = new KernelCpuUidUserSysTimeReader(
- new KernelCpuProcStringReader(mTestFile.getAbsolutePath()), false);
+ new KernelCpuProcStringReader(mTestFile.getAbsolutePath(), mMockClock),
+ false, mMockClock);
mCallback = new VerifiableCallback();
}
@@ -87,10 +89,13 @@
}
@Test
- @SkipPresubmit("b/180015146")
public void testThrottler() throws Exception {
+ mMockClock.realtime = 1000;
+
mReader = new KernelCpuUidUserSysTimeReader(
- new KernelCpuProcStringReader(mTestFile.getAbsolutePath()), true);
+ new KernelCpuProcStringReader(mTestFile.getAbsolutePath(), mMockClock),
+ true, mMockClock);
+
mReader.setThrottle(500);
writeToFile(uidLines(mUids, mInitialTimes));
@@ -103,8 +108,7 @@
mReader.readDelta(false, mCallback);
assertEquals(0, mCallback.mData.size());
- // TODO(b/180473895): Replace sleeps with injected simulated time.
- SystemClock.sleep(600);
+ mMockClock.realtime += 600;
long[][] times2 = increaseTime(times1);
writeToFile(uidLines(mUids, times2));
@@ -123,7 +127,7 @@
mReader.readDelta(true, mCallback);
assertEquals(6, mCallback.mData.size());
- SystemClock.sleep(600);
+ mMockClock.realtime += 600;
long[][] times4 = increaseTime(times3);
writeToFile(uidLines(mUids, times4));
@@ -138,7 +142,7 @@
mReader.readDelta(false, mCallback);
assertEquals(0, mCallback.mData.size());
- SystemClock.sleep(600);
+ mMockClock.realtime += 600;
mCallback.clear();
mReader.readDelta(false, mCallback);
diff --git a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
index 99d576d..c8387cb 100644
--- a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
+++ b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
@@ -36,13 +36,13 @@
* Mocks a BatteryStatsImpl object.
*/
public class MockBatteryStatsImpl extends BatteryStatsImpl {
- public BatteryStatsImpl.Clocks clocks;
+ public Clock mClock;
public boolean mForceOnBattery;
private NetworkStats mNetworkStats;
- MockBatteryStatsImpl(Clocks clocks) {
- super(clocks);
- this.clocks = mClocks;
+ MockBatteryStatsImpl(Clock clock) {
+ super(clock);
+ this.mClock = mClock;
initTimersAndCounters();
setExternalStatsSyncLocked(new DummyExternalStatsSync());
@@ -54,7 +54,7 @@
}
MockBatteryStatsImpl() {
- this(new MockClocks());
+ this(new MockClock());
}
public void initMeasuredEnergyStats() {
@@ -190,6 +190,11 @@
}
@Override
+ public Future<?> scheduleCleanupDueToRemovedUser(int userId) {
+ return null;
+ }
+
+ @Override
public Future<?> scheduleCpuSyncDueToRemovedUid(int uid) {
return null;
}
diff --git a/core/tests/coretests/src/com/android/internal/os/MockClocks.java b/core/tests/coretests/src/com/android/internal/os/MockClock.java
similarity index 94%
rename from core/tests/coretests/src/com/android/internal/os/MockClocks.java
rename to core/tests/coretests/src/com/android/internal/os/MockClock.java
index c26505e..ac69c33 100644
--- a/core/tests/coretests/src/com/android/internal/os/MockClocks.java
+++ b/core/tests/coretests/src/com/android/internal/os/MockClock.java
@@ -16,7 +16,7 @@
package com.android.internal.os;
-public class MockClocks implements BatteryStatsImpl.Clocks {
+public class MockClock extends Clock {
/** ElapsedRealtime in ms */
public long realtime;
/** Uptime in ms */
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 3e37237..8caff23 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -3139,6 +3139,12 @@
"group": "WM_DEBUG_WINDOW_TRANSITIONS",
"at": "com\/android\/server\/wm\/Transition.java"
},
+ "1494644409": {
+ "message": " Rejecting as detached: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/Transition.java"
+ },
"1495525537": {
"message": "createWallpaperAnimations()",
"level": "DEBUG",
diff --git a/graphics/java/android/graphics/HardwareRenderer.java b/graphics/java/android/graphics/HardwareRenderer.java
index 8bc3cae..ac2d0c4 100644
--- a/graphics/java/android/graphics/HardwareRenderer.java
+++ b/graphics/java/android/graphics/HardwareRenderer.java
@@ -28,7 +28,6 @@
import android.hardware.display.DisplayManager;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
-import android.os.PerformanceHintManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
@@ -856,36 +855,6 @@
callback.onPictureCaptured(picture);
}
- /** called by native */
- static PerformanceHintManager.Session createHintSession(int[] tids) {
- PerformanceHintManager performanceHintManager =
- ProcessInitializer.sInstance.getHintManager();
- if (performanceHintManager == null) {
- return null;
- }
- // Native code will always set a target duration before reporting actual durations.
- // So this is just a placeholder value that's never used.
- long targetDurationNanos = 16666667;
- return performanceHintManager.createHintSession(tids, targetDurationNanos);
- }
-
- /** called by native */
- static void updateTargetWorkDuration(PerformanceHintManager.Session session,
- long targetDurationNanos) {
- session.updateTargetWorkDuration(targetDurationNanos);
- }
-
- /** called by native */
- static void reportActualWorkDuration(PerformanceHintManager.Session session,
- long actualDurationNanos) {
- session.reportActualWorkDuration(actualDurationNanos);
- }
-
- /** called by native */
- static void closeHintSession(PerformanceHintManager.Session session) {
- session.close();
- }
-
/**
* Interface used to receive callbacks when Webview requests a surface control.
*
@@ -1189,7 +1158,6 @@
private boolean mIsolated = false;
private Context mContext;
private String mPackageName;
- private PerformanceHintManager mPerformanceHintManager;
private IGraphicsStats mGraphicsStatsService;
private IGraphicsStatsCallback mGraphicsStatsCallback = new IGraphicsStatsCallback.Stub() {
@Override
@@ -1201,10 +1169,6 @@
private ProcessInitializer() {
}
- synchronized PerformanceHintManager getHintManager() {
- return mPerformanceHintManager;
- }
-
synchronized void setPackageName(String name) {
if (mInitialized) return;
mPackageName = name;
@@ -1255,10 +1219,6 @@
initDisplayInfo();
- // HintManager and HintSession are designed to be accessible from isoalted processes
- // so not checking for isolated process here.
- initHintSession();
-
nSetIsHighEndGfx(ActivityManager.isHighEndGfx());
// Defensively clear out the context in case we were passed a context that can leak
// if we live longer than it, e.g. an activity context.
@@ -1302,11 +1262,6 @@
mDisplayInitialized = true;
}
- private void initHintSession() {
- if (mContext == null) return;
- mPerformanceHintManager = mContext.getSystemService(PerformanceHintManager.class);
- }
-
private void rotateBuffer() {
nRotateProcessStatsBuffer();
requestBuffer();
diff --git a/graphics/java/android/graphics/text/TextRunShaper.java b/graphics/java/android/graphics/text/TextRunShaper.java
index 8459e7b..19ea04a 100644
--- a/graphics/java/android/graphics/text/TextRunShaper.java
+++ b/graphics/java/android/graphics/text/TextRunShaper.java
@@ -24,8 +24,6 @@
import com.android.internal.util.Preconditions;
-import dalvik.annotation.optimization.FastNative;
-
/**
* Provides conversion from a text into glyph array.
*
@@ -116,12 +114,10 @@
}
}
- @FastNative
private static native long nativeShapeTextRun(
char[] text, int start, int count, int contextStart, int contextCount,
boolean isRtl, long nativePaint);
- @FastNative
private static native long nativeShapeTextRun(
String text, int start, int count, int contextStart, int contextCount,
boolean isRtl, long nativePaint);
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/SampleExtensionImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/SampleExtensionImpl.java
index a0d5b00..cafc233 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/SampleExtensionImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/SampleExtensionImpl.java
@@ -23,15 +23,19 @@
import android.app.Activity;
import android.content.Context;
+import android.content.Intent;
import android.graphics.Rect;
+import android.os.Bundle;
import android.util.Log;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.window.common.DeviceStateManagerPostureProducer;
import androidx.window.common.DisplayFeature;
import androidx.window.common.ResourceConfigDisplayFeatureProducer;
import androidx.window.common.SettingsDevicePostureProducer;
import androidx.window.common.SettingsDisplayFeatureProducer;
+import androidx.window.extensions.organizer.SplitController;
import androidx.window.util.DataProducer;
import androidx.window.util.PriorityDataProducer;
@@ -56,6 +60,8 @@
private final SettingsDisplayFeatureProducer mSettingsDisplayFeatureProducer;
private final DataProducer<List<DisplayFeature>> mDisplayFeatureProducer;
+ private final SplitController mSplitController;
+
SampleExtensionImpl(Context context) {
mSettingsDevicePostureProducer = new SettingsDevicePostureProducer(context);
mDevicePostureProducer = new PriorityDataProducer<>(List.of(
@@ -71,6 +77,8 @@
mDevicePostureProducer.addDataChangedCallback(this::onDisplayFeaturesChanged);
mDisplayFeatureProducer.addDataChangedCallback(this::onDisplayFeaturesChanged);
+
+ mSplitController = new SplitController();
}
private int getFeatureState(DisplayFeature feature) {
@@ -134,4 +142,28 @@
onDisplayFeaturesChanged();
}
+
+ @Override
+ public void setSplitRules(@NonNull List<ExtensionSplitRule> splitRules) {
+ mSplitController.setSplitRules(splitRules);
+ }
+
+ @Override
+ @NonNull
+ public List<ExtensionSplitRule> getSplitRules() {
+ return new ArrayList<>(mSplitController.getSplitRules());
+ }
+
+ @Override
+ public void setSplitOrganizerCallback(@Nullable SplitOrganizerCallback callback) {
+ mSplitController.setSplitOrganizerCallback(callback);
+ }
+
+ @Override
+ public void startActivityToSide(@NonNull Activity launchingActivity, @NonNull Intent intent,
+ @Nullable Bundle options, @NonNull ExtensionSplitPairRule splitPairRule,
+ int startRequestId) {
+ mSplitController.startActivityToSide(launchingActivity, intent, options, splitPairRule,
+ startRequestId);
+ }
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/JetpackTaskFragmentOrganizer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/JetpackTaskFragmentOrganizer.java
new file mode 100644
index 0000000..d84554b
--- /dev/null
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/JetpackTaskFragmentOrganizer.java
@@ -0,0 +1,261 @@
+/*
+ * 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 androidx.window.extensions.organizer;
+
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+
+import android.app.Activity;
+import android.app.WindowConfiguration.WindowingMode;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.util.ArrayMap;
+import android.view.SurfaceControl;
+import android.window.TaskFragmentAppearedInfo;
+import android.window.TaskFragmentCreationParams;
+import android.window.TaskFragmentInfo;
+import android.window.TaskFragmentOrganizer;
+import android.window.WindowContainerTransaction;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.Map;
+import java.util.concurrent.Executor;
+
+/**
+ * Platform default Extensions implementation of {@link TaskFragmentOrganizer} to organize
+ * task fragments.
+ *
+ * All calls into methods of this class are expected to be on the UI thread.
+ */
+class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {
+
+ /** Mapping from the client assigned unique token to the {@link TaskFragmentInfo}. */
+ private final Map<IBinder, TaskFragmentInfo> mFragmentInfos = new ArrayMap<>();
+
+ /** Mapping from the client assigned unique token to the TaskFragment {@link SurfaceControl}. */
+ private final Map<IBinder, SurfaceControl> mFragmentLeashes = new ArrayMap<>();
+
+ /**
+ * Mapping from the client assigned unique token to the TaskFragment parent
+ * {@link Configuration}.
+ */
+ final Map<IBinder, Configuration> mFragmentParentConfigs = new ArrayMap<>();
+
+ private final TaskFragmentCallback mCallback;
+
+ /**
+ * Callback that notifies the controller about changes to task fragments.
+ */
+ interface TaskFragmentCallback {
+ void onTaskFragmentAppeared(@NonNull TaskFragmentAppearedInfo taskFragmentAppearedInfo);
+ void onTaskFragmentInfoChanged(@NonNull TaskFragmentInfo taskFragmentInfo);
+ void onTaskFragmentVanished(@NonNull TaskFragmentInfo taskFragmentInfo);
+ void onTaskFragmentParentInfoChanged(@NonNull IBinder fragmentToken,
+ @NonNull Configuration parentConfig);
+ }
+
+ /**
+ * @param executor callbacks from WM Core are posted on this executor. It should be tied to the
+ * UI thread that all other calls into methods of this class are also on.
+ */
+ JetpackTaskFragmentOrganizer(@NonNull Executor executor, TaskFragmentCallback callback) {
+ super(executor);
+ mCallback = callback;
+ }
+
+ /**
+ * Starts a new Activity and puts it into split with an existing Activity side-by-side.
+ * @param launchingFragmentToken token for the launching TaskFragment. If it exists, it will
+ * be resized based on {@param launchingFragmentBounds}.
+ * Otherwise, we will create a new TaskFragment with the given
+ * token for the {@param launchingActivity}.
+ * @param launchingFragmentBounds the initial bounds for the launching TaskFragment.
+ * @param launchingActivity the Activity to put on the left hand side of the split as the
+ * primary.
+ * @param secondaryFragmentToken token to create the secondary TaskFragment with.
+ * @param secondaryFragmentBounds the initial bounds for the secondary TaskFragment
+ * @param activityIntent Intent to start the secondary Activity with.
+ * @param activityOptions ActivityOptions to start the secondary Activity with.
+ */
+ void startActivityToSide(IBinder launchingFragmentToken, Rect launchingFragmentBounds,
+ Activity launchingActivity, IBinder secondaryFragmentToken,
+ Rect secondaryFragmentBounds, Intent activityIntent,
+ @Nullable Bundle activityOptions) {
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ final IBinder ownerToken = launchingActivity.getActivityToken();
+
+ // Create or resize the launching TaskFragment.
+ if (mFragmentInfos.containsKey(launchingFragmentToken)) {
+ resizeTaskFragment(wct, launchingFragmentToken, launchingFragmentBounds);
+ } else {
+ createTaskFragmentAndReparentActivity(wct, launchingFragmentToken, ownerToken,
+ launchingFragmentBounds, WINDOWING_MODE_MULTI_WINDOW, launchingActivity);
+ }
+
+ // Create a TaskFragment for the secondary activity.
+ createTaskFragmentAndStartActivity(wct, secondaryFragmentToken, ownerToken,
+ secondaryFragmentBounds, WINDOWING_MODE_MULTI_WINDOW, activityIntent,
+ activityOptions);
+
+ applyTransaction(wct);
+ }
+
+ /**
+ * Expands an existing TaskFragment to fill parent.
+ * @param wct WindowContainerTransaction in which the task fragment should be resized.
+ * @param fragmentToken token of an existing TaskFragment.
+ */
+ void expandTaskFragment(WindowContainerTransaction wct, IBinder fragmentToken) {
+ resizeTaskFragment(wct, fragmentToken, new Rect());
+ }
+
+ /**
+ * Expands an existing TaskFragment to fill parent.
+ * @param fragmentToken token of an existing TaskFragment.
+ */
+ void expandTaskFragment(IBinder fragmentToken) {
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ expandTaskFragment(wct, fragmentToken);
+ applyTransaction(wct);
+ }
+
+ /**
+ * Expands an Activity to fill parent by moving it to a new TaskFragment.
+ * @param fragmentToken token to create new TaskFragment with.
+ * @param activity activity to move to the fill-parent TaskFragment.
+ */
+ void expandActivity(IBinder fragmentToken, Activity activity) {
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ createTaskFragmentAndReparentActivity(
+ wct, fragmentToken, activity.getActivityToken(), new Rect(),
+ WINDOWING_MODE_UNDEFINED, activity);
+ applyTransaction(wct);
+ }
+
+ /**
+ * @param ownerToken The token of the activity that creates this task fragment. It does not
+ * have to be a child of this task fragment, but must belong to the same task.
+ */
+ private void createTaskFragmentAndReparentActivity(
+ WindowContainerTransaction wct, IBinder fragmentToken, IBinder ownerToken,
+ @NonNull Rect bounds, @WindowingMode int windowingMode, Activity activity) {
+ final TaskFragmentCreationParams fragmentOptions =
+ createFragmentOptions(fragmentToken, ownerToken, bounds, windowingMode);
+ wct.createTaskFragment(fragmentOptions)
+ .reparentActivityToTaskFragment(fragmentToken, activity.getActivityToken());
+ }
+
+ /**
+ * @param ownerToken The token of the activity that creates this task fragment. It does not
+ * have to be a child of this task fragment, but must belong to the same task.
+ */
+ private void createTaskFragmentAndStartActivity(
+ WindowContainerTransaction wct, IBinder fragmentToken, IBinder ownerToken,
+ @NonNull Rect bounds, @WindowingMode int windowingMode, Intent activityIntent,
+ @Nullable Bundle activityOptions) {
+ final TaskFragmentCreationParams fragmentOptions =
+ createFragmentOptions(fragmentToken, ownerToken, bounds, windowingMode);
+ wct.createTaskFragment(fragmentOptions)
+ .startActivityInTaskFragment(fragmentToken, ownerToken, activityIntent,
+ activityOptions);
+ }
+
+ TaskFragmentCreationParams createFragmentOptions(IBinder fragmentToken, IBinder ownerToken,
+ Rect bounds, @WindowingMode int windowingMode) {
+ if (mFragmentInfos.containsKey(fragmentToken)) {
+ throw new IllegalArgumentException(
+ "There is an existing TaskFragment with fragmentToken=" + fragmentToken);
+ }
+
+ return new TaskFragmentCreationParams.Builder(
+ getIOrganizer(),
+ fragmentToken,
+ ownerToken)
+ .setInitialBounds(bounds)
+ .setWindowingMode(windowingMode)
+ .build();
+ }
+
+ void resizeTaskFragment(WindowContainerTransaction wct, IBinder fragmentToken,
+ @Nullable Rect bounds) {
+ if (!mFragmentInfos.containsKey(fragmentToken)) {
+ throw new IllegalArgumentException(
+ "Can't find an existing TaskFragment with fragmentToken=" + fragmentToken);
+ }
+ if (bounds == null) {
+ bounds = new Rect();
+ }
+ wct.setBounds(mFragmentInfos.get(fragmentToken).getToken(), bounds);
+ }
+
+ void deleteTaskFragment(WindowContainerTransaction wct, IBinder fragmentToken) {
+ if (!mFragmentInfos.containsKey(fragmentToken)) {
+ throw new IllegalArgumentException(
+ "Can't find an existing TaskFragment with fragmentToken=" + fragmentToken);
+ }
+ wct.deleteTaskFragment(mFragmentInfos.get(fragmentToken).getToken());
+ }
+
+ @Override
+ public void onTaskFragmentAppeared(@NonNull TaskFragmentAppearedInfo taskFragmentAppearedInfo) {
+ final TaskFragmentInfo info = taskFragmentAppearedInfo.getTaskFragmentInfo();
+ final IBinder fragmentToken = info.getFragmentToken();
+ final SurfaceControl leash = taskFragmentAppearedInfo.getLeash();
+ mFragmentInfos.put(fragmentToken, info);
+ mFragmentLeashes.put(fragmentToken, leash);
+
+ if (mCallback != null) {
+ mCallback.onTaskFragmentAppeared(taskFragmentAppearedInfo);
+ }
+ }
+
+ @Override
+ public void onTaskFragmentInfoChanged(@NonNull TaskFragmentInfo taskFragmentInfo) {
+ final IBinder fragmentToken = taskFragmentInfo.getFragmentToken();
+ mFragmentInfos.put(fragmentToken, taskFragmentInfo);
+
+ if (mCallback != null) {
+ mCallback.onTaskFragmentInfoChanged(taskFragmentInfo);
+ }
+ }
+
+ @Override
+ public void onTaskFragmentVanished(@NonNull TaskFragmentInfo taskFragmentInfo) {
+ mFragmentInfos.remove(taskFragmentInfo.getFragmentToken());
+ mFragmentLeashes.remove(taskFragmentInfo.getFragmentToken());
+ mFragmentParentConfigs.remove(taskFragmentInfo.getFragmentToken());
+
+ if (mCallback != null) {
+ mCallback.onTaskFragmentVanished(taskFragmentInfo);
+ }
+ }
+
+ @Override
+ public void onTaskFragmentParentInfoChanged(
+ @NonNull IBinder fragmentToken, @NonNull Configuration parentConfig) {
+ mFragmentParentConfigs.put(fragmentToken, parentConfig);
+
+ if (mCallback != null) {
+ mCallback.onTaskFragmentParentInfoChanged(fragmentToken, parentConfig);
+ }
+ }
+}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitContainer.java
new file mode 100644
index 0000000..ade8573
--- /dev/null
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitContainer.java
@@ -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.
+ */
+
+package androidx.window.extensions.organizer;
+
+import android.annotation.NonNull;
+import android.app.Activity;
+
+import androidx.window.extensions.ExtensionSplitPairRule;
+
+/**
+ * Client-side descriptor of a split that holds two containers.
+ */
+class SplitContainer {
+ private final TaskFragmentContainer mPrimaryContainer;
+ private final TaskFragmentContainer mSecondaryContainer;
+ private final ExtensionSplitPairRule mSplitPairRule;
+
+ SplitContainer(@NonNull TaskFragmentContainer primaryContainer,
+ @NonNull Activity primaryActivity,
+ @NonNull TaskFragmentContainer secondaryContainer,
+ @NonNull ExtensionSplitPairRule splitPairRule) {
+ mPrimaryContainer = primaryContainer;
+ mSecondaryContainer = secondaryContainer;
+ mSplitPairRule = splitPairRule;
+
+ if (mSplitPairRule.finishPrimaryWithSecondary || mSplitPairRule.useAsPlaceholder) {
+ mSecondaryContainer.addActivityToFinishOnExit(primaryActivity);
+ }
+ if (mSplitPairRule.finishSecondaryWithPrimary || mSplitPairRule.useAsPlaceholder) {
+ mPrimaryContainer.addContainerToFinishOnExit(mSecondaryContainer);
+ }
+ }
+
+ @NonNull
+ TaskFragmentContainer getPrimaryContainer() {
+ return mPrimaryContainer;
+ }
+
+ @NonNull
+ TaskFragmentContainer getSecondaryContainer() {
+ return mSecondaryContainer;
+ }
+
+ @NonNull
+ ExtensionSplitPairRule getSplitPairRule() {
+ return mSplitPairRule;
+ }
+}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitController.java
new file mode 100644
index 0000000..7298d34
--- /dev/null
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitController.java
@@ -0,0 +1,580 @@
+/*
+ * 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 androidx.window.extensions.organizer;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.Activity;
+import android.app.ActivityClient;
+import android.app.ActivityThread;
+import android.app.Application.ActivityLifecycleCallbacks;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.window.TaskFragmentAppearedInfo;
+import android.window.TaskFragmentInfo;
+import android.window.WindowContainerTransaction;
+
+import androidx.window.extensions.ExtensionInterface.SplitOrganizerCallback;
+import androidx.window.extensions.ExtensionSplitActivityRule;
+import androidx.window.extensions.ExtensionSplitInfo;
+import androidx.window.extensions.ExtensionSplitPairRule;
+import androidx.window.extensions.ExtensionSplitRule;
+import androidx.window.extensions.ExtensionTaskFragment;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Main controller class that manages split states and presentation.
+ */
+public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmentCallback {
+
+ private final SplitPresenter mPresenter;
+
+ // Currently applied split configuration.
+ private final List<ExtensionSplitRule> mSplitRules = new ArrayList<>();
+ private final List<TaskFragmentContainer> mContainers = new ArrayList<>();
+ private final List<SplitContainer> mSplitContainers = new ArrayList<>();
+
+ // Callback to Jetpack to notify about changes to split states.
+ private SplitOrganizerCallback mSplitOrganizerCallback;
+
+ public SplitController() {
+ mPresenter = new SplitPresenter(ActivityThread.currentActivityThread().getExecutor(),
+ this);
+ // Register a callback to be notified about activities being created.
+ ActivityThread.currentActivityThread().getApplication().registerActivityLifecycleCallbacks(
+ new LifecycleCallbacks());
+ }
+
+ public void setSplitRules(@NonNull List<ExtensionSplitRule> splitRules) {
+ mSplitRules.clear();
+ mSplitRules.addAll(splitRules);
+ }
+
+ @NonNull
+ public List<ExtensionSplitRule> getSplitRules() {
+ return mSplitRules;
+ }
+
+ /**
+ * Starts an activity to side of the launchingActivity with the provided split config.
+ */
+ public void startActivityToSide(@NonNull Activity launchingActivity, @NonNull Intent intent,
+ @Nullable Bundle options, @NonNull ExtensionSplitPairRule splitPairRule,
+ int startRequestId) {
+ try {
+ mPresenter.startActivityToSide(launchingActivity, intent, options, splitPairRule);
+ } catch (Exception e) {
+ if (mSplitOrganizerCallback != null && startRequestId != -1) {
+ mSplitOrganizerCallback.onActivityFailedToStartInContainer(startRequestId, e);
+ }
+ }
+ }
+
+ /**
+ * Registers the split organizer callback to notify about changes to active splits.
+ */
+ public void setSplitOrganizerCallback(@NonNull SplitOrganizerCallback callback) {
+ mSplitOrganizerCallback = callback;
+ updateCallbackIfNecessary();
+ }
+
+ @Override
+ public void onTaskFragmentAppeared(@NonNull TaskFragmentAppearedInfo taskFragmentAppearedInfo) {
+ for (TaskFragmentContainer container : mContainers) {
+ if (container.getTaskFragmentToken().equals(
+ taskFragmentAppearedInfo.getTaskFragmentInfo().getFragmentToken())) {
+ container.setInfo(taskFragmentAppearedInfo.getTaskFragmentInfo());
+ return;
+ }
+ }
+ }
+
+ @Override
+ public void onTaskFragmentInfoChanged(@NonNull TaskFragmentInfo taskFragmentInfo) {
+ for (TaskFragmentContainer container : mContainers) {
+ if (container.getTaskFragmentToken().equals(taskFragmentInfo.getFragmentToken())) {
+ container.setInfo(taskFragmentInfo);
+
+ if (taskFragmentInfo.isEmpty()) {
+ cleanupContainer(container, true /* shouldFinishDependent */);
+ updateCallbackIfNecessary();
+ }
+ return;
+ }
+ }
+ }
+
+ @Override
+ public void onTaskFragmentVanished(@NonNull TaskFragmentInfo taskFragmentInfo) {
+ for (TaskFragmentContainer container : mContainers) {
+ if (container.getTaskFragmentToken().equals(taskFragmentInfo.getFragmentToken())) {
+ cleanupContainer(container, true /* shouldFinishDependent */);
+ updateCallbackIfNecessary();
+ return;
+ }
+ }
+ }
+
+ @Override
+ public void onTaskFragmentParentInfoChanged(@NonNull IBinder fragmentToken,
+ @NonNull Configuration parentConfig) {
+ TaskFragmentContainer container = getContainer(fragmentToken);
+ if (container != null) {
+ mPresenter.updateContainer(container);
+ updateCallbackIfNecessary();
+ }
+ }
+
+ /**
+ * Checks if the activity start should be routed to a particular container. It can create a new
+ * container for the activity and a new split container if necessary.
+ */
+ void onActivityCreated(@NonNull Activity launchedActivity) {
+ final ComponentName componentName = launchedActivity.getComponentName();
+
+ final List<ExtensionSplitRule> splitRules = getSplitRules();
+ final TaskFragmentContainer currentContainer = getContainerWithActivity(
+ launchedActivity.getActivityToken());
+
+ // Check if the activity is configured to always be expanded.
+ if (shouldExpand(componentName, splitRules)) {
+ if (shouldContainerBeExpanded(currentContainer)) {
+ // Make sure that the existing container is expanded
+ mPresenter.expandTaskFragment(currentContainer.getTaskFragmentToken());
+ } else {
+ // Put activity into a new expanded container
+ final TaskFragmentContainer newContainer = newContainer(launchedActivity);
+ mPresenter.expandActivity(newContainer.getTaskFragmentToken(),
+ launchedActivity);
+ }
+ return;
+ }
+
+ // Check if activity requires a placeholder
+ if (launchPlaceholderIfNecessary(launchedActivity)) {
+ return;
+ }
+
+ // TODO(b/190433398): Check if it is a placeholder and there is already another split
+ // created by the primary activity. This is necessary for the case when the primary activity
+ // launched another secondary in the split, but the placeholder was still launched by the
+ // logic above. We didn't prevent the placeholder launcher because we didn't know that
+ // another secondary activity is coming up.
+
+ // Check if the activity should form a split with the activity below in the same task
+ // fragment.
+ Activity activityBelow = null;
+ if (currentContainer != null) {
+ final List<Activity> containerActivities = currentContainer.collectActivities();
+ final int index = containerActivities.indexOf(launchedActivity);
+ if (index > 0) {
+ activityBelow = containerActivities.get(index - 1);
+ }
+ }
+ if (activityBelow == null) {
+ IBinder belowToken = ActivityClient.getInstance().getActivityTokenBelow(
+ launchedActivity.getActivityToken());
+ if (belowToken != null) {
+ activityBelow = ActivityThread.currentActivityThread().getActivity(belowToken);
+ }
+ }
+ if (activityBelow == null) {
+ return;
+ }
+
+ final ExtensionSplitPairRule splitPairRule = getSplitRule(
+ activityBelow.getComponentName(), componentName, splitRules);
+ if (splitPairRule == null) {
+ return;
+ }
+
+ mPresenter.createNewSplitContainer(activityBelow, launchedActivity,
+ splitPairRule);
+
+ updateCallbackIfNecessary();
+ }
+
+ /**
+ * Returns a container that this activity is registered with. An activity can only belong to one
+ * container, or no container at all.
+ */
+ @Nullable
+ TaskFragmentContainer getContainerWithActivity(@NonNull IBinder activityToken) {
+ for (TaskFragmentContainer container : mContainers) {
+ if (container.hasActivity(activityToken)) {
+ return container;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Creates and registers a new organized container with an optional activity that will be
+ * re-parented to it in a WCT.
+ */
+ TaskFragmentContainer newContainer(@Nullable Activity activity) {
+ TaskFragmentContainer container = new TaskFragmentContainer(activity);
+ mContainers.add(container);
+ return container;
+ }
+
+ /**
+ * Creates and registers a new split with the provided containers and configuration.
+ */
+ void registerSplit(@NonNull TaskFragmentContainer primaryContainer,
+ @NonNull Activity primaryActivity,
+ @NonNull TaskFragmentContainer secondaryContainer,
+ @NonNull ExtensionSplitPairRule splitPairRule) {
+ SplitContainer splitContainer = new SplitContainer(primaryContainer, primaryActivity,
+ secondaryContainer, splitPairRule);
+ mSplitContainers.add(splitContainer);
+ }
+
+ void cleanupContainer(@NonNull TaskFragmentContainer container, boolean shouldFinishDependent) {
+ if (container.isFinished()) {
+ return;
+ }
+
+ container.finish(shouldFinishDependent);
+
+ // Remove all split containers that included this one
+ mContainers.remove(container);
+ List<SplitContainer> containersToRemove = new ArrayList<>();
+ for (SplitContainer splitContainer : mSplitContainers) {
+ if (container.equals(splitContainer.getSecondaryContainer())
+ || container.equals(splitContainer.getPrimaryContainer())) {
+ containersToRemove.add(splitContainer);
+ }
+ }
+ mSplitContainers.removeAll(containersToRemove);
+
+ mPresenter.deleteContainer(container);
+ }
+
+ /**
+ * Returns the topmost not finished container.
+ */
+ @Nullable
+ TaskFragmentContainer getTopActiveContainer() {
+ for (int i = mContainers.size() - 1; i >= 0; i--) {
+ TaskFragmentContainer container = mContainers.get(i);
+ if (!container.isFinished()) {
+ return container;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Updates the presentation of the container. If the container is part of the split or should
+ * have a placeholder, it will also update the other part of the split.
+ */
+ void updateContainer(@NonNull WindowContainerTransaction wct,
+ @NonNull TaskFragmentContainer container) {
+ if (launchPlaceholderIfNecessary(container)) {
+ // Placeholder was launched, the positions will be updated when the activity is added
+ // to the secondary container.
+ return;
+ }
+ if (shouldContainerBeExpanded(container)) {
+ if (container.getInfo() != null) {
+ mPresenter.expandTaskFragment(wct, container.getTaskFragmentToken());
+ }
+ // If the info is not available yet the task fragment will be expanded when it's ready
+ return;
+ }
+ SplitContainer splitContainer = getActiveSplitForContainer(container);
+ if (splitContainer == null) {
+ return;
+ }
+ if (splitContainer != mSplitContainers.get(mSplitContainers.size() - 1)) {
+ // Skip position update - it isn't the topmost split.
+ return;
+ }
+ if (splitContainer.getPrimaryContainer().isEmpty()
+ || splitContainer.getSecondaryContainer().isEmpty()) {
+ // Skip position update - one or both containers are empty.
+ return;
+ }
+ if (dismissPlaceholderIfNecessary(splitContainer)) {
+ // Placeholder was finished, the positions will be updated when its container is emptied
+ return;
+ }
+ mPresenter.updateSplitContainer(splitContainer, container, wct);
+ }
+
+ /**
+ * Returns the top active split container that has the provided container.
+ */
+ @Nullable
+ private SplitContainer getActiveSplitForContainer(@NonNull TaskFragmentContainer container) {
+ for (int i = mSplitContainers.size() - 1; i >= 0; i--) {
+ SplitContainer splitContainer = mSplitContainers.get(i);
+ if (container.equals(splitContainer.getSecondaryContainer())
+ || container.equals(splitContainer.getPrimaryContainer())) {
+ return splitContainer;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Checks if the container requires a placeholder and launches it if necessary.
+ */
+ private boolean launchPlaceholderIfNecessary(@NonNull TaskFragmentContainer container) {
+ final Activity topActivity = container.getTopNonFinishingActivity();
+ if (topActivity == null) {
+ return false;
+ }
+
+ return launchPlaceholderIfNecessary(topActivity);
+ }
+
+ boolean launchPlaceholderIfNecessary(@NonNull Activity activity) {
+ final TaskFragmentContainer container = getContainerWithActivity(
+ activity.getActivityToken());
+
+ SplitContainer splitContainer = container != null ? getActiveSplitForContainer(container)
+ : null;
+ if (splitContainer != null && container.equals(splitContainer.getPrimaryContainer())) {
+ // Don't launch placeholder in primary split container
+ return false;
+ }
+
+ // Check if there is enough space for launch
+ final ExtensionSplitPairRule placeholderRule = getPlaceholderRule(
+ activity.getComponentName());
+ if (placeholderRule == null || !mPresenter.shouldShowSideBySide(
+ mPresenter.getParentContainerBounds(activity), placeholderRule)) {
+ return false;
+ }
+
+ Intent placeholderIntent = new Intent();
+ placeholderIntent.setComponent(placeholderRule.secondaryActivityName);
+ // TODO(b/190433398): Handle failed request
+ startActivityToSide(activity, placeholderIntent, null, placeholderRule, -1);
+ return true;
+ }
+
+ private boolean dismissPlaceholderIfNecessary(@NonNull SplitContainer splitContainer) {
+ if (!splitContainer.getSplitPairRule().useAsPlaceholder) {
+ return false;
+ }
+
+ if (mPresenter.shouldShowSideBySide(splitContainer)) {
+ return false;
+ }
+
+ cleanupContainer(splitContainer.getSecondaryContainer(),
+ false /* shouldFinishDependent */);
+ return true;
+ }
+
+ /**
+ * Returns the rule to launch a placeholder for the activity with the provided component name
+ * if it is configured in the split config.
+ */
+ private ExtensionSplitPairRule getPlaceholderRule(@NonNull ComponentName componentName) {
+ for (ExtensionSplitRule rule : mSplitRules) {
+ if (!(rule instanceof ExtensionSplitPairRule)) {
+ continue;
+ }
+ ExtensionSplitPairRule pairRule = (ExtensionSplitPairRule) rule;
+ if (componentName.equals(pairRule.primaryActivityName)
+ && pairRule.useAsPlaceholder) {
+ return pairRule;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Notifies listeners about changes to split states if necessary.
+ */
+ private void updateCallbackIfNecessary() {
+ if (mSplitOrganizerCallback == null) {
+ return;
+ }
+ // TODO(b/190433398): Check if something actually changed
+ mSplitOrganizerCallback.onSplitInfoChanged(getActiveSplitStates());
+ }
+
+ /**
+ * Returns a list of descriptors for currently active split states.
+ */
+ private List<ExtensionSplitInfo> getActiveSplitStates() {
+ List<ExtensionSplitInfo> splitStates = new ArrayList<>();
+ for (SplitContainer container : mSplitContainers) {
+ ExtensionTaskFragment primaryContainer =
+ new ExtensionTaskFragment(
+ container.getPrimaryContainer().collectActivities());
+ ExtensionTaskFragment secondaryContainer =
+ new ExtensionTaskFragment(
+ container.getSecondaryContainer().collectActivities());
+ ExtensionSplitInfo splitState = new ExtensionSplitInfo(primaryContainer,
+ secondaryContainer, container.getSplitPairRule().splitRatio);
+ splitStates.add(splitState);
+ }
+ return splitStates;
+ }
+
+ /**
+ * Returns {@code true} if the container is expanded to occupy full task size.
+ * Returns {@code false} if the container is included in an active split.
+ */
+ boolean shouldContainerBeExpanded(@Nullable TaskFragmentContainer container) {
+ if (container == null) {
+ return false;
+ }
+ for (SplitContainer splitContainer : mSplitContainers) {
+ if (container.equals(splitContainer.getPrimaryContainer())
+ || container.equals(splitContainer.getSecondaryContainer())) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Returns a split rule for the provided pair of component names if available.
+ */
+ @Nullable
+ private static ExtensionSplitPairRule getSplitRule(@NonNull ComponentName primaryActivityName,
+ @NonNull ComponentName secondaryActivityName,
+ @NonNull List<ExtensionSplitRule> splitRules) {
+ if (splitRules == null || primaryActivityName == null || secondaryActivityName == null) {
+ return null;
+ }
+
+ for (ExtensionSplitRule rule : splitRules) {
+ if (!(rule instanceof ExtensionSplitPairRule)) {
+ continue;
+ }
+ ExtensionSplitPairRule pairRule = (ExtensionSplitPairRule) rule;
+ if (match(secondaryActivityName, pairRule.secondaryActivityName)
+ && match(primaryActivityName, pairRule.primaryActivityName)) {
+ return pairRule;
+ }
+ }
+ return null;
+ }
+
+ @Nullable
+ private TaskFragmentContainer getContainer(@NonNull IBinder fragmentToken) {
+ for (TaskFragmentContainer container : mContainers) {
+ if (container.getTaskFragmentToken().equals(fragmentToken)) {
+ return container;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns {@code true} if an Activity with the provided component name should always be
+ * expanded to occupy full task bounds. Such activity must not be put in a split.
+ */
+ private static boolean shouldExpand(@NonNull ComponentName componentName,
+ List<ExtensionSplitRule> splitRules) {
+ if (splitRules == null) {
+ return false;
+ }
+ for (ExtensionSplitRule rule : splitRules) {
+ if (!(rule instanceof ExtensionSplitActivityRule)) {
+ continue;
+ }
+ ExtensionSplitActivityRule activityRule = (ExtensionSplitActivityRule) rule;
+ if (match(componentName, activityRule.activityName)
+ && activityRule.alwaysExpand) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /** Match check allowing wildcards for activity class name but not package name. */
+ private static boolean match(@NonNull ComponentName activityComponent,
+ @NonNull ComponentName ruleComponent) {
+ if (activityComponent.toString().contains("*")) {
+ throw new IllegalArgumentException("Wildcard can only be part of the rule.");
+ }
+ final boolean packagesMatch =
+ activityComponent.getPackageName().equals(ruleComponent.getPackageName());
+ final boolean classesMatch =
+ activityComponent.getClassName().equals(ruleComponent.getClassName());
+ return packagesMatch && (classesMatch
+ || wildcardMatch(activityComponent.getClassName(), ruleComponent.getClassName()));
+ }
+
+ /**
+ * Checks if the provided name matches the pattern.
+ */
+ private static boolean wildcardMatch(@NonNull String name, @NonNull String pattern) {
+ if (!pattern.contains("*")) {
+ return false;
+ }
+ if (pattern.equals("*")) {
+ return true;
+ }
+ if (pattern.indexOf("*") != pattern.lastIndexOf("*") || !pattern.endsWith("*")) {
+ throw new IllegalArgumentException(
+ "Name pattern with a wildcard must only contain a single * in the end");
+ }
+ return name.startsWith(pattern.substring(0, pattern.length() - 1));
+ }
+
+ private final class LifecycleCallbacks implements ActivityLifecycleCallbacks {
+
+ @Override
+ public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
+ // Calling after Activity#onCreate is complete to allow the app launch something
+ // first. In case of a configured placeholder activity we want to make sure
+ // that we don't launch it if an activity itself already requested something to be
+ // launched to side.
+ SplitController.this.onActivityCreated(activity);
+ }
+
+ @Override
+ public void onActivityStarted(Activity activity) {
+ }
+
+ @Override
+ public void onActivityResumed(Activity activity) {
+ }
+
+ @Override
+ public void onActivityPaused(Activity activity) {
+ }
+
+ @Override
+ public void onActivityStopped(Activity activity) {
+ }
+
+ @Override
+ public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
+ }
+
+ @Override
+ public void onActivityDestroyed(Activity activity) {
+ }
+ }
+}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitPresenter.java
new file mode 100644
index 0000000..381d6d7
--- /dev/null
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitPresenter.java
@@ -0,0 +1,302 @@
+/*
+ * 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 androidx.window.extensions.organizer;
+
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.window.TaskFragmentCreationParams;
+import android.window.WindowContainerTransaction;
+
+import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.window.extensions.ExtensionSplitPairRule;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Controls the visual presentation of the splits according to the containers formed by
+ * {@link SplitController}.
+ */
+class SplitPresenter extends JetpackTaskFragmentOrganizer {
+ private static final int POSITION_LEFT = 0;
+ private static final int POSITION_RIGHT = 1;
+ private static final int POSITION_FILL = 2;
+
+ @IntDef(value = {
+ POSITION_LEFT,
+ POSITION_RIGHT,
+ POSITION_FILL,
+ })
+ private @interface Position {}
+
+ private final SplitController mController;
+
+ SplitPresenter(@NonNull Executor executor, SplitController controller) {
+ super(executor, controller);
+ mController = controller;
+ registerOrganizer();
+ }
+
+ /**
+ * Updates the presentation of the provided container.
+ */
+ void updateContainer(TaskFragmentContainer container) {
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ mController.updateContainer(wct, container);
+ applyTransaction(wct);
+ }
+
+ /**
+ * Deletes the provided container and updates the presentation if necessary.
+ */
+ void deleteContainer(TaskFragmentContainer container) {
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ deleteTaskFragment(wct, container.getTaskFragmentToken());
+
+ final TaskFragmentContainer newTopContainer = mController.getTopActiveContainer();
+ if (newTopContainer != null) {
+ mController.updateContainer(wct, newTopContainer);
+ }
+
+ applyTransaction(wct);
+ }
+
+ /**
+ * Creates a new split container with the two provided activities.
+ * @param primaryActivity An activity that should be in the primary container. If it is not
+ * currently in an existing container, a new one will be created and the
+ * activity will be re-parented to it.
+ * @param secondaryActivity An activity that should be in the secondary container. If it is not
+ * currently in an existing container, or if it is currently in the
+ * same container as the primary activity, a new container will be
+ * created and the activity will be re-parented to it.
+ * @param rule The split rule to be applied to the container.
+ */
+ void createNewSplitContainer(@NonNull Activity primaryActivity,
+ @NonNull Activity secondaryActivity, @NonNull ExtensionSplitPairRule rule) {
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+
+ final Rect parentBounds = getParentContainerBounds(primaryActivity);
+ final Rect primaryRectBounds = getBoundsForPosition(POSITION_LEFT, parentBounds, rule);
+ final Rect secondaryRectBounds = getBoundsForPosition(POSITION_RIGHT, parentBounds, rule);
+
+ TaskFragmentContainer primaryContainer = mController.getContainerWithActivity(
+ primaryActivity.getActivityToken());
+ if (primaryContainer == null) {
+ primaryContainer = mController.newContainer(primaryActivity);
+
+ final TaskFragmentCreationParams fragmentOptions =
+ createFragmentOptions(
+ primaryContainer.getTaskFragmentToken(),
+ primaryActivity.getActivityToken(),
+ primaryRectBounds,
+ WINDOWING_MODE_MULTI_WINDOW);
+ wct.createTaskFragment(fragmentOptions);
+
+ wct.reparentActivityToTaskFragment(primaryContainer.getTaskFragmentToken(),
+ primaryActivity.getActivityToken());
+ } else {
+ resizeTaskFragmentIfRegistered(wct, primaryContainer, primaryRectBounds);
+ }
+
+ TaskFragmentContainer secondaryContainer = mController.getContainerWithActivity(
+ secondaryActivity.getActivityToken());
+ if (secondaryContainer == null || secondaryContainer == primaryContainer) {
+ secondaryContainer = mController.newContainer(secondaryActivity);
+
+ final TaskFragmentCreationParams fragmentOptions =
+ createFragmentOptions(
+ secondaryContainer.getTaskFragmentToken(),
+ secondaryActivity.getActivityToken(),
+ secondaryRectBounds,
+ WINDOWING_MODE_MULTI_WINDOW);
+ wct.createTaskFragment(fragmentOptions);
+
+ wct.reparentActivityToTaskFragment(secondaryContainer.getTaskFragmentToken(),
+ secondaryActivity.getActivityToken());
+ } else {
+ resizeTaskFragmentIfRegistered(wct, secondaryContainer, secondaryRectBounds);
+ }
+
+ // TODO(b/190433398): The primary container and the secondary container should also be set
+ // as adjacent (WCT#setAdjacentRoots) to make activities behind invisible.
+ applyTransaction(wct);
+
+ mController.registerSplit(primaryContainer, primaryActivity, secondaryContainer, rule);
+ }
+
+ /**
+ * Starts a new activity to the side, creating a new split container. A new container will be
+ * created for the activity that will be started.
+ * @param launchingActivity An activity that should be in the primary container. If it is not
+ * currently in an existing container, a new one will be created and
+ * the activity will be re-parented to it.
+ * @param activityIntent The intent to start the new activity.
+ * @param activityOptions The options to apply to new activity start.
+ * @param rule The split rule to be applied to the container.
+ */
+ void startActivityToSide(@NonNull Activity launchingActivity, @NonNull Intent activityIntent,
+ @Nullable Bundle activityOptions, @NonNull ExtensionSplitPairRule rule) {
+ final Rect parentBounds = getParentContainerBounds(launchingActivity);
+ final Rect primaryRectBounds = getBoundsForPosition(POSITION_LEFT, parentBounds, rule);
+ final Rect secondaryRectBounds = getBoundsForPosition(POSITION_RIGHT, parentBounds, rule);
+
+ TaskFragmentContainer primaryContainer = mController.getContainerWithActivity(
+ launchingActivity.getActivityToken());
+ if (primaryContainer == null) {
+ primaryContainer = mController.newContainer(launchingActivity);
+ }
+
+ TaskFragmentContainer secondaryContainer = mController.newContainer(null);
+ startActivityToSide(
+ primaryContainer.getTaskFragmentToken(),
+ primaryRectBounds,
+ launchingActivity,
+ secondaryContainer.getTaskFragmentToken(),
+ secondaryRectBounds,
+ activityIntent,
+ activityOptions);
+
+ // TODO(b/190433398): The primary container and the secondary container should also be set
+ // as adjacent (WCT#setAdjacentRoots) to make activities behind invisible.
+
+ mController.registerSplit(primaryContainer, launchingActivity, secondaryContainer,
+ rule);
+ }
+
+ /**
+ * Updates the positions of containers in an existing split.
+ * @param splitContainer The split container to be updated.
+ * @param updatedContainer The task fragment that was updated and caused this split update.
+ * @param wct WindowContainerTransaction that this update should be performed with.
+ */
+ void updateSplitContainer(@NonNull SplitContainer splitContainer,
+ @NonNull TaskFragmentContainer updatedContainer,
+ @NonNull WindowContainerTransaction wct) {
+ // Getting the parent bounds using the updated container - it will have the recent value.
+ final Rect parentBounds = getParentContainerBounds(updatedContainer);
+ final ExtensionSplitPairRule rule = splitContainer.getSplitPairRule();
+ final Rect primaryRectBounds = getBoundsForPosition(POSITION_LEFT, parentBounds, rule);
+ final Rect secondaryRectBounds = getBoundsForPosition(POSITION_RIGHT, parentBounds, rule);
+
+ // TODO(b/190433398): Check if the bounds actually changed.
+ // If the task fragments are not registered yet, the positions will be updated after they
+ // are created again.
+ resizeTaskFragmentIfRegistered(wct, splitContainer.getPrimaryContainer(),
+ primaryRectBounds);
+ resizeTaskFragmentIfRegistered(wct, splitContainer.getSecondaryContainer(),
+ secondaryRectBounds);
+ }
+
+ /**
+ * Resizes the task fragment if it was already registered. Skips the operation if the container
+ * creation has not been reported from the server yet.
+ */
+ // TODO(b/190433398): Handle resize if the fragment hasn't appeared yet.
+ void resizeTaskFragmentIfRegistered(@NonNull WindowContainerTransaction wct,
+ @NonNull TaskFragmentContainer container,
+ @Nullable Rect bounds) {
+ if (container.getInfo() == null) {
+ return;
+ }
+ // TODO(b/190433398): Check if the bounds actually changed.
+ resizeTaskFragment(wct, container.getTaskFragmentToken(), bounds);
+ }
+
+ boolean shouldShowSideBySide(@NonNull SplitContainer splitContainer) {
+ final Rect parentBounds = getParentContainerBounds(splitContainer.getPrimaryContainer());
+ return shouldShowSideBySide(parentBounds, splitContainer.getSplitPairRule());
+ }
+
+ boolean shouldShowSideBySide(@Nullable Rect parentBounds,
+ @NonNull ExtensionSplitPairRule rule) {
+ return parentBounds != null && parentBounds.width() >= rule.minWidth
+ // TODO(b/190433398): Consider proper smallest width computation.
+ && Math.min(parentBounds.width(), parentBounds.height()) >= rule.minSmallestWidth;
+ }
+
+ @NonNull
+ private Rect getBoundsForPosition(@Position int position, @NonNull Rect parentBounds,
+ @NonNull ExtensionSplitPairRule rule) {
+ if (!shouldShowSideBySide(parentBounds, rule)) {
+ return new Rect();
+ }
+
+ float splitRatio = rule.splitRatio;
+ switch (position) {
+ case POSITION_LEFT:
+ return new Rect(
+ parentBounds.left,
+ parentBounds.top,
+ (int) (parentBounds.left + parentBounds.width() * splitRatio),
+ parentBounds.bottom);
+ case POSITION_RIGHT:
+ return new Rect(
+ (int) (parentBounds.left + parentBounds.width() * splitRatio),
+ parentBounds.top,
+ parentBounds.right,
+ parentBounds.bottom);
+ case POSITION_FILL:
+ return parentBounds;
+ }
+ return parentBounds;
+ }
+
+ @NonNull
+ Rect getParentContainerBounds(@NonNull TaskFragmentContainer container) {
+ final Configuration parentConfig = mFragmentParentConfigs.get(
+ container.getTaskFragmentToken());
+ if (parentConfig != null) {
+ return parentConfig.windowConfiguration.getBounds();
+ }
+
+ // If there is no parent yet - then assuming that activities are running in full task bounds
+ final Activity topActivity = container.getTopNonFinishingActivity();
+ final Rect bounds = topActivity != null ? getParentContainerBounds(topActivity) : null;
+
+ if (bounds == null) {
+ throw new IllegalStateException("Unknown parent bounds");
+ }
+ return bounds;
+ }
+
+ @NonNull
+ Rect getParentContainerBounds(@NonNull Activity activity) {
+ final TaskFragmentContainer container = mController.getContainerWithActivity(
+ activity.getActivityToken());
+ if (container != null) {
+ final Configuration parentConfig = mFragmentParentConfigs.get(
+ container.getTaskFragmentToken());
+ if (parentConfig != null) {
+ return parentConfig.windowConfiguration.getBounds();
+ }
+ }
+
+ // TODO(b/190433398): Check if the client-side available info about parent bounds is enough.
+ if (!activity.isInMultiWindowMode()) {
+ // In fullscreen mode the max bounds should correspond to the task bounds.
+ return activity.getResources().getConfiguration().windowConfiguration.getMaxBounds();
+ }
+ return activity.getResources().getConfiguration().windowConfiguration.getBounds();
+ }
+}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentContainer.java
new file mode 100644
index 0000000..3cf37a6
--- /dev/null
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentContainer.java
@@ -0,0 +1,202 @@
+/*
+ * 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 androidx.window.extensions.organizer;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.Activity;
+import android.app.ActivityThread;
+import android.os.Binder;
+import android.os.IBinder;
+import android.window.TaskFragmentInfo;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Client-side container for a stack of activities. Corresponds to an instance of TaskFragment
+ * on the server side.
+ */
+class TaskFragmentContainer {
+ /**
+ * Client-created token that uniquely identifies the task fragment container instance.
+ */
+ @NonNull
+ private final IBinder mToken;
+
+ /**
+ * Server-provided task fragment information.
+ */
+ private TaskFragmentInfo mInfo;
+
+ /**
+ * Activity that is being reparented to this container, but haven't been added to {@link #mInfo}
+ * yet.
+ */
+ private Activity mReparentingActivity;
+
+ /** Containers that are dependent on this one and should be completely destroyed on exit. */
+ private final List<TaskFragmentContainer> mContainersToFinishOnExit =
+ new ArrayList<>();
+
+ /** Individual associated activities in different containers that should be finished on exit. */
+ private final List<Activity> mActivitiesToFinishOnExit = new ArrayList<>();
+
+ /** Indicates whether the container was cleaned up after the last activity was removed. */
+ private boolean mIsFinished;
+
+ /**
+ * Creates a container with an existing activity that will be re-parented to it in a window
+ * container transaction.
+ */
+ TaskFragmentContainer(@Nullable Activity activity) {
+ mToken = new Binder("TaskFragmentContainer");
+ mReparentingActivity = activity;
+ }
+
+ /**
+ * Returns the client-created token that uniquely identifies this container.
+ */
+ @NonNull
+ IBinder getTaskFragmentToken() {
+ return mToken;
+ }
+
+ /** List of activities that belong to this container and live in this process. */
+ @NonNull
+ List<Activity> collectActivities() {
+ // Add the re-parenting activity, in case the server has not yet reported the task
+ // fragment info update with it placed in this container. We still want to apply rules
+ // in this intermediate state.
+ List<Activity> allActivities = new ArrayList<>();
+ if (mReparentingActivity != null) {
+ allActivities.add(mReparentingActivity);
+ }
+ // Add activities reported from the server.
+ if (mInfo == null) {
+ return allActivities;
+ }
+ ActivityThread activityThread = ActivityThread.currentActivityThread();
+ for (IBinder token : mInfo.getActivities()) {
+ Activity activity = activityThread.getActivity(token);
+ if (activity != null && !allActivities.contains(activity)) {
+ allActivities.add(activity);
+ }
+ }
+ return allActivities;
+ }
+
+ boolean hasActivity(@NonNull IBinder token) {
+ if (mInfo != null && mInfo.getActivities().contains(token)) {
+ return true;
+ }
+ return mReparentingActivity != null
+ && mReparentingActivity.getActivityToken().equals(token);
+ }
+
+ @Nullable
+ TaskFragmentInfo getInfo() {
+ return mInfo;
+ }
+
+ void setInfo(@Nullable TaskFragmentInfo info) {
+ mInfo = info;
+ if (mInfo == null || mReparentingActivity == null) {
+ return;
+ }
+ // Cleanup activities that were being re-parented
+ for (IBinder activityToken : mInfo.getActivities()) {
+ if (mReparentingActivity.getActivityToken().equals(activityToken)) {
+ mReparentingActivity = null;
+ break;
+ }
+ }
+ }
+
+ @Nullable
+ Activity getTopNonFinishingActivity() {
+ List<Activity> activities = collectActivities();
+ if (activities.isEmpty()) {
+ return null;
+ }
+ int i = activities.size() - 1;
+ while (i >= 0 && activities.get(i).isFinishing()) {
+ i--;
+ }
+ return i >= 0 ? activities.get(i) : null;
+ }
+
+ boolean isEmpty() {
+ return mReparentingActivity == null && (mInfo == null || mInfo.isEmpty());
+ }
+
+ /**
+ * Adds a container that should be finished when this container is finished.
+ */
+ void addContainerToFinishOnExit(@NonNull TaskFragmentContainer containerToFinish) {
+ mContainersToFinishOnExit.add(containerToFinish);
+ }
+
+ /**
+ * Adds an activity that should be finished when this container is finished.
+ */
+ void addActivityToFinishOnExit(@NonNull Activity activityToFinish) {
+ mActivitiesToFinishOnExit.add(activityToFinish);
+ }
+
+ /**
+ * Removes all activities that belong to this process and finishes other containers/activities
+ * configured to finish together.
+ */
+ void finish(boolean shouldFinishDependent) {
+ if (mIsFinished) {
+ return;
+ }
+ mIsFinished = true;
+
+ // Finish own activities
+ for (Activity activity : collectActivities()) {
+ activity.finish();
+ }
+
+ if (!shouldFinishDependent) {
+ return;
+ }
+
+ // Finish dependent containers
+ for (TaskFragmentContainer container : mContainersToFinishOnExit) {
+ container.finish(true /* shouldFinishDependent */);
+ }
+ mContainersToFinishOnExit.clear();
+
+ // Finish associated activities
+ for (Activity activity : mActivitiesToFinishOnExit) {
+ activity.finish();
+ }
+ mActivitiesToFinishOnExit.clear();
+
+ // Finish activities that were being re-parented to this container.
+ if (mReparentingActivity != null) {
+ mReparentingActivity.finish();
+ mReparentingActivity = null;
+ }
+ }
+
+ boolean isFinished() {
+ return mIsFinished;
+ }
+}
diff --git a/libs/WindowManager/Jetpack/window-extensions-release.aar b/libs/WindowManager/Jetpack/window-extensions-release.aar
index be6652d..fdbc5f6 100644
--- a/libs/WindowManager/Jetpack/window-extensions-release.aar
+++ b/libs/WindowManager/Jetpack/window-extensions-release.aar
Binary files differ
diff --git a/libs/WindowManager/Shell/res/color/one_handed_tutorial_background_color.xml b/libs/WindowManager/Shell/res/color/one_handed_tutorial_background_color.xml
new file mode 100644
index 0000000..4f56e0f
--- /dev/null
+++ b/libs/WindowManager/Shell/res/color/one_handed_tutorial_background_color.xml
@@ -0,0 +1,21 @@
+<?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.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+ <item android:color="?androidprv:attr/colorSurfaceVariant"/>
+</selector>
diff --git a/libs/WindowManager/Shell/res/drawable-hdpi/one_handed_tutorial.png b/libs/WindowManager/Shell/res/drawable-hdpi/one_handed_tutorial.png
deleted file mode 100644
index 6c1f1cf..0000000
--- a/libs/WindowManager/Shell/res/drawable-hdpi/one_handed_tutorial.png
+++ /dev/null
Binary files differ
diff --git a/libs/WindowManager/Shell/res/drawable/one_handed_tutorial_icon.xml b/libs/WindowManager/Shell/res/drawable/one_handed_tutorial_icon.xml
new file mode 100644
index 0000000..b32f34e
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/one_handed_tutorial_icon.xml
@@ -0,0 +1,14 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="32dp"
+ android:height="60dp"
+ android:viewportWidth="32"
+ android:viewportHeight="60">
+ <path
+ android:pathData="M1.9703,30.5041C1.9703,28.295 3.7612,26.5042 5.9703,26.5042H25.5551C27.7642,26.5042 29.5551,28.295 29.5551,30.5042V54.0296C29.5551,56.2387 27.7642,58.0296 25.5551,58.0296H5.9703C3.7612,58.0296 1.9703,56.2387 1.9703,54.0296V30.5041Z"
+ android:fillColor="#000000"
+ android:fillAlpha="0.16"/>
+ <path
+ android:pathData="M25.5254,2H6C3.7909,2 2,3.7909 2,6V54C2,56.2091 3.7909,58 6,58H25.5254C27.7346,58 29.5254,56.2091 29.5254,54V6C29.5254,3.7909 27.7346,2 25.5254,2ZM6,0C2.6863,0 0,2.6863 0,6V54C0,57.3137 2.6863,60 6,60H25.5254C28.8391,60 31.5254,57.3137 31.5254,54V6C31.5254,2.6863 28.8391,0 25.5254,0H6ZM12.2034,47.2336L12.8307,47.861L15.3178,45.3783V52.1277H16.2076V45.3783L18.6903,47.8654L19.322,47.2336L15.7627,43.6743L12.2034,47.2336ZM19.7034,55.0742H11.822V56.552H19.7034V55.0742Z"
+ android:fillColor="#000000"
+ android:fillType="evenOdd"/>
+</vector>
diff --git a/libs/WindowManager/Shell/res/layout/one_handed_tutorial.xml b/libs/WindowManager/Shell/res/layout/one_handed_tutorial.xml
index 0190aad..d29ed8b 100644
--- a/libs/WindowManager/Shell/res/layout/one_handed_tutorial.xml
+++ b/libs/WindowManager/Shell/res/layout/one_handed_tutorial.xml
@@ -31,7 +31,7 @@
android:layout_marginTop="6dp"
android:layout_marginBottom="0dp"
android:gravity="center_horizontal"
- android:src="@drawable/one_handed_tutorial"
+ android:src="@drawable/one_handed_tutorial_icon"
android:scaleType="centerInside" />
<TextView
@@ -45,7 +45,6 @@
android:fontFamily="google-sans-medium"
android:text="@string/one_handed_tutorial_title"
android:textSize="16sp"
- android:textStyle="bold"
android:textColor="@android:color/white"/>
<TextView
@@ -54,8 +53,8 @@
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:layout_marginBottom="0dp"
- android:layout_marginStart="46dp"
- android:layout_marginEnd="46dp"
+ android:layout_marginStart="60dp"
+ android:layout_marginEnd="60dp"
android:gravity="center_horizontal"
android:fontFamily="roboto-regular"
android:text="@string/one_handed_tutorial_description"
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 d460195..36b8923 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
@@ -45,6 +45,7 @@
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.SurfaceControl;
+import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
@@ -205,6 +206,7 @@
* between bubble activities without needing both to be alive at the same time.
*/
private SurfaceView mAnimatingOutSurfaceView;
+ private boolean mAnimatingOutSurfaceReady;
/** Container for the animating-out SurfaceView. */
private FrameLayout mAnimatingOutSurfaceContainer;
@@ -808,6 +810,20 @@
mAnimatingOutSurfaceView.setZOrderOnTop(true);
mAnimatingOutSurfaceView.setCornerRadius(mCornerRadius);
mAnimatingOutSurfaceView.setLayoutParams(new ViewGroup.LayoutParams(0, 0));
+ mAnimatingOutSurfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
+ @Override
+ public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {}
+
+ @Override
+ public void surfaceCreated(SurfaceHolder surfaceHolder) {
+ mAnimatingOutSurfaceReady = true;
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
+ mAnimatingOutSurfaceReady = false;
+ }
+ });
mAnimatingOutSurfaceContainer.addView(mAnimatingOutSurfaceView);
mAnimatingOutSurfaceContainer.setPadding(
@@ -2652,7 +2668,7 @@
return;
}
- if (!mIsExpanded) {
+ if (!mIsExpanded || !mAnimatingOutSurfaceReady) {
onComplete.accept(false);
return;
}
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 481b948..3ccb9e7 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
@@ -20,7 +20,6 @@
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.graphics.Rect;
-import android.util.Log;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
import android.window.DisplayAreaAppearedInfo;
@@ -30,7 +29,6 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
-import androidx.core.content.ContextCompat;
import com.android.internal.annotations.GuardedBy;
import com.android.wm.shell.R;
@@ -48,14 +46,17 @@
public class OneHandedBackgroundPanelOrganizer extends DisplayAreaOrganizer
implements OneHandedTransitionCallback {
private static final String TAG = "OneHandedBackgroundPanelOrganizer";
+ private static final int THEME_COLOR_OFFSET = 10;
+ private final Context mContext;
private final Object mLock = new Object();
private final SurfaceSession mSurfaceSession = new SurfaceSession();
- private final float[] mDefaultColor;
private final Executor mMainExecutor;
private final OneHandedSurfaceTransactionHelper.SurfaceControlTransactionFactory
mSurfaceControlTransactionFactory;
+ private float[] mDefaultColor;
+
/**
* The background to distinguish the boundary of translated windows and empty region when
* one handed mode triggered.
@@ -88,15 +89,14 @@
public OneHandedBackgroundPanelOrganizer(Context context, DisplayLayout displayLayout,
Executor executor) {
super(executor);
+ mContext = context;
// Ensure the mBkgBounds is portrait, due to OHM only support on portrait
if (displayLayout.height() > displayLayout.width()) {
mBkgBounds = new Rect(0, 0, displayLayout.width(), displayLayout.height());
} else {
mBkgBounds = new Rect(0, 0, displayLayout.height(), displayLayout.width());
}
- final int defaultColor = ContextCompat.getColor(context, R.color.GM2_grey_800);
- mDefaultColor = new float[]{Color.red(defaultColor) / 255.0f,
- Color.green(defaultColor) / 255.0f, Color.blue(defaultColor) / 255.0f};
+ updateThemeColors();
mMainExecutor = executor;
mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new;
}
@@ -170,7 +170,6 @@
}
if (getBackgroundSurface() == null) {
- Log.w(TAG, "mBackgroundSurface is null !");
return;
}
@@ -201,6 +200,30 @@
}
}
+ /**
+ * onConfigurationChanged events for updating tutorial text.
+ */
+ public void onConfigurationChanged() {
+ synchronized (mLock) {
+ if (mBackgroundSurface == null) {
+ getBackgroundSurface();
+ } else {
+ removeBackgroundPanelLayer();
+ }
+ updateThemeColors();
+ showBackgroundPanelLayer();
+ }
+ }
+
+ private void updateThemeColors() {
+ synchronized (mLock) {
+ final int themeColor = mContext.getColor(R.color.one_handed_tutorial_background_color);
+ mDefaultColor = new float[]{(Color.red(themeColor) - THEME_COLOR_OFFSET) / 255.0f,
+ (Color.green(themeColor) - THEME_COLOR_OFFSET) / 255.0f,
+ (Color.blue(themeColor) - THEME_COLOR_OFFSET) / 255.0f};
+ }
+ }
+
void dump(@NonNull PrintWriter pw) {
final String innerPrefix = " ";
pw.println(TAG);
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 2038cff..09cde38 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
@@ -658,12 +658,13 @@
}
private void onConfigChanged(Configuration newConfig) {
- if (mTutorialHandler == null) {
+ if (mTutorialHandler == null || mBackgroundPanelOrganizer == null) {
return;
}
if (!mIsOneHandedEnabled || newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
return;
}
+ mBackgroundPanelOrganizer.onConfigurationChanged();
mTutorialHandler.onConfigurationChanged();
}
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 d0206a4..97e04b5 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
@@ -25,8 +25,11 @@
import static com.android.wm.shell.onehanded.OneHandedState.STATE_EXITING;
import static com.android.wm.shell.onehanded.OneHandedState.STATE_NONE;
+import android.animation.ValueAnimator;
import android.annotation.Nullable;
import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.TypedArray;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.os.SystemProperties;
@@ -35,9 +38,13 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
+import android.view.animation.LinearInterpolator;
import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.TextView;
import androidx.annotation.NonNull;
+import androidx.appcompat.view.ContextThemeWrapper;
import com.android.internal.annotations.VisibleForTesting;
import com.android.wm.shell.R;
@@ -53,11 +60,14 @@
public class OneHandedTutorialHandler implements OneHandedTransitionCallback,
OneHandedState.OnStateChangedListener {
private static final String TAG = "OneHandedTutorialHandler";
- private static final String ONE_HANDED_MODE_OFFSET_PERCENTAGE =
- "persist.debug.one_handed_offset_percentage";
+ private static final String OFFSET_PERCENTAGE = "persist.debug.one_handed_offset_percentage";
+ private static final String TRANSLATE_ANIMATION_DURATION =
+ "persist.debug.one_handed_translate_animation_duration";
+ private static final float START_TRANSITION_FRACTION = 0.7f;
private final float mTutorialHeightRatio;
private final WindowManager mWindowManager;
+ private final OneHandedAnimationCallback mAnimationCallback;
private @OneHandedState.State int mCurrentState;
private int mTutorialAreaHeight;
@@ -67,7 +77,9 @@
private @Nullable View mTutorialView;
private @Nullable ViewGroup mTargetViewContainer;
- private final OneHandedAnimationCallback mAnimationCallback;
+ private float mAlphaTransitionStart;
+ private ValueAnimator mAlphaAnimator;
+ private int mAlphaAnimationDurationMs;
public OneHandedTutorialHandler(Context context, WindowManager windowManager) {
mContext = context;
@@ -75,15 +87,35 @@
final float offsetPercentageConfig = context.getResources().getFraction(
R.fraction.config_one_handed_offset, 1, 1);
final int sysPropPercentageConfig = SystemProperties.getInt(
- ONE_HANDED_MODE_OFFSET_PERCENTAGE, Math.round(offsetPercentageConfig * 100.0f));
+ OFFSET_PERCENTAGE, Math.round(offsetPercentageConfig * 100.0f));
mTutorialHeightRatio = sysPropPercentageConfig / 100.0f;
+ final int animationDuration = context.getResources().getInteger(
+ R.integer.config_one_handed_translate_animation_duration);
+ mAlphaAnimationDurationMs = SystemProperties.getInt(TRANSLATE_ANIMATION_DURATION,
+ animationDuration);
mAnimationCallback = new OneHandedAnimationCallback() {
@Override
+ public void onOneHandedAnimationCancel(
+ OneHandedAnimationController.OneHandedTransitionAnimator animator) {
+ if (mAlphaAnimator != null) {
+ mAlphaAnimator.cancel();
+ }
+ }
+
+ @Override
public void onAnimationUpdate(float xPos, float yPos) {
if (!isAttached()) {
return;
}
- mTargetViewContainer.setTranslationY(yPos - mTutorialAreaHeight);
+ if (yPos < mAlphaTransitionStart) {
+ checkTransitionEnd();
+ return;
+ }
+ if (mAlphaAnimator == null || mAlphaAnimator.isStarted()
+ || mAlphaAnimator.isRunning()) {
+ return;
+ }
+ mAlphaAnimator.start();
}
};
}
@@ -94,12 +126,16 @@
switch (newState) {
case STATE_ENTERING:
createViewAndAttachToWindow(mContext);
+ updateThemeColor();
+ setupAlphaTransition(true /* isEntering */);
break;
case STATE_ACTIVE:
- case STATE_EXITING:
- // no - op
+ checkTransitionEnd();
+ setupAlphaTransition(false /* isEntering */);
break;
+ case STATE_EXITING:
case STATE_NONE:
+ checkTransitionEnd();
removeTutorialFromWindowManager();
break;
default:
@@ -119,6 +155,7 @@
mDisplayBounds = new Rect(0, 0, displayLayout.height(), displayLayout.width());
}
mTutorialAreaHeight = Math.round(mDisplayBounds.height() * mTutorialHeightRatio);
+ mAlphaTransitionStart = mTutorialAreaHeight * START_TRANSITION_FRACTION;
}
@VisibleForTesting
@@ -129,6 +166,7 @@
mTutorialView = LayoutInflater.from(context).inflate(R.layout.one_handed_tutorial, null);
mTargetViewContainer = new FrameLayout(context);
mTargetViewContainer.setClipChildren(false);
+ mTargetViewContainer.setAlpha(mCurrentState == STATE_ACTIVE ? 1.0f : 0.0f);
mTargetViewContainer.addView(mTutorialView);
mTargetViewContainer.setLayerType(LAYER_TYPE_HARDWARE, null);
@@ -192,6 +230,52 @@
removeTutorialFromWindowManager();
if (mCurrentState == STATE_ENTERING || mCurrentState == STATE_ACTIVE) {
createViewAndAttachToWindow(mContext);
+ updateThemeColor();
+ checkTransitionEnd();
+ }
+ }
+
+ private void updateThemeColor() {
+ if (mTutorialView == null) {
+ return;
+ }
+
+ final Context themedContext = new ContextThemeWrapper(mTutorialView.getContext(),
+ com.android.internal.R.style.Theme_DeviceDefault_DayNight);
+ final int textColorPrimary;
+ final int themedTextColorSecondary;
+ TypedArray ta = themedContext.obtainStyledAttributes(new int[]{
+ com.android.internal.R.attr.textColorPrimary,
+ com.android.internal.R.attr.textColorSecondary});
+ textColorPrimary = ta.getColor(0, 0);
+ themedTextColorSecondary = ta.getColor(1, 0);
+ ta.recycle();
+
+ final ImageView iconView = mTutorialView.findViewById(R.id.one_handed_tutorial_image);
+ iconView.setImageTintList(ColorStateList.valueOf(textColorPrimary));
+
+ final TextView tutorialTitle = mTutorialView.findViewById(R.id.one_handed_tutorial_title);
+ final TextView tutorialDesc = mTutorialView.findViewById(
+ R.id.one_handed_tutorial_description);
+ tutorialTitle.setTextColor(textColorPrimary);
+ tutorialDesc.setTextColor(themedTextColorSecondary);
+ }
+
+ private void setupAlphaTransition(boolean isEntering) {
+ final float start = isEntering ? 0.0f : 1.0f;
+ final float end = isEntering ? 1.0f : 0.0f;
+ mAlphaAnimator = ValueAnimator.ofFloat(start, end);
+ mAlphaAnimator.setInterpolator(new LinearInterpolator());
+ mAlphaAnimator.setDuration(mAlphaAnimationDurationMs);
+ mAlphaAnimator.addUpdateListener(
+ animator -> mTargetViewContainer.setAlpha((float) animator.getAnimatedValue()));
+ }
+
+ private void checkTransitionEnd() {
+ if (mAlphaAnimator != null && mAlphaAnimator.isRunning()) {
+ mAlphaAnimator.end();
+ mAlphaAnimator.removeAllUpdateListeners();
+ mAlphaAnimator = null;
}
}
@@ -206,5 +290,9 @@
pw.println(mDisplayBounds);
pw.print(innerPrefix + "mTutorialAreaHeight=");
pw.println(mTutorialAreaHeight);
+ pw.print(innerPrefix + "mAlphaTransitionStart=");
+ pw.println(mAlphaTransitionStart);
+ pw.print(innerPrefix + "mAlphaAnimationDurationMs=");
+ pw.println(mAlphaAnimationDurationMs);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
index c46b559..05111a3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
@@ -26,14 +26,19 @@
import android.animation.ValueAnimator;
import android.annotation.IntDef;
import android.app.TaskInfo;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Color;
import android.graphics.Rect;
import android.view.Choreographer;
import android.view.Surface;
import android.view.SurfaceControl;
+import android.view.SurfaceSession;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import com.android.wm.shell.animation.Interpolators;
+import com.android.wm.shell.transition.Transitions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -253,6 +258,7 @@
mSurfaceControlTransactionFactory;
private PipSurfaceTransactionHelper mSurfaceTransactionHelper;
private @TransitionDirection int mTransitionDirection;
+ protected SurfaceControl mContentOverlay;
private PipTransitionAnimator(TaskInfo taskInfo, SurfaceControl leash,
@AnimationType int animationType, Rect destinationBounds, T baseValue, T startValue,
@@ -331,6 +337,53 @@
return false;
}
+ SurfaceControl getContentOverlay() {
+ return mContentOverlay;
+ }
+
+ PipTransitionAnimator<T> setUseContentOverlay(Context context) {
+ final SurfaceControl.Transaction tx = newSurfaceControlTransaction();
+ if (mContentOverlay != null) {
+ // remove existing content overlay if there is any.
+ tx.remove(mContentOverlay);
+ tx.apply();
+ }
+ mContentOverlay = new SurfaceControl.Builder(new SurfaceSession())
+ .setCallsite("PipAnimation")
+ .setName("PipContentOverlay")
+ .setColorLayer()
+ .build();
+ tx.show(mContentOverlay);
+ tx.setLayer(mContentOverlay, Integer.MAX_VALUE);
+ tx.setColor(mContentOverlay, getContentOverlayColor(context));
+ tx.setAlpha(mContentOverlay, 0f);
+ tx.reparent(mContentOverlay, mLeash);
+ tx.apply();
+ return this;
+ }
+
+ private float[] getContentOverlayColor(Context context) {
+ final TypedArray ta = context.obtainStyledAttributes(new int[] {
+ android.R.attr.colorBackground });
+ try {
+ int colorAccent = ta.getColor(0, 0);
+ return new float[] {
+ Color.red(colorAccent) / 255f,
+ Color.green(colorAccent) / 255f,
+ Color.blue(colorAccent) / 255f };
+ } finally {
+ ta.recycle();
+ }
+ }
+
+ /**
+ * Clears the {@link #mContentOverlay}, this should be done after the content overlay is
+ * faded out, such as in {@link PipTaskOrganizer#fadeOutAndRemoveOverlay}
+ */
+ void clearContentOverlay() {
+ mContentOverlay = null;
+ }
+
@VisibleForTesting
@TransitionDirection public int getTransitionDirection() {
return mTransitionDirection;
@@ -517,6 +570,9 @@
final Rect base = getBaseValue();
final Rect start = getStartValue();
final Rect end = getEndValue();
+ if (mContentOverlay != null) {
+ tx.setAlpha(mContentOverlay, fraction < 0.5f ? 0 : (fraction - 0.5f) * 2);
+ }
if (rotatedEndRect != null) {
// Animate the bounds in a different orientation. It only happens when
// switching between PiP and fullscreen.
@@ -562,14 +618,28 @@
setCurrentValue(bounds);
final Rect insets = computeInsets(fraction);
final float degree, x, y;
- if (rotationDelta == ROTATION_90) {
- degree = 90 * fraction;
- x = fraction * (end.right - start.left) + start.left;
- y = fraction * (end.top - start.top) + start.top;
+ if (Transitions.ENABLE_SHELL_TRANSITIONS) {
+ if (rotationDelta == ROTATION_90) {
+ degree = 90 * (1 - fraction);
+ x = fraction * (end.left - start.left)
+ + start.left + start.right * (1 - fraction);
+ y = fraction * (end.top - start.top) + start.top;
+ } else {
+ degree = -90 * (1 - fraction);
+ x = fraction * (end.left - start.left) + start.left;
+ y = fraction * (end.top - start.top)
+ + start.top + start.bottom * (1 - fraction);
+ }
} else {
- degree = -90 * fraction;
- x = fraction * (end.left - start.left) + start.left;
- y = fraction * (end.bottom - start.top) + start.top;
+ if (rotationDelta == ROTATION_90) {
+ degree = 90 * fraction;
+ x = fraction * (end.right - start.left) + start.left;
+ y = fraction * (end.top - start.top) + start.top;
+ } else {
+ degree = -90 * fraction;
+ x = fraction * (end.left - start.left) + start.left;
+ y = fraction * (end.bottom - start.top) + start.top;
+ }
}
getSurfaceTransactionHelper()
.rotateAndScaleWithCrop(tx, leash, initialContainerRect, bounds,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
index 728794d..180e3fb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
@@ -23,6 +23,7 @@
import android.view.SurfaceControl;
import com.android.wm.shell.R;
+import com.android.wm.shell.transition.Transitions;
/**
* Abstracts the common operations on {@link SurfaceControl.Transaction} for PiP transition.
@@ -137,7 +138,8 @@
// destination are different.
final float scale = srcW <= srcH ? (float) destW / srcW : (float) destH / srcH;
final Rect crop = mTmpDestinationRect;
- crop.set(0, 0, destW, destH);
+ crop.set(0, 0, Transitions.ENABLE_SHELL_TRANSITIONS ? destH
+ : destW, Transitions.ENABLE_SHELL_TRANSITIONS ? destW : destH);
// Inverse scale for crop to fit in screen coordinates.
crop.scale(1 / scale);
crop.offset(insets.left, insets.top);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 6c3576b..d77619a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -107,6 +107,13 @@
*/
private static final int ONE_SHOT_ALPHA_ANIMATION_TIMEOUT_MS = 1000;
+ /**
+ * The fixed start delay in ms when fading out the content overlay from bounds animation.
+ * This is to overcome the flicker caused by configuration change when rotating from landscape
+ * to portrait PiP in button navigation mode.
+ */
+ private static final int CONTENT_OVERLAY_FADE_OUT_DELAY_MS = 500;
+
private final Context mContext;
private final SyncTransactionQueue mSyncTransactionQueue;
private final PipBoundsState mPipBoundsState;
@@ -144,6 +151,10 @@
final int direction = animator.getTransitionDirection();
final int animationType = animator.getAnimationType();
final Rect destinationBounds = animator.getDestinationBounds();
+ if (isInPipDirection(direction) && animator.getContentOverlay() != null) {
+ fadeOutAndRemoveOverlay(animator.getContentOverlay(),
+ animator::clearContentOverlay, true /* withStartDelay*/);
+ }
if (mWaitForFixedRotation && animationType == ANIM_TYPE_BOUNDS
&& direction == TRANSITION_DIRECTION_TO_PIP) {
// Notify the display to continue the deferred orientation change.
@@ -168,17 +179,17 @@
finishResize(tx, destinationBounds, direction, animationType);
sendOnPipTransitionFinished(direction);
}
- if (direction == TRANSITION_DIRECTION_TO_PIP) {
- // TODO (b//169221267): Add jank listener for transactions without buffer updates.
- //InteractionJankMonitor.getInstance().end(
- // InteractionJankMonitor.CUJ_LAUNCHER_APP_CLOSE_TO_PIP);
- }
}
@Override
public void onPipAnimationCancel(TaskInfo taskInfo,
PipAnimationController.PipTransitionAnimator animator) {
- sendOnPipTransitionCancelled(animator.getTransitionDirection());
+ final int direction = animator.getTransitionDirection();
+ if (isInPipDirection(direction) && animator.getContentOverlay() != null) {
+ fadeOutAndRemoveOverlay(animator.getContentOverlay(),
+ animator::clearContentOverlay, true /* withStartDelay */);
+ }
+ sendOnPipTransitionCancelled(direction);
}
};
@@ -232,16 +243,8 @@
private @Surface.Rotation int mCurrentRotation;
/**
- * If set to {@code true}, no entering PiP transition would be kicked off and most likely
- * it's due to the fact that Launcher is handling the transition directly when swiping
- * auto PiP-able Activity to home.
- * See also {@link #startSwipePipToHome(ComponentName, ActivityInfo, PictureInPictureParams)}.
- */
- private boolean mInSwipePipToHomeTransition;
-
- /**
* An optional overlay used to mask content changing between an app in/out of PiP, only set if
- * {@link #mInSwipePipToHomeTransition} is true.
+ * {@link PipTransitionState#getInSwipePipToHomeTransition()} is true.
*/
private SurfaceControl mSwipePipToHomeOverlay;
@@ -332,7 +335,7 @@
*/
public Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo,
PictureInPictureParams pictureInPictureParams) {
- mInSwipePipToHomeTransition = true;
+ mPipTransitionState.setInSwipePipToHomeTransition(true);
sendOnPipTransitionStarted(TRANSITION_DIRECTION_TO_PIP);
setBoundsStateForEntry(componentName, pictureInPictureParams, activityInfo);
return mPipBoundsAlgorithm.getEntryDestinationBounds();
@@ -345,7 +348,7 @@
public void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds,
SurfaceControl overlay) {
// do nothing if there is no startSwipePipToHome being called before
- if (mInSwipePipToHomeTransition) {
+ if (mPipTransitionState.getInSwipePipToHomeTransition()) {
mPipBoundsState.setBounds(destinationBounds);
mSwipePipToHomeOverlay = overlay;
}
@@ -506,7 +509,7 @@
mOnDisplayIdChangeCallback.accept(info.displayId);
}
- if (mInSwipePipToHomeTransition) {
+ if (mPipTransitionState.getInSwipePipToHomeTransition()) {
if (!mWaitForFixedRotation) {
onEndOfSwipePipToHomeTransition();
} else {
@@ -615,7 +618,7 @@
private void onEndOfSwipePipToHomeTransition() {
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
- mInSwipePipToHomeTransition = false;
+ mPipTransitionState.setInSwipePipToHomeTransition(false);
mSwipePipToHomeOverlay = null;
return;
}
@@ -635,10 +638,11 @@
// Remove the swipe to home overlay
if (swipeToHomeOverlay != null) {
- fadeOutAndRemoveOverlay(swipeToHomeOverlay);
+ fadeOutAndRemoveOverlay(swipeToHomeOverlay,
+ null /* callback */, false /* withStartDelay */);
}
}, tx);
- mInSwipePipToHomeTransition = false;
+ mPipTransitionState.setInSwipePipToHomeTransition(false);
mSwipePipToHomeOverlay = null;
}
@@ -706,7 +710,7 @@
return;
}
clearWaitForFixedRotation();
- mInSwipePipToHomeTransition = false;
+ mPipTransitionState.setInSwipePipToHomeTransition(false);
mPictureInPictureParams = null;
mPipTransitionState.setTransitionState(PipTransitionState.UNDEFINED);
// Re-set the PIP bounds to none.
@@ -718,9 +722,12 @@
mOnDisplayIdChangeCallback.accept(Display.DEFAULT_DISPLAY);
}
- final PipAnimationController.PipTransitionAnimator animator =
+ final PipAnimationController.PipTransitionAnimator<?> animator =
mPipAnimationController.getCurrentAnimator();
if (animator != null) {
+ if (animator.getContentOverlay() != null) {
+ removeContentOverlay(animator.getContentOverlay(), animator::clearContentOverlay);
+ }
animator.removeAllUpdateListeners();
animator.removeAllListeners();
animator.cancel();
@@ -778,7 +785,7 @@
return;
}
if (mPipTransitionState.getTransitionState() == PipTransitionState.TASK_APPEARED) {
- if (mInSwipePipToHomeTransition) {
+ if (mPipTransitionState.getInSwipePipToHomeTransition()) {
onEndOfSwipePipToHomeTransition();
} else {
// Schedule a regular animation to ensure all the callbacks are still being sent.
@@ -844,10 +851,12 @@
// Skip this entirely if that's the case.
final boolean waitForFixedRotationOnEnteringPip = mWaitForFixedRotation
&& (mPipTransitionState.getTransitionState() != PipTransitionState.ENTERED_PIP);
- if ((mInSwipePipToHomeTransition || waitForFixedRotationOnEnteringPip) && fromRotation) {
+ if ((mPipTransitionState.getInSwipePipToHomeTransition()
+ || waitForFixedRotationOnEnteringPip) && fromRotation) {
if (DEBUG) {
Log.d(TAG, "Skip onMovementBoundsChanged on rotation change"
- + " mInSwipePipToHomeTransition=" + mInSwipePipToHomeTransition
+ + " InSwipePipToHomeTransition="
+ + mPipTransitionState.getInSwipePipToHomeTransition()
+ " mWaitForFixedRotation=" + mWaitForFixedRotation
+ " getTransitionState=" + mPipTransitionState.getTransitionState());
}
@@ -1195,7 +1204,8 @@
snapshotDest);
// Start animation to fade out the snapshot.
- fadeOutAndRemoveOverlay(snapshotSurface);
+ fadeOutAndRemoveOverlay(snapshotSurface,
+ null /* callback */, false /* withStartDelay */);
});
} else {
applyFinishBoundsResize(wct, direction);
@@ -1286,15 +1296,20 @@
animator.setTransitionDirection(direction)
.setPipAnimationCallback(mPipAnimationCallback)
.setPipTransactionHandler(mPipTransactionHandler)
- .setDuration(durationMs)
- .start();
- if (rotationDelta != Surface.ROTATION_0 && direction == TRANSITION_DIRECTION_TO_PIP) {
+ .setDuration(durationMs);
+ if (isInPipDirection(direction)) {
+ // Similar to auto-enter-pip transition, we use content overlay when there is no
+ // source rect hint to enter PiP use bounds animation.
+ if (sourceHintRect == null) animator.setUseContentOverlay(mContext);
// The destination bounds are used for the end rect of animation and the final bounds
// after animation finishes. So after the animation is started, the destination bounds
// can be updated to new rotation (computeRotatedBounds has changed the DisplayLayout
// without affecting the animation.
- animator.setDestinationBounds(mPipBoundsAlgorithm.getEntryDestinationBounds());
+ if (rotationDelta != Surface.ROTATION_0) {
+ animator.setDestinationBounds(mPipBoundsAlgorithm.getEntryDestinationBounds());
+ }
}
+ animator.start();
return animator;
}
@@ -1307,6 +1322,14 @@
outDestinationBounds.set(mPipBoundsAlgorithm.getEntryDestinationBounds());
// Transform the destination bounds to current display coordinates.
rotateBounds(outDestinationBounds, displayBounds, mNextRotation, mCurrentRotation);
+ // When entering PiP (from button navigation mode), adjust the source rect hint by
+ // display cutout if applicable.
+ if (sourceHintRect != null && mTaskInfo.displayCutoutInsets != null) {
+ if (rotationDelta == Surface.ROTATION_270) {
+ sourceHintRect.offset(mTaskInfo.displayCutoutInsets.left,
+ mTaskInfo.displayCutoutInsets.top);
+ }
+ }
} else if (direction == TRANSITION_DIRECTION_LEAVE_PIP) {
final Rect rotatedDestinationBounds = new Rect(outDestinationBounds);
rotateBounds(rotatedDestinationBounds, mPipBoundsState.getDisplayBounds(),
@@ -1345,7 +1368,8 @@
/**
* Fades out and removes an overlay surface.
*/
- private void fadeOutAndRemoveOverlay(SurfaceControl surface) {
+ private void fadeOutAndRemoveOverlay(SurfaceControl surface, Runnable callback,
+ boolean withStartDelay) {
if (surface == null) {
return;
}
@@ -1353,24 +1377,43 @@
final ValueAnimator animator = ValueAnimator.ofFloat(1.0f, 0.0f);
animator.setDuration(mCrossFadeAnimationDuration);
animator.addUpdateListener(animation -> {
- final float alpha = (float) animation.getAnimatedValue();
- final SurfaceControl.Transaction transaction =
- mSurfaceControlTransactionFactory.getTransaction();
- transaction.setAlpha(surface, alpha);
- transaction.apply();
+ if (mPipTransitionState.getTransitionState() == PipTransitionState.UNDEFINED) {
+ // Could happen if onTaskVanished happens during the animation since we may have
+ // set a start delay on this animation.
+ Log.d(TAG, "Task vanished, skip fadeOutAndRemoveOverlay");
+ animation.removeAllListeners();
+ animation.removeAllUpdateListeners();
+ animation.cancel();
+ } else {
+ final float alpha = (float) animation.getAnimatedValue();
+ final SurfaceControl.Transaction transaction =
+ mSurfaceControlTransactionFactory.getTransaction();
+ transaction.setAlpha(surface, alpha);
+ transaction.apply();
+ }
});
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- final SurfaceControl.Transaction tx =
- mSurfaceControlTransactionFactory.getTransaction();
- tx.remove(surface);
- tx.apply();
+ removeContentOverlay(surface, callback);
}
});
+ animator.setStartDelay(withStartDelay ? CONTENT_OVERLAY_FADE_OUT_DELAY_MS : 0);
animator.start();
}
+ private void removeContentOverlay(SurfaceControl surface, Runnable callback) {
+ if (mPipTransitionState.getTransitionState() == PipTransitionState.UNDEFINED) {
+ // Avoid double removal, which is fatal.
+ return;
+ }
+ final SurfaceControl.Transaction tx =
+ mSurfaceControlTransactionFactory.getTransaction();
+ tx.remove(surface);
+ tx.apply();
+ if (callback != null) callback.run();
+ }
+
/**
* Dumps internal states.
*/
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index 18153e3..ae17a93 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -18,6 +18,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.util.RotationUtils.deltaRotation;
import static android.view.WindowManager.TRANSIT_PIP;
import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
@@ -151,7 +152,8 @@
mPipTransitionState.setTransitionState(PipTransitionState.ENTERING_PIP);
mFinishCallback = finishCallback;
return startEnterAnimation(enterPip.getTaskInfo(), enterPip.getLeash(),
- startTransaction, finishTransaction);
+ startTransaction, finishTransaction, enterPip.getStartRotation(),
+ enterPip.getEndRotation());
}
@Nullable
@@ -208,7 +210,8 @@
private boolean startEnterAnimation(final TaskInfo taskInfo, final SurfaceControl leash,
final SurfaceControl.Transaction startTransaction,
- final SurfaceControl.Transaction finishTransaction) {
+ final SurfaceControl.Transaction finishTransaction,
+ final int startRotation, final int endRotation) {
setBoundsStateForEntry(taskInfo.topActivity, taskInfo.pictureInPictureParams,
taskInfo.topActivityInfo);
final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
@@ -216,7 +219,8 @@
PipAnimationController.PipTransitionAnimator animator;
finishTransaction.setPosition(leash, destinationBounds.left, destinationBounds.top);
if (taskInfo.pictureInPictureParams != null
- && taskInfo.pictureInPictureParams.isAutoEnterEnabled()) {
+ && taskInfo.pictureInPictureParams.isAutoEnterEnabled()
+ && mPipTransitionState.getInSwipePipToHomeTransition()) {
mOneShotAnimationType = ANIM_TYPE_BOUNDS;
// PiP menu is attached late in the process here to avoid any artifacts on the leash
@@ -234,13 +238,21 @@
mFinishCallback = null;
return true;
}
+
+ int rotationDelta = deltaRotation(endRotation, startRotation);
+ if (rotationDelta != Surface.ROTATION_0) {
+ Matrix tmpTransform = new Matrix();
+ tmpTransform.postRotate(rotationDelta == Surface.ROTATION_90
+ ? Surface.ROTATION_270 : Surface.ROTATION_90);
+ startTransaction.setMatrix(leash, tmpTransform, new float[9]);
+ }
if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) {
final Rect sourceHintRect =
PipBoundsAlgorithm.getValidSourceHintRect(
taskInfo.pictureInPictureParams, currentBounds);
animator = mPipAnimationController.getAnimator(taskInfo, leash, currentBounds,
currentBounds, destinationBounds, sourceHintRect, TRANSITION_DIRECTION_TO_PIP,
- 0 /* startingAngle */, Surface.ROTATION_0);
+ 0 /* startingAngle */, rotationDelta);
} else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
startTransaction.setAlpha(leash, 0f);
// PiP menu is attached late in the process here to avoid any artifacts on the leash
@@ -258,6 +270,7 @@
.setPipAnimationCallback(mPipAnimationCallback)
.setDuration(mEnterExitAnimationDuration)
.start();
+
return true;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionState.java
index d23aada..85e56b7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionState.java
@@ -17,6 +17,9 @@
package com.android.wm.shell.pip;
import android.annotation.IntDef;
+import android.app.PictureInPictureParams;
+import android.content.ComponentName;
+import android.content.pm.ActivityInfo;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -34,6 +37,15 @@
public static final int ENTERED_PIP = 4;
public static final int EXITING_PIP = 5;
+ /**
+ * If set to {@code true}, no entering PiP transition would be kicked off and most likely
+ * it's due to the fact that Launcher is handling the transition directly when swiping
+ * auto PiP-able Activity to home.
+ * See also {@link PipTaskOrganizer#startSwipePipToHome(ComponentName, ActivityInfo,
+ * PictureInPictureParams)}.
+ */
+ private boolean mInSwipePipToHomeTransition;
+
// Not a complete set of states but serves what we want right now.
@IntDef(prefix = { "TRANSITION_STATE_" }, value = {
UNDEFINED,
@@ -65,6 +77,13 @@
&& mState != EXITING_PIP;
}
+ public void setInSwipePipToHomeTransition(boolean inSwipePipToHomeTransition) {
+ mInSwipePipToHomeTransition = inSwipePipToHomeTransition;
+ }
+
+ public boolean getInSwipePipToHomeTransition() {
+ return mInSwipePipToHomeTransition;
+ }
/**
* Resize request can be initiated in other component, ignore if we are no longer in PIP,
* still waiting for animation or we're exiting from it.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
index 1da9577..82092ac 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
@@ -158,14 +158,16 @@
@Override
public void onReleasedInTarget(@NonNull MagnetizedObject.MagneticTarget target) {
- mMainExecutor.executeDelayed(() -> {
- mMotionHelper.notifyDismissalPending();
- mMotionHelper.animateDismiss();
- hideDismissTargetMaybe();
+ if (mEnableDismissDragToEdge) {
+ mMainExecutor.executeDelayed(() -> {
+ mMotionHelper.notifyDismissalPending();
+ mMotionHelper.animateDismiss();
+ hideDismissTargetMaybe();
- mPipUiEventLogger.log(
- PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_DRAG_TO_REMOVE);
- }, 0);
+ mPipUiEventLogger.log(
+ PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_DRAG_TO_REMOVE);
+ }, 0);
+ }
}
});
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index aca545b4..71f23a7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -249,14 +249,17 @@
});
return;
}
- }
- for (int i = 0; i < apps.length; ++i) {
- if (apps[i].mode == MODE_OPENING) {
- t.show(apps[i].leash);
+ } else {
+ for (int i = 0; i < apps.length; ++i) {
+ if (apps[i].mode == MODE_OPENING) {
+ t.show(apps[i].leash);
+ }
}
}
RemoteAnimationTarget divider = mStageCoordinator.getDividerBarLegacyTarget();
- t.show(divider.leash);
+ if (divider.leash != null) {
+ t.show(divider.leash);
+ }
t.apply();
if (cancelled) return;
try {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 81ce2b7..6f23ae5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -620,22 +620,9 @@
}
mSyncQueue.runInSync(t -> {
- final SurfaceControl dividerLeash = mSplitLayout.getDividerLeash();
final SurfaceControl sideStageLeash = mSideStage.mRootLeash;
final SurfaceControl mainStageLeash = mMainStage.mRootLeash;
- if (dividerLeash != null) {
- if (mDividerVisible) {
- t.show(dividerLeash)
- .setLayer(dividerLeash, Integer.MAX_VALUE)
- .setPosition(dividerLeash,
- mSplitLayout.getDividerBounds().left,
- mSplitLayout.getDividerBounds().top);
- } else {
- t.hide(dividerLeash);
- }
- }
-
if (sideStageVisible) {
final Rect sideStageBounds = getSideStageBounds();
t.show(sideStageLeash)
@@ -662,9 +649,30 @@
} else {
t.hide(mainStageLeash);
}
+
+ applyDividerVisibility(t);
});
}
+ private void applyDividerVisibility(SurfaceControl.Transaction t) {
+ final SurfaceControl dividerLeash = mSplitLayout.getDividerLeash();
+ if (dividerLeash == null) {
+ return;
+ }
+
+ if (mDividerVisible) {
+ t.show(dividerLeash)
+ .setLayer(dividerLeash, Integer.MAX_VALUE)
+ .setPosition(dividerLeash,
+ mSplitLayout.getDividerBounds().left,
+ mSplitLayout.getDividerBounds().top);
+ } else {
+ t.hide(dividerLeash);
+ }
+
+ }
+
+
private void onStageHasChildrenChanged(StageListenerImpl stageListener) {
final boolean hasChildren = stageListener.mHasChildren;
final boolean isSideStage = stageListener == mSideStageListener;
@@ -782,6 +790,7 @@
&& mSplitLayout.updateConfiguration(mDisplayAreaInfo.configuration)
&& mMainStage.isActive()) {
onBoundsChanged(mSplitLayout);
+ mSyncQueue.runInSync(t -> applyDividerVisibility(t));
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
index 107a3f8..dff5577 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
@@ -23,6 +23,7 @@
import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SPLASH_SCREEN;
import android.annotation.ColorInt;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.app.ActivityThread;
import android.content.BroadcastReceiver;
@@ -37,6 +38,7 @@
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.AdaptiveIconDrawable;
+import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
@@ -57,11 +59,13 @@
import com.android.internal.graphics.palette.Palette;
import com.android.internal.graphics.palette.Quantizer;
import com.android.internal.graphics.palette.VariationalKMeansQuantizer;
+import com.android.launcher3.icons.BaseIconFactory;
import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.common.TransactionPool;
import java.util.List;
import java.util.function.Consumer;
+import java.util.function.IntPredicate;
import java.util.function.IntSupplier;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;
@@ -130,7 +134,6 @@
* @param splashScreenViewConsumer Receiving the SplashScreenView object, which will also be
* executed on splash screen thread. Note that the view can be
* null if failed.
- * @param bgColorConsumer Receiving the background color once it's estimated complete.
*/
void createContentView(Context context, @StartingWindowType int suggestType, ActivityInfo info,
int taskId, Consumer<SplashScreenView> splashScreenViewConsumer) {
@@ -207,9 +210,9 @@
}
private static int estimateWindowBGColor(Drawable themeBGDrawable) {
- final DrawableColorTester themeBGTester =
- new DrawableColorTester(themeBGDrawable, true /* filterTransparent */);
- if (themeBGTester.nonTransparentRatio() == 0) {
+ final DrawableColorTester themeBGTester = new DrawableColorTester(
+ themeBGDrawable, DrawableColorTester.TRANSPARENT_FILTER /* filterType */);
+ if (themeBGTester.passFilterRatio() == 0) {
// the window background is transparent, unable to draw
Slog.w(TAG, "Window background is transparent, fill background with black color");
return getSystemBGColor();
@@ -368,8 +371,14 @@
if (DEBUG) {
Slog.d(TAG, "The icon is not an AdaptiveIconDrawable");
}
- // TODO process legacy icon(bitmap)
- createIconDrawable(iconDrawable, true);
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "legacy_icon_factory");
+ final ShapeIconFactory factory = new ShapeIconFactory(
+ SplashscreenContentDrawer.this.mContext,
+ scaledIconDpi, mFinalIconSize);
+ final Bitmap bitmap = factory.createScaledBitmapWithoutShadow(
+ iconDrawable, true /* shrinkNonAdaptiveIcons */);
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+ createIconDrawable(new BitmapDrawable(bitmap), true);
}
animationDuration = 0;
}
@@ -377,11 +386,15 @@
return fillViewWithIcon(mFinalIconSize, mFinalIconDrawable, animationDuration);
}
+ private class ShapeIconFactory extends BaseIconFactory {
+ protected ShapeIconFactory(Context context, int fillResIconDpi, int iconBitmapSize) {
+ super(context, fillResIconDpi, iconBitmapSize, true /* shapeDetection */);
+ }
+ }
+
private void createIconDrawable(Drawable iconDrawable, boolean legacy) {
if (legacy) {
mFinalIconDrawable = SplashscreenIconDrawableFactory.makeLegacyIconDrawable(
- mTmpAttrs.mIconBgColor != Color.TRANSPARENT
- ? mTmpAttrs.mIconBgColor : Color.WHITE,
iconDrawable, mDefaultIconSize, mFinalIconSize, mSplashscreenWorkerHandler);
} else {
mFinalIconDrawable = SplashscreenIconDrawableFactory.makeIconDrawable(
@@ -402,7 +415,8 @@
final ColorCache.IconColor iconColor = mColorCache.getIconColor(
mActivityInfo.packageName, mActivityInfo.getIconResource(),
mLastPackageContextConfigHash,
- () -> new DrawableColorTester(iconForeground, true /* filterTransparent */),
+ () -> new DrawableColorTester(iconForeground,
+ DrawableColorTester.TRANSLUCENT_FILTER /* filterType */),
() -> new DrawableColorTester(adaptiveIconDrawable.getBackground()));
if (DEBUG) {
@@ -431,7 +445,7 @@
// Reference AdaptiveIcon description, outer is 108 and inner is 72, so we
// scale by 192/160 if we only draw adaptiveIcon's foreground.
final float noBgScale =
- iconColor.mFgNonTransparentRatio < ENLARGE_FOREGROUND_ICON_THRESHOLD
+ iconColor.mFgNonTranslucentRatio < ENLARGE_FOREGROUND_ICON_THRESHOLD
? NO_BACKGROUND_SCALE : 1f;
// Using AdaptiveIconDrawable here can help keep the shape consistent with the
// current settings.
@@ -533,13 +547,26 @@
}
private static class DrawableColorTester {
+ private static final int NO_ALPHA_FILTER = 0;
+ // filter out completely invisible pixels
+ private static final int TRANSPARENT_FILTER = 1;
+ // filter out translucent and invisible pixels
+ private static final int TRANSLUCENT_FILTER = 2;
+
+ @IntDef(flag = true, value = {
+ NO_ALPHA_FILTER,
+ TRANSPARENT_FILTER,
+ TRANSLUCENT_FILTER
+ })
+ private @interface QuantizerFilterType {}
+
private final ColorTester mColorChecker;
DrawableColorTester(Drawable drawable) {
- this(drawable, false /* filterTransparent */);
+ this(drawable, NO_ALPHA_FILTER /* filterType */);
}
- DrawableColorTester(Drawable drawable, boolean filterTransparent) {
+ DrawableColorTester(Drawable drawable, @QuantizerFilterType int filterType) {
// Some applications use LayerDrawable for their windowBackground. To ensure that we
// only get the real background, so that the color is not affected by the alpha of the
// upper layer, try to get the lower layer here. This can also speed up the calculation.
@@ -558,12 +585,12 @@
} else {
mColorChecker = drawable instanceof ColorDrawable
? new SingleColorTester((ColorDrawable) drawable)
- : new ComplexDrawableTester(drawable, filterTransparent);
+ : new ComplexDrawableTester(drawable, filterType);
}
}
- public float nonTransparentRatio() {
- return mColorChecker.nonTransparentRatio();
+ public float passFilterRatio() {
+ return mColorChecker.passFilterRatio();
}
public boolean isComplexColor() {
@@ -582,7 +609,7 @@
* A help class to check the color information from a Drawable.
*/
private interface ColorTester {
- float nonTransparentRatio();
+ float passFilterRatio();
boolean isComplexColor();
@@ -610,7 +637,7 @@
}
@Override
- public float nonTransparentRatio() {
+ public float passFilterRatio() {
final int alpha = mColorDrawable.getAlpha();
return (float) (alpha / 255);
}
@@ -639,15 +666,21 @@
private static final int MAX_BITMAP_SIZE = 40;
private final Palette mPalette;
private final boolean mFilterTransparent;
- private static final TransparentFilterQuantizer TRANSPARENT_FILTER_QUANTIZER =
- new TransparentFilterQuantizer();
+ private static final AlphaFilterQuantizer ALPHA_FILTER_QUANTIZER =
+ new AlphaFilterQuantizer();
- ComplexDrawableTester(Drawable drawable, boolean filterTransparent) {
+ /**
+ * @param drawable The test target.
+ * @param filterType Targeting to filter out transparent or translucent pixels,
+ * this would be needed if want to check
+ * {@link #passFilterRatio()}, also affecting the estimated result
+ * of the dominant color.
+ */
+ ComplexDrawableTester(Drawable drawable, @QuantizerFilterType int filterType) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "ComplexDrawableTester");
final Rect initialBounds = drawable.copyBounds();
int width = drawable.getIntrinsicWidth();
int height = drawable.getIntrinsicHeight();
-
// Some drawables do not have intrinsic dimensions
if (width <= 0 || height <= 0) {
width = MAX_BITMAP_SIZE;
@@ -668,9 +701,10 @@
// The Palette API will ignore Alpha, so it cannot handle transparent pixels, but
// sometimes we will need this information to know if this Drawable object is
// transparent.
- mFilterTransparent = filterTransparent;
+ mFilterTransparent = filterType != NO_ALPHA_FILTER;
if (mFilterTransparent) {
- builder = new Palette.Builder(bitmap, TRANSPARENT_FILTER_QUANTIZER)
+ ALPHA_FILTER_QUANTIZER.setFilter(filterType);
+ builder = new Palette.Builder(bitmap, ALPHA_FILTER_QUANTIZER)
.maximumColorCount(5);
} else {
builder = new Palette.Builder(bitmap, null)
@@ -682,8 +716,8 @@
}
@Override
- public float nonTransparentRatio() {
- return mFilterTransparent ? TRANSPARENT_FILTER_QUANTIZER.mNonTransparentRatio : 1;
+ public float passFilterRatio() {
+ return mFilterTransparent ? ALPHA_FILTER_QUANTIZER.mPassFilterRatio : 1;
}
@Override
@@ -714,17 +748,34 @@
return true;
}
- private static class TransparentFilterQuantizer implements Quantizer {
+ private static class AlphaFilterQuantizer implements Quantizer {
private static final int NON_TRANSPARENT = 0xFF000000;
private final Quantizer mInnerQuantizer = new VariationalKMeansQuantizer();
- private float mNonTransparentRatio;
+ private final IntPredicate mTransparentFilter = i -> (i & NON_TRANSPARENT) != 0;
+ private final IntPredicate mTranslucentFilter = i ->
+ (i & NON_TRANSPARENT) == NON_TRANSPARENT;
+
+ private IntPredicate mFilter = mTransparentFilter;
+ private float mPassFilterRatio;
+
+ void setFilter(@QuantizerFilterType int filterType) {
+ switch (filterType) {
+ case TRANSLUCENT_FILTER:
+ mFilter = mTranslucentFilter;
+ break;
+ case TRANSPARENT_FILTER:
+ default:
+ mFilter = mTransparentFilter;
+ break;
+ }
+ }
@Override
public void quantize(final int[] pixels, final int maxColors) {
- mNonTransparentRatio = 0;
+ mPassFilterRatio = 0;
int realSize = 0;
for (int i = pixels.length - 1; i > 0; i--) {
- if ((pixels[i] & NON_TRANSPARENT) != 0) {
+ if (mFilter.test(pixels[i])) {
realSize++;
}
}
@@ -735,11 +786,11 @@
mInnerQuantizer.quantize(pixels, maxColors);
return;
}
- mNonTransparentRatio = (float) realSize / pixels.length;
+ mPassFilterRatio = (float) realSize / pixels.length;
final int[] samplePixels = new int[realSize];
int rowIndex = 0;
for (int i = pixels.length - 1; i > 0; i--) {
- if ((pixels[i] & NON_TRANSPARENT) == NON_TRANSPARENT) {
+ if (mFilter.test(pixels[i])) {
samplePixels[rowIndex] = pixels[i];
rowIndex++;
}
@@ -798,16 +849,16 @@
final int mBgColor;
final boolean mIsBgComplex;
final boolean mIsBgGrayscale;
- final float mFgNonTransparentRatio;
+ final float mFgNonTranslucentRatio;
IconColor(int hash, int fgColor, int bgColor, boolean isBgComplex,
- boolean isBgGrayscale, float fgNonTransparentRatio) {
+ boolean isBgGrayscale, float fgNonTranslucnetRatio) {
super(hash);
mFgColor = fgColor;
mBgColor = bgColor;
mIsBgComplex = isBgComplex;
mIsBgGrayscale = isBgGrayscale;
- mFgNonTransparentRatio = fgNonTransparentRatio;
+ mFgNonTranslucentRatio = fgNonTranslucnetRatio;
}
}
@@ -893,7 +944,7 @@
final DrawableColorTester bgTester = bgColorTesterSupplier.get();
final IconColor iconColor = new IconColor(hash, fgTester.getDominateColor(),
bgTester.getDominateColor(), bgTester.isComplexColor(), bgTester.isGrayscale(),
- fgTester.nonTransparentRatio());
+ fgTester.passFilterRatio());
colors.mIconColors[leastUsedIndex[0]] = iconColor;
return iconColor;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
index 211941f..ba9123d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
@@ -64,11 +64,10 @@
}
}
- static Drawable makeLegacyIconDrawable(@ColorInt int backgroundColor,
- @NonNull Drawable foregroundDrawable, int srcIconSize, int iconSize,
- Handler splashscreenWorkerHandler) {
- return new ImmobileIconDrawable(new LegacyIconDrawable(backgroundColor,
- foregroundDrawable), srcIconSize, iconSize, splashscreenWorkerHandler);
+ static Drawable makeLegacyIconDrawable(@NonNull Drawable iconDrawable, int srcIconSize,
+ int iconSize, Handler splashscreenWorkerHandler) {
+ return new ImmobileIconDrawable(iconDrawable, srcIconSize, iconSize,
+ splashscreenWorkerHandler);
}
private static class ImmobileIconDrawable extends Drawable {
@@ -179,65 +178,6 @@
}
}
- private static class LegacyIconDrawable extends MaskBackgroundDrawable {
- // reference FixedScaleDrawable
- // iconBounds = 0.7 * X * outerBounds, X is the scale of diagonal
- private static final float LEGACY_ICON_SCALE = .7f * .8f;
- private final Drawable mForegroundDrawable;
- private float mScaleX, mScaleY, mTransX, mTransY;
-
- LegacyIconDrawable(@ColorInt int backgroundColor, Drawable foregroundDrawable) {
- super(backgroundColor);
- mForegroundDrawable = foregroundDrawable;
- mScaleX = LEGACY_ICON_SCALE;
- mScaleY = LEGACY_ICON_SCALE;
- }
-
- @Override
- protected void updateLayerBounds(Rect bounds) {
- super.updateLayerBounds(bounds);
-
- if (mForegroundDrawable == null) {
- return;
- }
- float outerBoundsWidth = bounds.width();
- float outerBoundsHeight = bounds.height();
- float h = mForegroundDrawable.getIntrinsicHeight();
- float w = mForegroundDrawable.getIntrinsicWidth();
- mScaleX = LEGACY_ICON_SCALE;
- mScaleY = LEGACY_ICON_SCALE;
- if (h > w && w > 0) {
- mScaleX *= w / h;
- } else if (w > h && h > 0) {
- mScaleY *= h / w;
- }
- int innerBoundsWidth = (int) (0.5 + outerBoundsWidth * mScaleX);
- int innerBoundsHeight = (int) (0.5 + outerBoundsHeight * mScaleY);
- final Rect rect = new Rect(0, 0, innerBoundsWidth, innerBoundsHeight);
- mForegroundDrawable.setBounds(rect);
- mTransX = (outerBoundsWidth - innerBoundsWidth) / 2;
- mTransY = (outerBoundsHeight - innerBoundsHeight) / 2;
- invalidateSelf();
- }
-
- @Override
- public void draw(Canvas canvas) {
- super.draw(canvas);
- int saveCount = canvas.save();
- canvas.translate(mTransX, mTransY);
- if (mForegroundDrawable != null) {
- mForegroundDrawable.draw(canvas);
- }
- canvas.restoreToCount(saveCount);
- }
-
- @Override
- public void setColorFilter(ColorFilter colorFilter) {
- if (mForegroundDrawable != null) {
- mForegroundDrawable.setColorFilter(colorFilter);
- }
- }
- }
/**
* A lightweight AdaptiveIconDrawable which support foreground to be Animatable, and keep this
* drawable masked by config_icon_mask.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
index 243751fe..fc7c86d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
@@ -168,16 +168,14 @@
void addSplashScreenStartingWindow(StartingWindowInfo windowInfo, IBinder appToken,
@StartingWindowType int suggestType) {
final RunningTaskInfo taskInfo = windowInfo.taskInfo;
- final ActivityInfo activityInfo = taskInfo.topActivityInfo;
- if (activityInfo == null) {
+ final ActivityInfo activityInfo = windowInfo.targetActivityInfo != null
+ ? windowInfo.targetActivityInfo
+ : taskInfo.topActivityInfo;
+ if (activityInfo == null || activityInfo.packageName == null) {
return;
}
final int displayId = taskInfo.displayId;
- if (activityInfo.packageName == null) {
- return;
- }
-
final int taskId = taskInfo.taskId;
Context context = mContext;
// replace with the default theme if the application didn't set
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt
index 6488e2f..39e89fb 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt
@@ -16,6 +16,7 @@
package com.android.wm.shell.flicker.pip
+import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.RequiresDevice
@@ -66,7 +67,7 @@
}
}
- @Presubmit
+ @Postsubmit
@Test
fun showBothAppWindowsThenHidePip() {
testSpec.assertWm {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
index 284f384..d536adb 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
@@ -214,6 +214,7 @@
final ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo();
taskInfo.topActivityInfo = info;
taskInfo.taskId = taskId;
+ windowInfo.targetActivityInfo = info;
windowInfo.taskInfo = taskInfo;
return windowInfo;
}
diff --git a/libs/hwui/jni/android_graphics_Canvas.cpp b/libs/hwui/jni/android_graphics_Canvas.cpp
index dada5ae9..a4cf028 100644
--- a/libs/hwui/jni/android_graphics_Canvas.cpp
+++ b/libs/hwui/jni/android_graphics_Canvas.cpp
@@ -197,30 +197,53 @@
static_assert(SkRegion::kReverseDifference_Op == static_cast<SkRegion::Op>(SkClipOp::kReverseDifference_deprecated), "");
static_assert(SkRegion::kReplace_Op == static_cast<SkRegion::Op>(SkClipOp::kReplace_deprecated), "");
-static SkClipOp opHandleToClipOp(jint opHandle) {
- // The opHandle is defined in Canvas.java to be Region::Op
- SkRegion::Op rgnOp = static_cast<SkRegion::Op>(opHandle);
-
- // In the future, when we no longer support the wide range of ops (e.g. Union, Xor)
- // this function can perform a range check and throw an unsupported-exception.
- // e.g. if (rgnOp != kIntersect && rgnOp != kDifference) throw...
-
- // Skia now takes a different type, SkClipOp, as the parameter to clipping calls
- // This type is binary compatible with SkRegion::Op, so a static_cast<> is safe.
- return static_cast<SkClipOp>(rgnOp);
-}
-
static jboolean clipRect(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle, jfloat l, jfloat t,
jfloat r, jfloat b, jint opHandle) {
- bool nonEmptyClip = get_canvas(canvasHandle)->clipRect(l, t, r, b,
- opHandleToClipOp(opHandle));
+ // The opHandle is defined in Canvas.java to be Region::Op
+ SkRegion::Op rgnOp = static_cast<SkRegion::Op>(opHandle);
+ bool nonEmptyClip;
+ switch (rgnOp) {
+ case SkRegion::Op::kReplace_Op:
+ // For now replace can still be handled as an SkClipOp but will be emulated in the
+ // future
+ [[fallthrough]];
+ case SkRegion::Op::kIntersect_Op:
+ case SkRegion::Op::kDifference_Op:
+ // Intersect and difference are supported clip operations
+ nonEmptyClip =
+ get_canvas(canvasHandle)->clipRect(l, t, r, b, static_cast<SkClipOp>(rgnOp));
+ break;
+ default:
+ // All other operations would expand the clip and are no longer supported,
+ // so log and skip (to avoid breaking legacy apps).
+ ALOGW("Ignoring unsupported clip operation %d", opHandle);
+ SkRect clipBounds; // ignored
+ nonEmptyClip = get_canvas(canvasHandle)->getClipBounds(&clipBounds);
+ break;
+ }
return nonEmptyClip ? JNI_TRUE : JNI_FALSE;
}
static jboolean clipPath(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle, jlong pathHandle,
jint opHandle) {
+ SkRegion::Op rgnOp = static_cast<SkRegion::Op>(opHandle);
SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
- bool nonEmptyClip = get_canvas(canvasHandle)->clipPath(path, opHandleToClipOp(opHandle));
+ bool nonEmptyClip;
+ switch (rgnOp) {
+ case SkRegion::Op::kReplace_Op:
+ // For now replace can still be handled as an SkClipOp but will be emulated in the
+ // future
+ [[fallthrough]];
+ case SkRegion::Op::kIntersect_Op:
+ case SkRegion::Op::kDifference_Op:
+ nonEmptyClip = get_canvas(canvasHandle)->clipPath(path, static_cast<SkClipOp>(rgnOp));
+ break;
+ default:
+ ALOGW("Ignoring unsupported clip operation %d", opHandle);
+ SkRect clipBounds; // ignored
+ nonEmptyClip = get_canvas(canvasHandle)->getClipBounds(&clipBounds);
+ break;
+ }
return nonEmptyClip ? JNI_TRUE : JNI_FALSE;
}
diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
index afe86cc..db59154 100644
--- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
+++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
@@ -44,8 +44,6 @@
#include <utils/StrongPointer.h>
#include <utils/Timers.h>
-#include <pthread.h>
-
#include <algorithm>
#include <atomic>
#include <vector>
@@ -60,10 +58,6 @@
struct {
jclass clazz;
jmethodID invokePictureCapturedCallback;
- jmethodID createHintSession;
- jmethodID updateTargetWorkDuration;
- jmethodID reportActualWorkDuration;
- jmethodID closeHintSession;
} gHardwareRenderer;
struct {
@@ -90,14 +84,6 @@
return env;
}
-static bool hasExceptionAndClear(JNIEnv* env) {
- if (GraphicsJNI::hasException(env)) {
- env->ExceptionClear();
- return true;
- }
- return false;
-}
-
typedef ANativeWindow* (*ANW_fromSurface)(JNIEnv* env, jobject surface);
ANW_fromSurface fromSurface;
@@ -147,67 +133,6 @@
}
};
-class HintSessionWrapper : public LightRefBase<HintSessionWrapper> {
-public:
- static sp<HintSessionWrapper> create(JNIEnv* env, RenderProxy* proxy) {
- if (!Properties::useHintManager) return nullptr;
-
- // Include UI thread (self), render thread, and thread pool.
- std::vector<int> tids = CommonPool::getThreadIds();
- tids.push_back(proxy->getRenderThreadTid());
- tids.push_back(pthread_gettid_np(pthread_self()));
-
- jintArray tidsArray = env->NewIntArray(tids.size());
- if (hasExceptionAndClear(env)) return nullptr;
- env->SetIntArrayRegion(tidsArray, 0, tids.size(), reinterpret_cast<jint*>(tids.data()));
- if (hasExceptionAndClear(env)) return nullptr;
- jobject session = env->CallStaticObjectMethod(
- gHardwareRenderer.clazz, gHardwareRenderer.createHintSession, tidsArray);
- if (hasExceptionAndClear(env) || !session) return nullptr;
- return new HintSessionWrapper(env, session);
- }
-
- ~HintSessionWrapper() {
- if (!mSession) return;
- JNIEnv* env = getenv(mVm);
- env->CallStaticVoidMethod(gHardwareRenderer.clazz, gHardwareRenderer.closeHintSession,
- mSession);
- hasExceptionAndClear(env);
- env->DeleteGlobalRef(mSession);
- mSession = nullptr;
- }
-
- void updateTargetWorkDuration(long targetDurationNanos) {
- if (!mSession) return;
- JNIEnv* env = getenv(mVm);
- env->CallStaticVoidMethod(gHardwareRenderer.clazz,
- gHardwareRenderer.updateTargetWorkDuration, mSession,
- static_cast<jlong>(targetDurationNanos));
- hasExceptionAndClear(env);
- }
-
- void reportActualWorkDuration(long actualDurationNanos) {
- if (!mSession) return;
- JNIEnv* env = getenv(mVm);
- env->CallStaticVoidMethod(gHardwareRenderer.clazz,
- gHardwareRenderer.reportActualWorkDuration, mSession,
- static_cast<jlong>(actualDurationNanos));
- hasExceptionAndClear(env);
- }
-
-private:
- HintSessionWrapper(JNIEnv* env, jobject jobject) {
- env->GetJavaVM(&mVm);
- if (jobject) {
- mSession = env->NewGlobalRef(jobject);
- LOG_ALWAYS_FATAL_IF(!mSession, "Failed to make global ref");
- }
- }
-
- JavaVM* mVm = nullptr;
- jobject mSession = nullptr;
-};
-
static void android_view_ThreadedRenderer_rotateProcessStatsBuffer(JNIEnv* env, jobject clazz) {
RenderProxy::rotateProcessStatsBuffer();
}
@@ -235,12 +160,6 @@
RootRenderNode* rootRenderNode = reinterpret_cast<RootRenderNode*>(rootRenderNodePtr);
ContextFactoryImpl factory(rootRenderNode);
RenderProxy* proxy = new RenderProxy(translucent, rootRenderNode, &factory);
- sp<HintSessionWrapper> wrapper = HintSessionWrapper::create(env, proxy);
- if (wrapper) {
- proxy->setHintSessionCallbacks(
- [wrapper](int64_t nanos) { wrapper->updateTargetWorkDuration(nanos); },
- [wrapper](int64_t nanos) { wrapper->reportActualWorkDuration(nanos); });
- }
return (jlong) proxy;
}
@@ -1069,18 +988,6 @@
gHardwareRenderer.invokePictureCapturedCallback = GetStaticMethodIDOrDie(env, hardwareRenderer,
"invokePictureCapturedCallback",
"(JLandroid/graphics/HardwareRenderer$PictureCapturedCallback;)V");
- gHardwareRenderer.createHintSession =
- GetStaticMethodIDOrDie(env, hardwareRenderer, "createHintSession",
- "([I)Landroid/os/PerformanceHintManager$Session;");
- gHardwareRenderer.updateTargetWorkDuration =
- GetStaticMethodIDOrDie(env, hardwareRenderer, "updateTargetWorkDuration",
- "(Landroid/os/PerformanceHintManager$Session;J)V");
- gHardwareRenderer.reportActualWorkDuration =
- GetStaticMethodIDOrDie(env, hardwareRenderer, "reportActualWorkDuration",
- "(Landroid/os/PerformanceHintManager$Session;J)V");
- gHardwareRenderer.closeHintSession =
- GetStaticMethodIDOrDie(env, hardwareRenderer, "closeHintSession",
- "(Landroid/os/PerformanceHintManager$Session;)V");
jclass aSurfaceTransactionCallbackClass =
FindClassOrDie(env, "android/graphics/HardwareRenderer$ASurfaceTransactionCallback");
diff --git a/libs/hwui/jni/text/TextShaper.cpp b/libs/hwui/jni/text/TextShaper.cpp
index a6fb958..8e4dd53 100644
--- a/libs/hwui/jni/text/TextShaper.cpp
+++ b/libs/hwui/jni/text/TextShaper.cpp
@@ -160,7 +160,6 @@
}
static const JNINativeMethod gMethods[] = {
- // Fast Natives
{"nativeShapeTextRun", "("
"[C" // text
"I" // start
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index db29e34..e7081df 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -16,6 +16,7 @@
#include "DrawFrameTask.h"
+#include <dlfcn.h>
#include <gui/TraceUtils.h>
#include <utils/Log.h>
#include <algorithm>
@@ -26,11 +27,63 @@
#include "../RenderNode.h"
#include "CanvasContext.h"
#include "RenderThread.h"
+#include "thread/CommonPool.h"
namespace android {
namespace uirenderer {
namespace renderthread {
+namespace {
+
+typedef APerformanceHintManager* (*APH_getManager)();
+typedef APerformanceHintSession* (*APH_createSession)(APerformanceHintManager*, const int32_t*,
+ size_t, int64_t);
+typedef void (*APH_updateTargetWorkDuration)(APerformanceHintSession*, int64_t);
+typedef void (*APH_reportActualWorkDuration)(APerformanceHintSession*, int64_t);
+typedef void (*APH_closeSession)(APerformanceHintSession* session);
+
+bool gAPerformanceHintBindingInitialized = false;
+APH_getManager gAPH_getManagerFn = nullptr;
+APH_createSession gAPH_createSessionFn = nullptr;
+APH_updateTargetWorkDuration gAPH_updateTargetWorkDurationFn = nullptr;
+APH_reportActualWorkDuration gAPH_reportActualWorkDurationFn = nullptr;
+APH_closeSession gAPH_closeSessionFn = nullptr;
+
+void ensureAPerformanceHintBindingInitialized() {
+ if (gAPerformanceHintBindingInitialized) return;
+
+ void* handle_ = dlopen("libandroid.so", RTLD_NOW | RTLD_NODELETE);
+ LOG_ALWAYS_FATAL_IF(handle_ == nullptr, "Failed to dlopen libandroid.so!");
+
+ gAPH_getManagerFn = (APH_getManager)dlsym(handle_, "APerformanceHint_getManager");
+ LOG_ALWAYS_FATAL_IF(gAPH_getManagerFn == nullptr,
+ "Failed to find required symbol APerformanceHint_getManager!");
+
+ gAPH_createSessionFn = (APH_createSession)dlsym(handle_, "APerformanceHint_createSession");
+ LOG_ALWAYS_FATAL_IF(gAPH_createSessionFn == nullptr,
+ "Failed to find required symbol APerformanceHint_createSession!");
+
+ gAPH_updateTargetWorkDurationFn = (APH_updateTargetWorkDuration)dlsym(
+ handle_, "APerformanceHint_updateTargetWorkDuration");
+ LOG_ALWAYS_FATAL_IF(
+ gAPH_updateTargetWorkDurationFn == nullptr,
+ "Failed to find required symbol APerformanceHint_updateTargetWorkDuration!");
+
+ gAPH_reportActualWorkDurationFn = (APH_reportActualWorkDuration)dlsym(
+ handle_, "APerformanceHint_reportActualWorkDuration");
+ LOG_ALWAYS_FATAL_IF(
+ gAPH_reportActualWorkDurationFn == nullptr,
+ "Failed to find required symbol APerformanceHint_reportActualWorkDuration!");
+
+ gAPH_closeSessionFn = (APH_closeSession)dlsym(handle_, "APerformanceHint_closeSession");
+ LOG_ALWAYS_FATAL_IF(gAPH_closeSessionFn == nullptr,
+ "Failed to find required symbol APerformanceHint_closeSession!");
+
+ gAPerformanceHintBindingInitialized = true;
+}
+
+} // namespace
+
DrawFrameTask::DrawFrameTask()
: mRenderThread(nullptr)
, mContext(nullptr)
@@ -39,17 +92,13 @@
DrawFrameTask::~DrawFrameTask() {}
-void DrawFrameTask::setContext(RenderThread* thread, CanvasContext* context,
- RenderNode* targetNode) {
+void DrawFrameTask::setContext(RenderThread* thread, CanvasContext* context, RenderNode* targetNode,
+ int32_t uiThreadId, int32_t renderThreadId) {
mRenderThread = thread;
mContext = context;
mTargetNode = targetNode;
-}
-
-void DrawFrameTask::setHintSessionCallbacks(std::function<void(int64_t)> updateTargetWorkDuration,
- std::function<void(int64_t)> reportActualWorkDuration) {
- mUpdateTargetWorkDuration = std::move(updateTargetWorkDuration);
- mReportActualWorkDuration = std::move(reportActualWorkDuration);
+ mUiThreadId = uiThreadId;
+ mRenderThreadId = renderThreadId;
}
void DrawFrameTask::pushLayerUpdate(DeferredLayerUpdater* layer) {
@@ -144,27 +193,25 @@
unblockUiThread();
}
- // These member callbacks are effectively const as they are set once during init, so it's safe
- // to use these directly instead of making local copies.
- if (mUpdateTargetWorkDuration && mReportActualWorkDuration) {
- constexpr int64_t kSanityCheckLowerBound = 100000; // 0.1ms
- constexpr int64_t kSanityCheckUpperBound = 10000000000; // 10s
- int64_t targetWorkDuration = frameDeadline - intendedVsync;
- targetWorkDuration = targetWorkDuration * Properties::targetCpuTimePercentage / 100;
- if (targetWorkDuration > kSanityCheckLowerBound &&
- targetWorkDuration < kSanityCheckUpperBound &&
- targetWorkDuration != mLastTargetWorkDuration) {
- mLastTargetWorkDuration = targetWorkDuration;
- mUpdateTargetWorkDuration(targetWorkDuration);
- }
- int64_t frameDuration = systemTime(SYSTEM_TIME_MONOTONIC) - frameStartTime;
- int64_t actualDuration = frameDuration -
- (std::min(syncDelayDuration, mLastDequeueBufferDuration)) -
- dequeueBufferDuration;
- if (actualDuration > kSanityCheckLowerBound && actualDuration < kSanityCheckUpperBound) {
- mReportActualWorkDuration(actualDuration);
- }
+ if (!mHintSessionWrapper) mHintSessionWrapper.emplace(mUiThreadId, mRenderThreadId);
+ constexpr int64_t kSanityCheckLowerBound = 100000; // 0.1ms
+ constexpr int64_t kSanityCheckUpperBound = 10000000000; // 10s
+ int64_t targetWorkDuration = frameDeadline - intendedVsync;
+ targetWorkDuration = targetWorkDuration * Properties::targetCpuTimePercentage / 100;
+ if (targetWorkDuration > kSanityCheckLowerBound &&
+ targetWorkDuration < kSanityCheckUpperBound &&
+ targetWorkDuration != mLastTargetWorkDuration) {
+ mLastTargetWorkDuration = targetWorkDuration;
+ mHintSessionWrapper->updateTargetWorkDuration(targetWorkDuration);
}
+ int64_t frameDuration = systemTime(SYSTEM_TIME_MONOTONIC) - frameStartTime;
+ int64_t actualDuration = frameDuration -
+ (std::min(syncDelayDuration, mLastDequeueBufferDuration)) -
+ dequeueBufferDuration;
+ if (actualDuration > kSanityCheckLowerBound && actualDuration < kSanityCheckUpperBound) {
+ mHintSessionWrapper->reportActualWorkDuration(actualDuration);
+ }
+
mLastDequeueBufferDuration = dequeueBufferDuration;
}
@@ -216,6 +263,44 @@
mSignal.signal();
}
+DrawFrameTask::HintSessionWrapper::HintSessionWrapper(int32_t uiThreadId, int32_t renderThreadId) {
+ if (!Properties::useHintManager) return;
+ if (uiThreadId < 0 || renderThreadId < 0) return;
+
+ ensureAPerformanceHintBindingInitialized();
+
+ APerformanceHintManager* manager = gAPH_getManagerFn();
+ if (!manager) return;
+
+ std::vector<int32_t> tids = CommonPool::getThreadIds();
+ tids.push_back(uiThreadId);
+ tids.push_back(renderThreadId);
+
+ // DrawFrameTask code will always set a target duration before reporting actual durations.
+ // So this is just a placeholder value that's never used.
+ int64_t dummyTargetDurationNanos = 16666667;
+ mHintSession =
+ gAPH_createSessionFn(manager, tids.data(), tids.size(), dummyTargetDurationNanos);
+}
+
+DrawFrameTask::HintSessionWrapper::~HintSessionWrapper() {
+ if (mHintSession) {
+ gAPH_closeSessionFn(mHintSession);
+ }
+}
+
+void DrawFrameTask::HintSessionWrapper::updateTargetWorkDuration(long targetDurationNanos) {
+ if (mHintSession) {
+ gAPH_updateTargetWorkDurationFn(mHintSession, targetDurationNanos);
+ }
+}
+
+void DrawFrameTask::HintSessionWrapper::reportActualWorkDuration(long actualDurationNanos) {
+ if (mHintSession) {
+ gAPH_reportActualWorkDurationFn(mHintSession, actualDurationNanos);
+ }
+}
+
} /* namespace renderthread */
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h
index 2455ea8..6a61a2b 100644
--- a/libs/hwui/renderthread/DrawFrameTask.h
+++ b/libs/hwui/renderthread/DrawFrameTask.h
@@ -16,8 +16,10 @@
#ifndef DRAWFRAMETASK_H
#define DRAWFRAMETASK_H
+#include <optional>
#include <vector>
+#include <performance_hint_private.h>
#include <utils/Condition.h>
#include <utils/Mutex.h>
#include <utils/StrongPointer.h>
@@ -60,9 +62,8 @@
DrawFrameTask();
virtual ~DrawFrameTask();
- void setContext(RenderThread* thread, CanvasContext* context, RenderNode* targetNode);
- void setHintSessionCallbacks(std::function<void(int64_t)> updateTargetWorkDuration,
- std::function<void(int64_t)> reportActualWorkDuration);
+ void setContext(RenderThread* thread, CanvasContext* context, RenderNode* targetNode,
+ int32_t uiThreadId, int32_t renderThreadId);
void setContentDrawBounds(int left, int top, int right, int bottom) {
mContentDrawBounds.set(left, top, right, bottom);
}
@@ -85,6 +86,18 @@
}
private:
+ class HintSessionWrapper {
+ public:
+ HintSessionWrapper(int32_t uiThreadId, int32_t renderThreadId);
+ ~HintSessionWrapper();
+
+ void updateTargetWorkDuration(long targetDurationNanos);
+ void reportActualWorkDuration(long actualDurationNanos);
+
+ private:
+ APerformanceHintSession* mHintSession = nullptr;
+ };
+
void postAndWait();
bool syncFrameState(TreeInfo& info);
void unblockUiThread();
@@ -95,6 +108,8 @@
RenderThread* mRenderThread;
CanvasContext* mContext;
RenderNode* mTargetNode = nullptr;
+ int32_t mUiThreadId = -1;
+ int32_t mRenderThreadId = -1;
Rect mContentDrawBounds;
/*********************************************
@@ -112,8 +127,7 @@
nsecs_t mLastDequeueBufferDuration = 0;
nsecs_t mLastTargetWorkDuration = 0;
- std::function<void(int64_t)> mUpdateTargetWorkDuration;
- std::function<void(int64_t)> mReportActualWorkDuration;
+ std::optional<HintSessionWrapper> mHintSessionWrapper;
};
} /* namespace renderthread */
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index a77b5b5..c485ce2 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -29,6 +29,8 @@
#include "utils/Macros.h"
#include "utils/TimeUtils.h"
+#include <pthread.h>
+
namespace android {
namespace uirenderer {
namespace renderthread {
@@ -39,7 +41,8 @@
mContext = mRenderThread.queue().runSync([&]() -> CanvasContext* {
return CanvasContext::create(mRenderThread, translucent, rootRenderNode, contextFactory);
});
- mDrawFrameTask.setContext(&mRenderThread, mContext, rootRenderNode);
+ mDrawFrameTask.setContext(&mRenderThread, mContext, rootRenderNode,
+ pthread_gettid_np(pthread_self()), getRenderThreadTid());
}
RenderProxy::~RenderProxy() {
@@ -48,7 +51,7 @@
void RenderProxy::destroyContext() {
if (mContext) {
- mDrawFrameTask.setContext(nullptr, nullptr, nullptr);
+ mDrawFrameTask.setContext(nullptr, nullptr, nullptr, -1, -1);
// This is also a fence as we need to be certain that there are no
// outstanding mDrawFrame tasks posted before it is destroyed
mRenderThread.queue().runSync([this]() { delete mContext; });
@@ -76,12 +79,6 @@
mRenderThread.queue().runSync([this, name]() { mContext->setName(std::string(name)); });
}
-void RenderProxy::setHintSessionCallbacks(std::function<void(int64_t)> updateTargetWorkDuration,
- std::function<void(int64_t)> reportActualWorkDuration) {
- mDrawFrameTask.setHintSessionCallbacks(std::move(updateTargetWorkDuration),
- std::move(reportActualWorkDuration));
-}
-
void RenderProxy::setSurface(ANativeWindow* window, bool enableTimeout) {
if (window) { ANativeWindow_acquire(window); }
mRenderThread.queue().post([this, win = window, enableTimeout]() mutable {
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 1b0f22e..2b5405c 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -71,8 +71,6 @@
void setSwapBehavior(SwapBehavior swapBehavior);
bool loadSystemProperties();
void setName(const char* name);
- void setHintSessionCallbacks(std::function<void(int64_t)> updateTargetWorkDuration,
- std::function<void(int64_t)> reportActualWorkDuration);
void setSurface(ANativeWindow* window, bool enableTimeout = true);
void setSurfaceControl(ASurfaceControl* surfaceControl);
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 521cbcb..85baa3d 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -72,6 +72,37 @@
Finally, you request (or receive) a filled output buffer, consume its contents and release it
back to the codec.
+ <h3 id=qualityFloor><a name="qualityFloor">Minimum Quality Floor for Video Encoding</h3>
+ <p>
+ Beginning with {@link android.os.Build.VERSION_CODES#S}, Android's Video MediaCodecs enforce a
+ minimum quality floor. The intent is to eliminate poor quality video encodings. This quality
+ floor is applied when the codec is in Variable Bitrate (VBR) mode; it is not applied when
+ the codec is in Constant Bitrate (CBR) mode. The quality floor enforcement is also restricted
+ to a particular size range; this size range is currently for video resolutions
+ larger than 320x240 up through 1920x1080.
+
+ <p>
+ When this quality floor is in effect, the codec and supporting framework code will work to
+ ensure that the generated video is of at least a "fair" or "good" quality. The metric
+ used to choose these targets is the VMAF (Video Multi-method Assessment Function) with a
+ target score of 70 for selected test sequences.
+
+ <p>
+ The typical effect is that
+ some videos will generate a higher bitrate than originally configured. This will be most
+ notable for videos which were configured with very low bitrates; the codec will use a bitrate
+ that is determined to be more likely to generate an "fair" or "good" quality video. Another
+ situation is where a video includes very complicated content (lots of motion and detail);
+ in such configurations, the codec will use extra bitrate as needed to avoid losing all of
+ the content's finer detail.
+
+ <p>
+ This quality floor will not impact content captured at high bitrates (a high bitrate should
+ already provide the codec with sufficient capacity to encode all of the detail).
+ The quality floor does not operate on CBR encodings.
+ The quality floor currently does not operate on resolutions of 320x240 or lower, nor on
+ videos with resolution above 1920x1080.
+
<h3>Data Types</h3>
<p>
Codecs operate on three kinds of data: compressed data, raw audio data and raw video data.
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index f49e045..77c1e55b 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -1100,6 +1100,13 @@
* clipped internally to ensure the video recording can proceed smoothly based on
* the capabilities of the platform.
*
+ * <p>
+ * NB: the actual bitrate and other encoding characteristics may be affected by
+ * the minimum quality floor behavior introduced in
+ * {@link android.os.Build.VERSION_CODES#S}. More detail on how and where this
+ * impacts video encoding can be found in the
+ * {@link MediaCodec} page and looking for "quality floor" (near the top of the page).
+ *
* @param bitRate the video encoding bit rate in bits per second.
*/
public void setVideoEncodingBitRate(int bitRate) {
diff --git a/media/jni/android_mtp_MtpDevice.cpp b/media/jni/android_mtp_MtpDevice.cpp
index ac89fecd..8436ba4 100644
--- a/media/jni/android_mtp_MtpDevice.cpp
+++ b/media/jni/android_mtp_MtpDevice.cpp
@@ -416,20 +416,14 @@
return -1;
}
- MtpProperty* property = new MtpProperty(MTP_DEVICE_PROPERTY_SESSION_INITIATOR_VERSION_INFO,
- MTP_TYPE_STR, true);
- if (!property) {
- env->ThrowNew(clazz_io_exception, "Failed to obtain property.");
- return -1;
- }
-
- if (property->getDataType() != MTP_TYPE_STR) {
+ MtpProperty property(MTP_DEVICE_PROPERTY_SESSION_INITIATOR_VERSION_INFO, MTP_TYPE_STR, true);
+ if (property.getDataType() != MTP_TYPE_STR) {
env->ThrowNew(clazz_io_exception, "Unexpected property data type.");
return -1;
}
- property->setCurrentValue(propertyStr);
- if (!device->setDevicePropValueStr(property)) {
+ property.setCurrentValue(propertyStr);
+ if (!device->setDevicePropValueStr(&property)) {
env->ThrowNew(clazz_io_exception, "Failed to obtain property value.");
return -1;
}
diff --git a/native/android/Android.bp b/native/android/Android.bp
index 3ee2c18..32b7a07 100644
--- a/native/android/Android.bp
+++ b/native/android/Android.bp
@@ -57,6 +57,7 @@
"net.c",
"obb.cpp",
"permission_manager.cpp",
+ "performance_hint.cpp",
"sensor.cpp",
"sharedmem.cpp",
"storage_manager.cpp",
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index de6db1a..f33e118 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -312,6 +312,13 @@
LIBANDROID_PLATFORM {
global:
+ APerformanceHint_getManager;
+ APerformanceHint_createSession;
+ APerformanceHint_getPreferredUpdateRateNanos;
+ APerformanceHint_updateTargetWorkDuration;
+ APerformanceHint_reportActualWorkDuration;
+ APerformanceHint_closeSession;
+ APerformanceHint_setIHintManagerForTesting;
extern "C++" {
ASurfaceControl_registerSurfaceStatsListener*;
ASurfaceControl_unregisterSurfaceStatsListener*;
diff --git a/native/android/performance_hint.cpp b/native/android/performance_hint.cpp
new file mode 100644
index 0000000..95a2da9
--- /dev/null
+++ b/native/android/performance_hint.cpp
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "perf_hint"
+
+#include <utility>
+#include <vector>
+
+#include <android/os/IHintManager.h>
+#include <android/os/IHintSession.h>
+#include <binder/Binder.h>
+#include <binder/IBinder.h>
+#include <binder/IServiceManager.h>
+#include <performance_hint_private.h>
+#include <utils/SystemClock.h>
+
+using namespace android;
+using namespace android::os;
+
+struct APerformanceHintSession;
+
+struct APerformanceHintManager {
+public:
+ static APerformanceHintManager* getInstance();
+ APerformanceHintManager(sp<IHintManager> service, int64_t preferredRateNanos);
+ APerformanceHintManager() = delete;
+ ~APerformanceHintManager() = default;
+
+ APerformanceHintSession* createSession(const int32_t* threadIds, size_t size,
+ int64_t initialTargetWorkDurationNanos);
+ int64_t getPreferredRateNanos() const;
+
+private:
+ static APerformanceHintManager* create(sp<IHintManager> iHintManager);
+
+ sp<IHintManager> mHintManager;
+ const int64_t mPreferredRateNanos;
+};
+
+struct APerformanceHintSession {
+public:
+ APerformanceHintSession(sp<IHintSession> session, int64_t preferredRateNanos,
+ int64_t targetDurationNanos);
+ APerformanceHintSession() = delete;
+ ~APerformanceHintSession();
+
+ int updateTargetWorkDuration(int64_t targetDurationNanos);
+ int reportActualWorkDuration(int64_t actualDurationNanos);
+
+private:
+ friend struct APerformanceHintManager;
+
+ sp<IHintSession> mHintSession;
+ // HAL preferred update rate
+ const int64_t mPreferredRateNanos;
+ // Target duration for choosing update rate
+ int64_t mTargetDurationNanos;
+ // Last update timestamp
+ int64_t mLastUpdateTimestamp;
+ // Cached samples
+ std::vector<int64_t> mActualDurationsNanos;
+ std::vector<int64_t> mTimestampsNanos;
+};
+
+static IHintManager* gIHintManagerForTesting = nullptr;
+static APerformanceHintManager* gHintManagerForTesting = nullptr;
+
+// ===================================== APerformanceHintManager implementation
+APerformanceHintManager::APerformanceHintManager(sp<IHintManager> manager,
+ int64_t preferredRateNanos)
+ : mHintManager(std::move(manager)), mPreferredRateNanos(preferredRateNanos) {}
+
+APerformanceHintManager* APerformanceHintManager::getInstance() {
+ if (gHintManagerForTesting) return gHintManagerForTesting;
+ if (gIHintManagerForTesting) {
+ APerformanceHintManager* manager = create(gIHintManagerForTesting);
+ gIHintManagerForTesting = nullptr;
+ return manager;
+ }
+ static APerformanceHintManager* instance = create(nullptr);
+ return instance;
+}
+
+APerformanceHintManager* APerformanceHintManager::create(sp<IHintManager> manager) {
+ if (!manager) {
+ manager = interface_cast<IHintManager>(
+ defaultServiceManager()->checkService(String16("performance_hint")));
+ }
+ if (manager == nullptr) {
+ ALOGE("%s: PerformanceHint service is not ready ", __FUNCTION__);
+ return nullptr;
+ }
+ int64_t preferredRateNanos = -1L;
+ binder::Status ret = manager->getHintSessionPreferredRate(&preferredRateNanos);
+ if (!ret.isOk()) {
+ ALOGE("%s: PerformanceHint cannot get preferred rate. %s", __FUNCTION__,
+ ret.exceptionMessage().c_str());
+ return nullptr;
+ }
+ if (preferredRateNanos <= 0) {
+ ALOGE("%s: PerformanceHint invalid preferred rate.", __FUNCTION__);
+ return nullptr;
+ }
+ return new APerformanceHintManager(std::move(manager), preferredRateNanos);
+}
+
+APerformanceHintSession* APerformanceHintManager::createSession(
+ const int32_t* threadIds, size_t size, int64_t initialTargetWorkDurationNanos) {
+ sp<IBinder> token = sp<BBinder>::make();
+ std::vector<int32_t> tids(threadIds, threadIds + size);
+ sp<IHintSession> session;
+ binder::Status ret =
+ mHintManager->createHintSession(token, tids, initialTargetWorkDurationNanos, &session);
+ if (!ret.isOk() || !session) {
+ return nullptr;
+ }
+ return new APerformanceHintSession(std::move(session), mPreferredRateNanos,
+ initialTargetWorkDurationNanos);
+}
+
+int64_t APerformanceHintManager::getPreferredRateNanos() const {
+ return mPreferredRateNanos;
+}
+
+// ===================================== APerformanceHintSession implementation
+
+APerformanceHintSession::APerformanceHintSession(sp<IHintSession> session,
+ int64_t preferredRateNanos,
+ int64_t targetDurationNanos)
+ : mHintSession(std::move(session)),
+ mPreferredRateNanos(preferredRateNanos),
+ mTargetDurationNanos(targetDurationNanos),
+ mLastUpdateTimestamp(elapsedRealtimeNano()) {}
+
+APerformanceHintSession::~APerformanceHintSession() {
+ binder::Status ret = mHintSession->close();
+ if (!ret.isOk()) {
+ ALOGE("%s: HintSession close failed: %s", __FUNCTION__, ret.exceptionMessage().c_str());
+ }
+}
+
+int APerformanceHintSession::updateTargetWorkDuration(int64_t targetDurationNanos) {
+ if (targetDurationNanos <= 0) {
+ ALOGE("%s: targetDurationNanos must be positive", __FUNCTION__);
+ return EINVAL;
+ }
+ binder::Status ret = mHintSession->updateTargetWorkDuration(targetDurationNanos);
+ if (!ret.isOk()) {
+ ALOGE("%s: HintSessionn updateTargetWorkDuration failed: %s", __FUNCTION__,
+ ret.exceptionMessage().c_str());
+ return EPIPE;
+ }
+ mTargetDurationNanos = targetDurationNanos;
+ /**
+ * Most of the workload is target_duration dependent, so now clear the cached samples
+ * as they are most likely obsolete.
+ */
+ mActualDurationsNanos.clear();
+ mTimestampsNanos.clear();
+ mLastUpdateTimestamp = elapsedRealtimeNano();
+ return 0;
+}
+
+int APerformanceHintSession::reportActualWorkDuration(int64_t actualDurationNanos) {
+ if (actualDurationNanos <= 0) {
+ ALOGE("%s: actualDurationNanos must be positive", __FUNCTION__);
+ return EINVAL;
+ }
+ int64_t now = elapsedRealtimeNano();
+ mActualDurationsNanos.push_back(actualDurationNanos);
+ mTimestampsNanos.push_back(now);
+
+ /**
+ * Use current sample to determine the rate limit. We can pick a shorter rate limit
+ * if any sample underperformed, however, it could be the lower level system is slow
+ * to react. So here we explicitly choose the rate limit with the latest sample.
+ */
+ int64_t rateLimit = actualDurationNanos > mTargetDurationNanos ? mPreferredRateNanos
+ : 10 * mPreferredRateNanos;
+ if (now - mLastUpdateTimestamp <= rateLimit) return 0;
+
+ binder::Status ret =
+ mHintSession->reportActualWorkDuration(mActualDurationsNanos, mTimestampsNanos);
+ mActualDurationsNanos.clear();
+ mTimestampsNanos.clear();
+ if (!ret.isOk()) {
+ ALOGE("%s: HintSession reportActualWorkDuration failed: %s", __FUNCTION__,
+ ret.exceptionMessage().c_str());
+ return EPIPE;
+ }
+ mLastUpdateTimestamp = now;
+ return 0;
+}
+
+// ===================================== C API
+APerformanceHintManager* APerformanceHint_getManager() {
+ return APerformanceHintManager::getInstance();
+}
+
+APerformanceHintSession* APerformanceHint_createSession(APerformanceHintManager* manager,
+ const int32_t* threadIds, size_t size,
+ int64_t initialTargetWorkDurationNanos) {
+ return manager->createSession(threadIds, size, initialTargetWorkDurationNanos);
+}
+
+int64_t APerformanceHint_getPreferredUpdateRateNanos(APerformanceHintManager* manager) {
+ return manager->getPreferredRateNanos();
+}
+
+int APerformanceHint_updateTargetWorkDuration(APerformanceHintSession* session,
+ int64_t targetDurationNanos) {
+ return session->updateTargetWorkDuration(targetDurationNanos);
+}
+
+int APerformanceHint_reportActualWorkDuration(APerformanceHintSession* session,
+ int64_t actualDurationNanos) {
+ return session->reportActualWorkDuration(actualDurationNanos);
+}
+
+void APerformanceHint_closeSession(APerformanceHintSession* session) {
+ delete session;
+}
+
+void APerformanceHint_setIHintManagerForTesting(void* iManager) {
+ delete gHintManagerForTesting;
+ gHintManagerForTesting = nullptr;
+ gIHintManagerForTesting = static_cast<IHintManager*>(iManager);
+}
diff --git a/native/android/tests/performance_hint/Android.bp b/native/android/tests/performance_hint/Android.bp
new file mode 100644
index 0000000..fdc1bc6
--- /dev/null
+++ b/native/android/tests/performance_hint/Android.bp
@@ -0,0 +1,65 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // 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"],
+}
+
+cc_test {
+ name: "PerformanceHintNativeTestCases",
+
+ multilib: {
+ lib32: {
+ suffix: "32",
+ },
+ lib64: {
+ suffix: "64",
+ },
+ },
+
+ srcs: ["PerformanceHintNativeTest.cpp"],
+
+ shared_libs: [
+ "libandroid",
+ "liblog",
+ "libbinder",
+ "libpowermanager",
+ "libutils",
+ ],
+
+ static_libs: [
+ "libbase",
+ "libgmock",
+ "libgtest",
+ ],
+ stl: "c++_shared",
+
+ test_suites: [
+ "device-tests",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+
+ header_libs: [
+ "libandroid_headers_private",
+ ],
+}
diff --git a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
new file mode 100644
index 0000000..284e9ee
--- /dev/null
+++ b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "PerformanceHintNativeTest"
+
+#include <android/os/IHintManager.h>
+#include <android/os/IHintSession.h>
+#include <binder/IBinder.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <performance_hint_private.h>
+#include <memory>
+#include <vector>
+
+using android::binder::Status;
+using android::os::IHintManager;
+using android::os::IHintSession;
+
+using namespace android;
+using namespace testing;
+
+class MockIHintManager : public IHintManager {
+public:
+ MOCK_METHOD(Status, createHintSession,
+ (const ::android::sp<::android::IBinder>& token, const ::std::vector<int32_t>& tids,
+ int64_t durationNanos, ::android::sp<::android::os::IHintSession>* _aidl_return),
+ (override));
+ MOCK_METHOD(Status, getHintSessionPreferredRate, (int64_t * _aidl_return), (override));
+ MOCK_METHOD(IBinder*, onAsBinder, (), (override));
+};
+
+class MockIHintSession : public IHintSession {
+public:
+ MOCK_METHOD(Status, updateTargetWorkDuration, (int64_t targetDurationNanos), (override));
+ MOCK_METHOD(Status, reportActualWorkDuration,
+ (const ::std::vector<int64_t>& actualDurationNanos,
+ const ::std::vector<int64_t>& timeStampNanos),
+ (override));
+ MOCK_METHOD(Status, close, (), (override));
+ MOCK_METHOD(IBinder*, onAsBinder, (), (override));
+};
+
+class PerformanceHintTest : public Test {
+public:
+ void SetUp() override {
+ mMockIHintManager = new StrictMock<MockIHintManager>();
+ APerformanceHint_setIHintManagerForTesting(mMockIHintManager);
+ }
+
+ void TearDown() override {
+ mMockIHintManager = nullptr;
+ // Destroys MockIHintManager.
+ APerformanceHint_setIHintManagerForTesting(nullptr);
+ }
+
+ APerformanceHintManager* createManager() {
+ EXPECT_CALL(*mMockIHintManager, getHintSessionPreferredRate(_))
+ .Times(Exactly(1))
+ .WillRepeatedly(DoAll(SetArgPointee<0>(123L), Return(Status())));
+ return APerformanceHint_getManager();
+ }
+
+ StrictMock<MockIHintManager>* mMockIHintManager = nullptr;
+};
+
+TEST_F(PerformanceHintTest, TestGetPreferredUpdateRateNanos) {
+ APerformanceHintManager* manager = createManager();
+ int64_t preferredUpdateRateNanos = APerformanceHint_getPreferredUpdateRateNanos(manager);
+ EXPECT_EQ(123L, preferredUpdateRateNanos);
+}
+
+TEST_F(PerformanceHintTest, TestSession) {
+ APerformanceHintManager* manager = createManager();
+
+ std::vector<int32_t> tids;
+ tids.push_back(1);
+ tids.push_back(2);
+ int64_t targetDuration = 56789L;
+
+ StrictMock<MockIHintSession>* iSession = new StrictMock<MockIHintSession>();
+ sp<IHintSession> session_sp(iSession);
+
+ EXPECT_CALL(*mMockIHintManager, createHintSession(_, Eq(tids), Eq(targetDuration), _))
+ .Times(Exactly(1))
+ .WillRepeatedly(DoAll(SetArgPointee<3>(std::move(session_sp)), Return(Status())));
+
+ APerformanceHintSession* session =
+ APerformanceHint_createSession(manager, tids.data(), tids.size(), targetDuration);
+ ASSERT_TRUE(session);
+
+ int64_t targetDurationNanos = 10;
+ EXPECT_CALL(*iSession, updateTargetWorkDuration(Eq(targetDurationNanos))).Times(Exactly(1));
+ int result = APerformanceHint_updateTargetWorkDuration(session, targetDurationNanos);
+ EXPECT_EQ(0, result);
+
+ usleep(2); // Sleep for longer than preferredUpdateRateNanos.
+ int64_t actualDurationNanos = 20;
+ std::vector<int64_t> actualDurations;
+ actualDurations.push_back(20);
+ EXPECT_CALL(*iSession, reportActualWorkDuration(Eq(actualDurations), _)).Times(Exactly(1));
+ result = APerformanceHint_reportActualWorkDuration(session, actualDurationNanos);
+ EXPECT_EQ(0, result);
+
+ result = APerformanceHint_updateTargetWorkDuration(session, -1L);
+ EXPECT_EQ(EINVAL, result);
+ result = APerformanceHint_reportActualWorkDuration(session, -1L);
+ EXPECT_EQ(EINVAL, result);
+
+ EXPECT_CALL(*iSession, close()).Times(Exactly(1));
+ APerformanceHint_closeSession(session);
+}
diff --git a/packages/PackageInstaller/AndroidManifest.xml b/packages/PackageInstaller/AndroidManifest.xml
index 48cdf16..197b7b2 100644
--- a/packages/PackageInstaller/AndroidManifest.xml
+++ b/packages/PackageInstaller/AndroidManifest.xml
@@ -31,7 +31,7 @@
android:directBootAware="true">
<receiver android:name=".TemporaryFileManager"
- android:exported="true">
+ android:exported="false">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
@@ -76,7 +76,7 @@
<receiver android:name=".InstallEventReceiver"
android:permission="android.permission.INSTALL_PACKAGES"
- android:exported="true">
+ android:exported="false">
<intent-filter android:priority="1">
<action android:name="com.android.packageinstaller.ACTION_INSTALL_COMMIT" />
</intent-filter>
@@ -106,14 +106,14 @@
<receiver android:name=".UninstallEventReceiver"
android:permission="android.permission.INSTALL_PACKAGES"
- android:exported="true">
+ android:exported="false">
<intent-filter android:priority="1">
<action android:name="com.android.packageinstaller.ACTION_UNINSTALL_COMMIT" />
</intent-filter>
</receiver>
<receiver android:name=".PackageInstalledReceiver"
- android:exported="true">
+ android:exported="false">
<intent-filter android:priority="1">
<action android:name="android.intent.action.PACKAGE_ADDED" />
<data android:scheme="package" />
diff --git a/packages/PackageInstaller/TEST_MAPPING b/packages/PackageInstaller/TEST_MAPPING
index 5d7b9bb..cef9014 100644
--- a/packages/PackageInstaller/TEST_MAPPING
+++ b/packages/PackageInstaller/TEST_MAPPING
@@ -19,6 +19,9 @@
},
{
"name": "CtsPackageUninstallTestCases"
+ },
+ {
+ "name": "PackageInstallerTests"
}
]
-}
\ No newline at end of file
+}
diff --git a/packages/SettingsLib/ActionBarShadow/Android.bp b/packages/SettingsLib/ActionBarShadow/Android.bp
index 800ab67..4a07d49 100644
--- a/packages/SettingsLib/ActionBarShadow/Android.bp
+++ b/packages/SettingsLib/ActionBarShadow/Android.bp
@@ -19,5 +19,5 @@
],
sdk_version: "system_current",
- min_sdk_version: "21",
+ min_sdk_version: "28",
}
diff --git a/packages/SettingsLib/ActionBarShadow/lint-baseline.xml b/packages/SettingsLib/ActionBarShadow/lint-baseline.xml
deleted file mode 100644
index 4d5de5f..0000000
--- a/packages/SettingsLib/ActionBarShadow/lint-baseline.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0">
-
- <issue
- id="NewApi"
- message="Call requires API level 23 (current min is 21): `android.view.View#setOnScrollChangeListener`"
- errorLine1=" mScrollView.setOnScrollChangeListener(mScrollChangeWatcher);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SettingsLib/ActionBarShadow/src/com/android/settingslib/widget/ActionBarShadowController.java"
- line="81"
- column="25"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 23 (current min is 21): `android.view.View#setOnScrollChangeListener`"
- errorLine1=" mScrollView.setOnScrollChangeListener(null);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SettingsLib/ActionBarShadow/src/com/android/settingslib/widget/ActionBarShadowController.java"
- line="88"
- column="21"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Class requires API level 23 (current min is 21): `android.view.View.OnScrollChangeListener`"
- errorLine1=" final class ScrollChangeWatcher implements View.OnScrollChangeListener {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SettingsLib/ActionBarShadow/src/com/android/settingslib/widget/ActionBarShadowController.java"
- line="95"
- column="48"/>
- </issue>
-
-</issues>
diff --git a/packages/SettingsLib/ActionButtonsPreference/lint-baseline.xml b/packages/SettingsLib/ActionButtonsPreference/lint-baseline.xml
deleted file mode 100644
index 95b7e3b..0000000
--- a/packages/SettingsLib/ActionButtonsPreference/lint-baseline.xml
+++ /dev/null
@@ -1,81 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0">
-
- <issue
- id="NewApi"
- message="`android:Widget.DeviceDefault.Button.Borderless.Colored` requires API level 28 (current min is 21)"
- errorLine1=" <style name="SettingsActionButton" parent="android:Widget.DeviceDefault.Button.Borderless.Colored">"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SettingsLib/ActionButtonsPreference/res/values/styles.xml"
- line="19"
- column="40"/>
- </issue>
-
- <issue
- id="NewApi"
- message="`android:drawableTint` requires API level 23 (current min is 21)"
- errorLine1=" <item name="android:drawableTint">@*android:color/btn_colored_borderless_text_material</item>"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SettingsLib/ActionButtonsPreference/res/values/styles.xml"
- line="21"
- column="15"/>
- </issue>
-
- <issue
- id="NewApi"
- message="`?android:attr/dialogCornerRadius` requires API level 28 (current min is 21)"
- errorLine1=" android:topLeftRadius="?android:attr/dialogCornerRadius""
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SettingsLib/ActionButtonsPreference/res/drawable/half_rounded_left_bk.xml"
- line="23"
- column="9"/>
- </issue>
-
- <issue
- id="NewApi"
- message="`?android:attr/dialogCornerRadius` requires API level 28 (current min is 21)"
- errorLine1=" android:bottomLeftRadius="?android:attr/dialogCornerRadius""
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SettingsLib/ActionButtonsPreference/res/drawable/half_rounded_left_bk.xml"
- line="25"
- column="9"/>
- </issue>
-
- <issue
- id="NewApi"
- message="`?android:attr/dialogCornerRadius` requires API level 28 (current min is 21)"
- errorLine1=" android:topRightRadius="?android:attr/dialogCornerRadius""
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SettingsLib/ActionButtonsPreference/res/drawable/half_rounded_right_bk.xml"
- line="24"
- column="9"/>
- </issue>
-
- <issue
- id="NewApi"
- message="`?android:attr/dialogCornerRadius` requires API level 28 (current min is 21)"
- errorLine1=" android:bottomRightRadius="?android:attr/dialogCornerRadius""
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SettingsLib/ActionButtonsPreference/res/drawable/half_rounded_right_bk.xml"
- line="26"
- column="9"/>
- </issue>
-
- <issue
- id="NewApi"
- message="`?android:attr/dialogCornerRadius` requires API level 28 (current min is 21)"
- errorLine1=" android:bottomRightRadius="?android:attr/dialogCornerRadius""
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SettingsLib/ActionButtonsPreference/res/drawable/rounded_bk.xml"
- line="23"
- column="9"/>
- </issue>
-
-</issues>
diff --git a/packages/SettingsLib/ActionButtonsPreference/res/drawable/half_rounded_left_bk.xml b/packages/SettingsLib/ActionButtonsPreference/res/drawable/half_rounded_left_bk.xml
index 16a85d6..8a25726 100644
--- a/packages/SettingsLib/ActionButtonsPreference/res/drawable/half_rounded_left_bk.xml
+++ b/packages/SettingsLib/ActionButtonsPreference/res/drawable/half_rounded_left_bk.xml
@@ -17,6 +17,8 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ tools:targetApi="28"
android:shape="rectangle">
<solid android:color="?androidprv:attr/colorSurface" />
<corners
diff --git a/packages/SettingsLib/ActionButtonsPreference/res/drawable/half_rounded_right_bk.xml b/packages/SettingsLib/ActionButtonsPreference/res/drawable/half_rounded_right_bk.xml
index 1b9f68f..7e626e5 100644
--- a/packages/SettingsLib/ActionButtonsPreference/res/drawable/half_rounded_right_bk.xml
+++ b/packages/SettingsLib/ActionButtonsPreference/res/drawable/half_rounded_right_bk.xml
@@ -1,22 +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.
+ 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.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ tools:targetApi="28"
android:shape="rectangle">
<solid android:color="?androidprv:attr/colorSurface" />
<corners
diff --git a/packages/SettingsLib/ActionButtonsPreference/res/drawable/rounded_bk.xml b/packages/SettingsLib/ActionButtonsPreference/res/drawable/rounded_bk.xml
index a884ef1..9f4980b 100644
--- a/packages/SettingsLib/ActionButtonsPreference/res/drawable/rounded_bk.xml
+++ b/packages/SettingsLib/ActionButtonsPreference/res/drawable/rounded_bk.xml
@@ -1,22 +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.
+ 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.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ tools:targetApi="28"
android:shape="rectangle">
<solid android:color="?androidprv:attr/colorSurface" />
<corners
diff --git a/packages/SettingsLib/ActionButtonsPreference/res/values/styles.xml b/packages/SettingsLib/ActionButtonsPreference/res/values/styles.xml
index 42c7d76..8a449cf 100644
--- a/packages/SettingsLib/ActionButtonsPreference/res/values/styles.xml
+++ b/packages/SettingsLib/ActionButtonsPreference/res/values/styles.xml
@@ -15,7 +15,9 @@
limitations under the License.
-->
-<resources>
+<resources
+ xmlns:tools="http://schemas.android.com/tools"
+ tools:targetApi="28">
<style name="SettingsLibActionButton" parent="android:Widget.DeviceDefault.Button.Borderless.Colored">
<item name="android:drawablePadding">4dp</item>
<item name="android:drawableTint">@*android:color/btn_colored_borderless_text_material</item>
diff --git a/packages/SettingsLib/BarChartPreference/Android.bp b/packages/SettingsLib/BarChartPreference/Android.bp
index ae26066..4f65373 100644
--- a/packages/SettingsLib/BarChartPreference/Android.bp
+++ b/packages/SettingsLib/BarChartPreference/Android.bp
@@ -14,7 +14,7 @@
resource_dirs: ["res"],
static_libs: [
- "androidx.preference_preference",
+ "androidx.preference_preference",
],
sdk_version: "system_current",
diff --git a/packages/SettingsLib/BarChartPreference/lint-baseline.xml b/packages/SettingsLib/BarChartPreference/lint-baseline.xml
deleted file mode 100644
index f1043bb..0000000
--- a/packages/SettingsLib/BarChartPreference/lint-baseline.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0">
-
- <issue
- id="NewApi"
- message="`@android:style/Widget.DeviceDefault.Button.Borderless.Colored` requires API level 28 (current min is 21)"
- errorLine1=" parent="@android:style/Widget.DeviceDefault.Button.Borderless.Colored">"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SettingsLib/BarChartPreference/res/values/styles.xml"
- line="35"
- column="12"/>
- </issue>
-
-</issues>
diff --git a/packages/SettingsLib/BarChartPreference/res/values/styles.xml b/packages/SettingsLib/BarChartPreference/res/values/styles.xml
index 7a3fb7d..92514ad 100644
--- a/packages/SettingsLib/BarChartPreference/res/values/styles.xml
+++ b/packages/SettingsLib/BarChartPreference/res/values/styles.xml
@@ -15,7 +15,9 @@
limitations under the License.
-->
-<resources>
+<resources
+ xmlns:tools="http://schemas.android.com/tools"
+ tools:targetApi="28">
<style name="SettingsBarChart">
<item name="android:layout_marginStart">10dp</item>
diff --git a/packages/SettingsLib/HelpUtils/lint-baseline.xml b/packages/SettingsLib/HelpUtils/lint-baseline.xml
deleted file mode 100644
index 940f027..0000000
--- a/packages/SettingsLib/HelpUtils/lint-baseline.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0">
-
- <issue
- id="NewApi"
- message="Call requires API level 28 (current min is 21): `android.content.pm.PackageInfo#getLongVersionCode`"
- errorLine1=" sCachedVersionCode = Long.toString(info.getLongVersionCode());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SettingsLib/HelpUtils/src/com/android/settingslib/HelpUtils.java"
- line="239"
- column="57"/>
- </issue>
-
-</issues>
diff --git a/packages/SettingsLib/HelpUtils/src/com/android/settingslib/HelpUtils.java b/packages/SettingsLib/HelpUtils/src/com/android/settingslib/HelpUtils.java
index 281269e..70c8658 100644
--- a/packages/SettingsLib/HelpUtils/src/com/android/settingslib/HelpUtils.java
+++ b/packages/SettingsLib/HelpUtils/src/com/android/settingslib/HelpUtils.java
@@ -25,6 +25,7 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.net.Uri;
+import android.os.Build;
import android.provider.Settings.Global;
import android.text.TextUtils;
import android.util.Log;
@@ -32,6 +33,7 @@
import android.view.MenuItem;
import android.view.MenuItem.OnMenuItemClickListener;
+import androidx.annotation.RequiresApi;
import androidx.annotation.VisibleForTesting;
import com.android.settingslib.widget.R;
@@ -73,6 +75,15 @@
private HelpUtils() {
}
+ /**
+ * Prepares the help menu item by doing the following.
+ * - If the helpUrlString is empty or null, the help menu item is made invisible.
+ * - Otherwise, this makes the help menu item visible and sets the intent for the help menu
+ * item to view the URL.
+ *
+ * @return returns whether the help menu item has been made visible.
+ */
+ @RequiresApi(Build.VERSION_CODES.P)
public static boolean prepareHelpMenuItem(Activity activity, Menu menu, String helpUri,
String backupContext) {
// menu contains help item, skip it
@@ -84,6 +95,15 @@
return prepareHelpMenuItem(activity, helpItem, helpUri, backupContext);
}
+ /**
+ * Prepares the help menu item by doing the following.
+ * - If the helpUrlString is empty or null, the help menu item is made invisible.
+ * - Otherwise, this makes the help menu item visible and sets the intent for the help menu
+ * item to view the URL.
+ *
+ * @return returns whether the help menu item has been made visible.
+ */
+ @RequiresApi(Build.VERSION_CODES.P)
public static boolean prepareHelpMenuItem(Activity activity, Menu menu, int helpUriResource,
String backupContext) {
// menu contains help item, skip it
@@ -105,6 +125,7 @@
* @return returns whether the help menu item has been made visible.
*/
@VisibleForTesting
+ @RequiresApi(Build.VERSION_CODES.P)
static boolean prepareHelpMenuItem(final Activity activity, MenuItem helpMenuItem,
String helpUriString, String backupContext) {
if (Global.getInt(activity.getContentResolver(), Global.DEVICE_PROVISIONED, 0) == 0) {
@@ -152,6 +173,10 @@
}
}
+ /**
+ * Get the help intent from helpUriString.
+ */
+ @RequiresApi(Build.VERSION_CODES.P)
public static Intent getHelpIntent(Context context, String helpUriString,
String backupContext) {
if (Global.getInt(context.getContentResolver(), Global.DEVICE_PROVISIONED, 0) == 0) {
@@ -223,6 +248,7 @@
*
* @return the uri with added query parameters
*/
+ @RequiresApi(Build.VERSION_CODES.P)
public static Uri uriWithAddedParameters(Context context, Uri baseUri) {
Uri.Builder builder = baseUri.buildUpon();
diff --git a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
index f04b0e3..266fc78 100644
--- a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
+++ b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
@@ -267,26 +267,22 @@
private static void startLottieAnimationWith(LottieAnimationView illustrationView,
Uri imageUri) {
- try {
- final InputStream inputStream =
- getInputStreamFromUri(illustrationView.getContext(), imageUri);
- illustrationView.setAnimation(inputStream, /* cacheKey= */ null);
- illustrationView.setRepeatCount(LottieDrawable.INFINITE);
- illustrationView.playAnimation();
- } catch (IllegalStateException e) {
- Log.w(TAG, "Invalid illustration image uri: " + imageUri, e);
- }
+ final InputStream inputStream =
+ getInputStreamFromUri(illustrationView.getContext(), imageUri);
+ illustrationView.setFailureListener(
+ result -> Log.w(TAG, "Invalid illustration image uri: " + imageUri, result));
+ illustrationView.setAnimation(inputStream, /* cacheKey= */ null);
+ illustrationView.setRepeatCount(LottieDrawable.INFINITE);
+ illustrationView.playAnimation();
}
private static void startLottieAnimationWith(LottieAnimationView illustrationView,
@RawRes int rawRes) {
- try {
- illustrationView.setAnimation(rawRes);
- illustrationView.setRepeatCount(LottieDrawable.INFINITE);
- illustrationView.playAnimation();
- } catch (IllegalStateException e) {
- Log.w(TAG, "Invalid illustration resource id: " + rawRes, e);
- }
+ illustrationView.setFailureListener(
+ result -> Log.w(TAG, "Invalid illustration resource id: " + rawRes, result));
+ illustrationView.setAnimation(rawRes);
+ illustrationView.setRepeatCount(LottieDrawable.INFINITE);
+ illustrationView.playAnimation();
}
private static void resetAnimations(LottieAnimationView illustrationView) {
diff --git a/packages/SettingsLib/ProgressBar/lint-baseline.xml b/packages/SettingsLib/ProgressBar/lint-baseline.xml
deleted file mode 100644
index 03d0f3f..0000000
--- a/packages/SettingsLib/ProgressBar/lint-baseline.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0">
-
- <issue
- id="NewApi"
- message="`?android:attr/colorSecondary` requires API level 25 (current min is 21)"
- errorLine1=" android:background="?android:attr/colorSecondary" />"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SettingsLib/ProgressBar/res/layout/progress_header.xml"
- line="27"
- column="9"/>
- </issue>
-
-</issues>
diff --git a/packages/SettingsLib/ProgressBar/res/layout/progress_header.xml b/packages/SettingsLib/ProgressBar/res/layout/progress_header.xml
index 268858b..52ff42c 100644
--- a/packages/SettingsLib/ProgressBar/res/layout/progress_header.xml
+++ b/packages/SettingsLib/ProgressBar/res/layout/progress_header.xml
@@ -17,6 +17,8 @@
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ tools:targetApi="25"
android:layout_width="match_parent"
android:layout_height="3dp">
<View
diff --git a/packages/SettingsLib/RestrictedLockUtils/lint-baseline.xml b/packages/SettingsLib/RestrictedLockUtils/lint-baseline.xml
deleted file mode 100644
index 173c735..0000000
--- a/packages/SettingsLib/RestrictedLockUtils/lint-baseline.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0">
-
- <issue
- id="NewApi"
- message="Call requires API level 23 (current min is 21): `android.content.Context#getSystemService`"
- errorLine1=" ComponentName adminComponent = userContext.getSystemService("
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java"
- line="59"
- column="52"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 23 (current min is 21): `android.content.Context#getSystemService`"
- errorLine1=" UserManager um = context.getSystemService(UserManager.class);"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java"
- line="101"
- column="34"/>
- </issue>
-
-</issues>
diff --git a/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java b/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java
index a77e34b..80f02b4 100644
--- a/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java
+++ b/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java
@@ -21,11 +21,13 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.os.Build;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
import java.util.Objects;
@@ -34,10 +36,18 @@
* support message dialog.
*/
public class RestrictedLockUtils {
+ /**
+ * Get EnforcedAdmin from DevicePolicyManager
+ */
+ @RequiresApi(Build.VERSION_CODES.M)
public static EnforcedAdmin getProfileOrDeviceOwner(Context context, UserHandle user) {
return getProfileOrDeviceOwner(context, null, user);
}
+ /**
+ * Get EnforcedAdmin from DevicePolicyManager
+ */
+ @RequiresApi(Build.VERSION_CODES.M)
public static EnforcedAdmin getProfileOrDeviceOwner(
Context context, String enforcedRestriction, UserHandle user) {
if (user == null) {
@@ -73,6 +83,7 @@
/**
* Send the intent to trigger the {@code android.settings.ShowAdminSupportDetailsDialog}.
*/
+ @RequiresApi(Build.VERSION_CODES.M)
public static void sendShowAdminSupportDetailsIntent(Context context, EnforcedAdmin admin) {
final Intent intent = getShowAdminSupportDetailsIntent(context, admin);
int targetUserId = UserHandle.myUserId();
@@ -97,6 +108,10 @@
return intent;
}
+ /**
+ * Check if current user is profile or not
+ */
+ @RequiresApi(Build.VERSION_CODES.M)
public static boolean isCurrentUserOrProfile(Context context, int userId) {
UserManager um = context.getSystemService(UserManager.class);
return um.getUserProfiles().contains(UserHandle.of(userId));
diff --git a/packages/SettingsLib/SettingsSpinner/lint-baseline.xml b/packages/SettingsLib/SettingsSpinner/lint-baseline.xml
deleted file mode 100644
index ae1ed38e..0000000
--- a/packages/SettingsLib/SettingsSpinner/lint-baseline.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0">
-
- <issue
- id="NewApi"
- message="Call requires API level 23 (current min is 21): `new android.widget.Spinner`"
- errorLine1=" super(context, attrs, defStyleAttr, defStyleRes, mode, null);"
- errorLine2=" ~~~~~">
- <location
- file="frameworks/base/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/settingsspinner/SettingsSpinner.java"
- line="122"
- column="9"/>
- </issue>
-
-</issues>
diff --git a/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/settingsspinner/SettingsSpinner.java b/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/settingsspinner/SettingsSpinner.java
index 0be80a9f..14286fa 100644
--- a/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/settingsspinner/SettingsSpinner.java
+++ b/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/settingsspinner/SettingsSpinner.java
@@ -17,9 +17,12 @@
package com.android.settingslib.widget.settingsspinner;
import android.content.Context;
+import android.os.Build;
import android.util.AttributeSet;
import android.widget.Spinner;
+import androidx.annotation.RequiresApi;
+
import com.android.settingslib.widget.R;
/**
@@ -117,6 +120,7 @@
* @see Spinner#MODE_DIALOG
* @see Spinner#MODE_DROPDOWN
*/
+ @RequiresApi(Build.VERSION_CODES.M)
public SettingsSpinner(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes,
int mode) {
super(context, attrs, defStyleAttr, defStyleRes, mode, null);
diff --git a/packages/SettingsLib/src/com/android/settingslib/enterprise/ActionDisabledByAdminControllerFactory.java b/packages/SettingsLib/src/com/android/settingslib/enterprise/ActionDisabledByAdminControllerFactory.java
index 7275d6b..bd9e0d3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/enterprise/ActionDisabledByAdminControllerFactory.java
+++ b/packages/SettingsLib/src/com/android/settingslib/enterprise/ActionDisabledByAdminControllerFactory.java
@@ -18,9 +18,6 @@
import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED;
-import static com.android.settingslib.enterprise.ActionDisabledLearnMoreButtonLauncher.DEFAULT_RESOLVE_ACTIVITY_CHECKER;
-import static com.android.settingslib.enterprise.ManagedDeviceActionDisabledByAdminController.DEFAULT_FOREGROUND_USER_CHECKER;
-
import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator;
@@ -46,11 +43,7 @@
} else if (isFinancedDevice(context)) {
return new FinancedDeviceActionDisabledByAdminController(stringProvider);
} else {
- return new ManagedDeviceActionDisabledByAdminController(
- stringProvider,
- userHandle,
- DEFAULT_FOREGROUND_USER_CHECKER,
- DEFAULT_RESOLVE_ACTIVITY_CHECKER);
+ return new ManagedDeviceActionDisabledByAdminController(stringProvider, userHandle);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/enterprise/ActionDisabledLearnMoreButtonLauncher.java b/packages/SettingsLib/src/com/android/settingslib/enterprise/ActionDisabledLearnMoreButtonLauncher.java
index f9d3aaf..4114879 100644
--- a/packages/SettingsLib/src/com/android/settingslib/enterprise/ActionDisabledLearnMoreButtonLauncher.java
+++ b/packages/SettingsLib/src/com/android/settingslib/enterprise/ActionDisabledLearnMoreButtonLauncher.java
@@ -22,7 +22,6 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.UserHandle;
import android.os.UserManager;
@@ -35,17 +34,6 @@
*/
public abstract class ActionDisabledLearnMoreButtonLauncher {
- public static ResolveActivityChecker DEFAULT_RESOLVE_ACTIVITY_CHECKER =
- (packageManager, url, userHandle) -> packageManager.resolveActivityAsUser(
- createLearnMoreIntent(url),
- PackageManager.MATCH_DEFAULT_ONLY,
- userHandle.getIdentifier()) != null;
-
- interface ResolveActivityChecker {
- boolean canResolveActivityAsUser(
- PackageManager packageManager, String url, UserHandle userHandle);
- }
-
/**
* Sets up a "learn more" button which shows a screen with device policy settings
*/
@@ -123,14 +111,6 @@
finishSelf();
}
- protected final boolean canLaunchHelpPage(
- PackageManager packageManager,
- String url,
- UserHandle userHandle,
- ResolveActivityChecker resolveActivityChecker) {
- return resolveActivityChecker.canResolveActivityAsUser(packageManager, url, userHandle);
- }
-
private void showAdminPolicies(Context context, EnforcedAdmin enforcedAdmin) {
if (enforcedAdmin.component != null) {
launchShowAdminPolicies(context, enforcedAdmin.user, enforcedAdmin.component);
diff --git a/packages/SettingsLib/src/com/android/settingslib/enterprise/ManagedDeviceActionDisabledByAdminController.java b/packages/SettingsLib/src/com/android/settingslib/enterprise/ManagedDeviceActionDisabledByAdminController.java
index c2034f8..93e811d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/enterprise/ManagedDeviceActionDisabledByAdminController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/enterprise/ManagedDeviceActionDisabledByAdminController.java
@@ -20,14 +20,13 @@
import android.app.admin.DevicePolicyManager;
import android.content.Context;
-import android.content.pm.PackageManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.text.TextUtils;
import androidx.annotation.Nullable;
-import com.android.settingslib.enterprise.ActionDisabledLearnMoreButtonLauncher.ResolveActivityChecker;
+import java.util.Objects;
/**
@@ -36,37 +35,17 @@
final class ManagedDeviceActionDisabledByAdminController
extends BaseActionDisabledByAdminController {
- interface ForegroundUserChecker {
- boolean isUserForeground(Context context, UserHandle userHandle);
- }
-
- public final static ForegroundUserChecker DEFAULT_FOREGROUND_USER_CHECKER =
- ManagedDeviceActionDisabledByAdminController::isUserForeground;
-
- /**
- * The {@link UserHandle} which is preferred for launching the web help page in
- * <p>If not able to launch the web help page in this user, the current user will be used as
- * fallback instead. If the current user cannot open it either, the admin policies page will
- * be used instead.
- */
- private final UserHandle mPreferredUserHandle;
-
- private final ForegroundUserChecker mForegroundUserChecker;
- private final ResolveActivityChecker mResolveActivityChecker;
+ private final UserHandle mUserHandle;
/**
* Constructs a {@link ManagedDeviceActionDisabledByAdminController}
- * @param preferredUserHandle - user on which to launch the help web page, if necessary
+ * @param userHandle - user on which to launch the help web page, if necessary
*/
ManagedDeviceActionDisabledByAdminController(
DeviceAdminStringProvider stringProvider,
- UserHandle preferredUserHandle,
- ForegroundUserChecker foregroundUserChecker,
- ResolveActivityChecker resolveActivityChecker) {
+ UserHandle userHandle) {
super(stringProvider);
- mPreferredUserHandle = requireNonNull(preferredUserHandle);
- mForegroundUserChecker = requireNonNull(foregroundUserChecker);
- mResolveActivityChecker = requireNonNull(resolveActivityChecker);
+ mUserHandle = requireNonNull(userHandle);
}
@Override
@@ -74,52 +53,14 @@
assertInitialized();
String url = mStringProvider.getLearnMoreHelpPageUrl();
-
- if (!TextUtils.isEmpty(url)
- && canLaunchHelpPageInPreferredOrCurrentUser(context, url, mPreferredUserHandle)) {
- setupLearnMoreButtonToLaunchHelpPage(context, url, mPreferredUserHandle);
- } else {
+ if (TextUtils.isEmpty(url)) {
mLauncher.setupLearnMoreButtonToShowAdminPolicies(context, mEnforcementAdminUserId,
mEnforcedAdmin);
+ } else {
+ mLauncher.setupLearnMoreButtonToLaunchHelpPage(context, url, mUserHandle);
}
}
- private boolean canLaunchHelpPageInPreferredOrCurrentUser(
- Context context, String url, UserHandle preferredUserHandle) {
- PackageManager packageManager = context.getPackageManager();
- if (mLauncher.canLaunchHelpPage(
- packageManager, url, preferredUserHandle, mResolveActivityChecker)
- && mForegroundUserChecker.isUserForeground(context, preferredUserHandle)) {
- return true;
- }
- return mLauncher.canLaunchHelpPage(
- packageManager, url, context.getUser(), mResolveActivityChecker);
- }
-
- /**
- * Sets up the "Learn more" button to launch the web help page in the {@code
- * preferredUserHandle} user. If not possible to launch it there, it sets up the button to
- * launch it in the current user instead.
- */
- private void setupLearnMoreButtonToLaunchHelpPage(
- Context context, String url, UserHandle preferredUserHandle) {
- PackageManager packageManager = context.getPackageManager();
- if (mLauncher.canLaunchHelpPage(
- packageManager, url, preferredUserHandle, mResolveActivityChecker)
- && mForegroundUserChecker.isUserForeground(context, preferredUserHandle)) {
- mLauncher.setupLearnMoreButtonToLaunchHelpPage(context, url, preferredUserHandle);
- }
- if (mLauncher.canLaunchHelpPage(
- packageManager, url, context.getUser(), mResolveActivityChecker)) {
- mLauncher.setupLearnMoreButtonToLaunchHelpPage(context, url, context.getUser());
- }
- }
-
- private static boolean isUserForeground(Context context, UserHandle userHandle) {
- return context.createContextAsUser(userHandle, /* flags= */ 0)
- .getSystemService(UserManager.class).isUserForeground();
- }
-
@Override
public String getAdminSupportTitle(@Nullable String restriction) {
if (restriction == null) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/HandlerInjector.java b/packages/SettingsLib/src/com/android/settingslib/utils/HandlerInjector.java
new file mode 100644
index 0000000..7c7044c
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/utils/HandlerInjector.java
@@ -0,0 +1,41 @@
+/*
+ * 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.settingslib.utils;
+
+import android.os.Handler;
+
+/**
+ * Wrapper the {@link android.os.Handler} for testing compatibility.
+ */
+public class HandlerInjector {
+
+ protected final Handler mHandler;
+
+ public HandlerInjector(Handler handler) {
+ mHandler = handler;
+ }
+
+ /** Wrapper the {@link android.os.Handler#postDelayed} for testing compatibility. */
+ public void postDelayed(Runnable runnable, long delayMillis) {
+ mHandler.postDelayed(runnable, delayMillis);
+ }
+
+ /** Wrapper the {@link android.os.Handler#removeCallbacks} for testing compatibility. */
+ public void removeCallbacks(Runnable runnable) {
+ mHandler.removeCallbacks(runnable);
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java
index d95f936..56454e9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java
@@ -21,6 +21,7 @@
import android.content.Context;
import android.content.Intent;
+import android.graphics.drawable.Drawable;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.NetworkSelectionStatus;
@@ -294,6 +295,28 @@
return noInternet ? NO_INTERNET_WIFI_PIE[level] : WIFI_PIE[level];
}
+ /**
+ * Wrapper the {@link #getInternetIconResource} for testing compatibility.
+ */
+ public static class InternetIconInjector {
+
+ protected final Context mContext;
+
+ public InternetIconInjector(Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Returns the Internet icon for a given RSSI level.
+ *
+ * @param noInternet True if a connected Wi-Fi network cannot access the Internet
+ * @param level The number of bars to show (0-4)
+ */
+ public Drawable getIcon(boolean noInternet, int level) {
+ return mContext.getDrawable(WifiUtils.getInternetIconResource(level, noInternet));
+ }
+ }
+
public static boolean isMeteredOverridden(WifiConfiguration config) {
return config.meteredOverride != WifiConfiguration.METERED_OVERRIDE_NONE;
}
diff --git a/packages/SettingsLib/tests/robotests/OWNERS b/packages/SettingsLib/tests/robotests/OWNERS
new file mode 100644
index 0000000..8a7a27e
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/OWNERS
@@ -0,0 +1,2 @@
+# We do not guard tests - everyone is welcomed to contribute to tests.
+per-file *.java=*
\ No newline at end of file
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/enterprise/ManagedDeviceActionDisabledByAdminControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/enterprise/ManagedDeviceActionDisabledByAdminControllerTest.java
index 509e12d..d9be4f3 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/enterprise/ManagedDeviceActionDisabledByAdminControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/enterprise/ManagedDeviceActionDisabledByAdminControllerTest.java
@@ -30,8 +30,6 @@
import android.app.Activity;
import android.content.Context;
-import android.content.pm.ResolveInfo;
-import android.os.UserHandle;
import android.os.UserManager;
import androidx.test.core.app.ApplicationProvider;
@@ -47,11 +45,9 @@
@RunWith(RobolectricTestRunner.class)
public class ManagedDeviceActionDisabledByAdminControllerTest {
- private static UserHandle MANAGED_USER = UserHandle.of(123);
private static final String RESTRICTION = UserManager.DISALLOW_ADJUST_VOLUME;
private static final String EMPTY_URL = "";
private static final String SUPPORT_TITLE_FOR_RESTRICTION = DISALLOW_ADJUST_VOLUME_TITLE;
- public static final ResolveInfo TEST_RESULT_INFO = new ResolveInfo();
private final Context mContext = ApplicationProvider.getApplicationContext();
private final Activity mActivity = ActivityController.of(new Activity()).get();
@@ -64,6 +60,15 @@
}
@Test
+ public void setupLearnMoreButton_validUrl_negativeButtonSet() {
+ ManagedDeviceActionDisabledByAdminController controller = createController(URL);
+
+ controller.setupLearnMoreButton(mContext);
+
+ mTestUtils.assertLearnMoreAction(LEARN_MORE_ACTION_LAUNCH_HELP_PAGE);
+ }
+
+ @Test
public void setupLearnMoreButton_noUrl_negativeButtonSet() {
ManagedDeviceActionDisabledByAdminController controller = createController(EMPTY_URL);
@@ -73,58 +78,6 @@
}
@Test
- public void setupLearnMoreButton_validUrl_foregroundUser_launchesHelpPage() {
- ManagedDeviceActionDisabledByAdminController controller = createController(
- URL,
- /* isUserForeground= */ true,
- /* preferredUserHandle= */ MANAGED_USER,
- /* userContainingBrowser= */ MANAGED_USER);
-
- controller.setupLearnMoreButton(mContext);
-
- mTestUtils.assertLearnMoreAction(LEARN_MORE_ACTION_LAUNCH_HELP_PAGE);
- }
-
- @Test
- public void setupLearnMoreButton_validUrl_browserInPreferredUser_notForeground_showsAdminPolicies() {
- ManagedDeviceActionDisabledByAdminController controller = createController(
- URL,
- /* isUserForeground= */ false,
- /* preferredUserHandle= */ MANAGED_USER,
- /* userContainingBrowser= */ MANAGED_USER);
-
- controller.setupLearnMoreButton(mContext);
-
- mTestUtils.assertLearnMoreAction(LEARN_MORE_ACTION_SHOW_ADMIN_POLICIES);
- }
-
- @Test
- public void setupLearnMoreButton_validUrl_browserInCurrentUser_launchesHelpPage() {
- ManagedDeviceActionDisabledByAdminController controller = createController(
- URL,
- /* isUserForeground= */ false,
- /* preferredUserHandle= */ MANAGED_USER,
- /* userContainingBrowser= */ mContext.getUser());
-
- controller.setupLearnMoreButton(mContext);
-
- mTestUtils.assertLearnMoreAction(LEARN_MORE_ACTION_LAUNCH_HELP_PAGE);
- }
-
- @Test
- public void setupLearnMoreButton_validUrl_browserNotOnAnyUser_showsAdminPolicies() {
- ManagedDeviceActionDisabledByAdminController controller = createController(
- URL,
- /* isUserForeground= */ false,
- /* preferredUserHandle= */ MANAGED_USER,
- /* userContainingBrowser= */ null);
-
- controller.setupLearnMoreButton(mContext);
-
- mTestUtils.assertLearnMoreAction(LEARN_MORE_ACTION_SHOW_ADMIN_POLICIES);
- }
-
- @Test
public void getAdminSupportTitleResource_noRestriction_works() {
ManagedDeviceActionDisabledByAdminController controller = createController();
@@ -157,33 +110,13 @@
}
private ManagedDeviceActionDisabledByAdminController createController() {
- return createController(
- /* url= */ null,
- /* foregroundUserChecker= */ true,
- mContext.getUser(),
- /* userContainingBrowser= */ null);
+ return createController(/* url= */ null);
}
private ManagedDeviceActionDisabledByAdminController createController(String url) {
- return createController(
- url,
- /* foregroundUserChecker= */ true,
- mContext.getUser(),
- /* userContainingBrowser= */ null);
- }
-
- private ManagedDeviceActionDisabledByAdminController createController(
- String url,
- boolean isUserForeground,
- UserHandle preferredUserHandle,
- UserHandle userContainingBrowser) {
ManagedDeviceActionDisabledByAdminController controller =
new ManagedDeviceActionDisabledByAdminController(
- new FakeDeviceAdminStringProvider(url),
- preferredUserHandle,
- /* foregroundUserChecker= */ (context, userHandle) -> isUserForeground,
- /* resolveActivityChecker= */ (packageManager, __, userHandle) ->
- userHandle.equals(userContainingBrowser));
+ new FakeDeviceAdminStringProvider(url), mContext.getUser());
controller.initialize(mTestUtils.createLearnMoreButtonLauncher());
controller.updateEnforcedAdmin(ENFORCED_ADMIN, ENFORCEMENT_ADMIN_USER_ID);
return controller;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/HandlerInjectorTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/HandlerInjectorTest.java
new file mode 100644
index 0000000..4b34377
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/HandlerInjectorTest.java
@@ -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.
+ */
+
+package com.android.settingslib.utils;
+
+import static org.mockito.Mockito.verify;
+
+import android.os.Handler;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class HandlerInjectorTest {
+
+ public static final long TEST_DELAY_MILLIS = 0L;
+
+ @Rule
+ public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+ @Mock
+ public Handler mHandler;
+ @Mock
+ public Runnable mRunnable;
+
+ private HandlerInjector mHandlerInjector;
+
+ @Before
+ public void setUp() {
+ mHandlerInjector = new HandlerInjector(mHandler);
+ }
+
+ @Test
+ public void postDelayed_doByMainThreadHandler() {
+ mHandlerInjector.postDelayed(mRunnable, TEST_DELAY_MILLIS);
+
+ verify(mHandler).postDelayed(mRunnable, TEST_DELAY_MILLIS);
+ }
+
+ @Test
+ public void removeCallbacks_doByMainThreadHandler() {
+ mHandlerInjector.removeCallbacks(mRunnable);
+
+ verify(mHandler).removeCallbacks(mRunnable);
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/IllustrationPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/IllustrationPreferenceTest.java
index ea9be04..9e3312a 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/IllustrationPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/IllustrationPreferenceTest.java
@@ -18,6 +18,8 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
@@ -130,4 +132,27 @@
verify(drawable).start();
}
+
+ @Test
+ public void playLottieAnimationWithUri_verifyFailureListener() {
+ doReturn(null).when(mAnimationView).getDrawable();
+
+ mPreference.setImageUri(mImageUri);
+ mPreference.onBindViewHolder(mViewHolder);
+
+ verify(mAnimationView).setFailureListener(any());
+ }
+
+ @Test
+ public void playLottieAnimationWithResource_verifyFailureListener() {
+ // fake the valid lottie image
+ final int fakeValidResId = 111;
+ doNothing().when(mAnimationView).setImageResource(fakeValidResId);
+ doReturn(null).when(mAnimationView).getDrawable();
+
+ mPreference.setLottieAnimationResId(fakeValidResId);
+ mPreference.onBindViewHolder(mViewHolder);
+
+ verify(mAnimationView).setFailureListener(any());
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java
index 4530148..7c2b904 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java
@@ -20,6 +20,8 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
@@ -37,6 +39,8 @@
import android.text.format.DateUtils;
import android.util.ArraySet;
+import androidx.test.core.app.ApplicationProvider;
+
import com.android.settingslib.R;
import org.junit.Before;
@@ -45,7 +49,6 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
import java.util.ArrayList;
import java.util.Set;
@@ -70,7 +73,7 @@
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mContext = RuntimeEnvironment.application;
+ mContext = spy(ApplicationProvider.getApplicationContext());
}
@Test
@@ -160,6 +163,21 @@
assertThat(bundle.getString(WifiUtils.KEY_CHOSEN_WIFIENTRY_KEY)).isEqualTo(key);
}
+ @Test
+ public void testInternetIconInjector_getIcon_returnsCorrectValues() {
+ WifiUtils.InternetIconInjector iconInjector = new WifiUtils.InternetIconInjector(mContext);
+
+ for (int level = 0; level <= 4; level++) {
+ iconInjector.getIcon(false /* noInternet */, level);
+ verify(mContext).getDrawable(
+ WifiUtils.getInternetIconResource(level, false /* noInternet */));
+
+ iconInjector.getIcon(true /* noInternet */, level);
+ verify(mContext).getDrawable(
+ WifiUtils.getInternetIconResource(level, true /* noInternet */));
+ }
+ }
+
private static ArrayList<ScanResult> buildScanResultCache() {
ArrayList<ScanResult> scanResults = new ArrayList<>();
for (int i = 0; i < 5; i++) {
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
index 690ace7..a9245f8 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
@@ -291,6 +291,7 @@
VALIDATORS.put(Global.Wearable.HFP_CLIENT_PROFILE_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Global.Wearable.COMPANION_OS_VERSION, ANY_INTEGER_VALIDATOR);
VALIDATORS.put(Global.Wearable.ENABLE_ALL_LANGUAGES, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Global.Wearable.OEM_SETUP_VERSION, ANY_INTEGER_VALIDATOR);
}
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 6d7fb02..7a9f81e0 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -276,7 +276,7 @@
VALIDATORS.put(Secure.ACCESSIBILITY_BUTTON_MODE,
new InclusiveIntegerRangeValidator(
Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR,
- Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU));
+ Secure.ACCESSIBILITY_BUTTON_MODE_GESTURE));
VALIDATORS.put(Secure.ACCESSIBILITY_FLOATING_MENU_SIZE,
new DiscreteValueValidator(new String[] {"0", "1"}));
VALIDATORS.put(Secure.ACCESSIBILITY_FLOATING_MENU_ICON_TYPE,
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 9e65799..6a4b5e9 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -102,7 +102,8 @@
Settings.System.PEAK_REFRESH_RATE, // depends on hardware capabilities
Settings.System.SCREEN_BRIGHTNESS_FLOAT,
Settings.System.SCREEN_BRIGHTNESS_FOR_VR_FLOAT,
- Settings.System.MULTI_AUDIO_FOCUS_ENABLED // form-factor/OEM specific
+ Settings.System.MULTI_AUDIO_FOCUS_ENABLED, // form-factor/OEM specific
+ Settings.System.WEAR_ACCESSIBILITY_GESTURE_ENABLED
);
private static final Set<String> BACKUP_DENY_LIST_GLOBAL_SETTINGS =
@@ -654,7 +655,8 @@
Settings.Global.Wearable.HFP_CLIENT_PROFILE_ENABLED,
Settings.Global.Wearable.COMPANION_OS_VERSION,
Settings.Global.Wearable.ENABLE_ALL_LANGUAGES,
- Settings.Global.Wearable.SETUP_LOCALE);
+ Settings.Global.Wearable.SETUP_LOCALE,
+ Settings.Global.Wearable.OEM_SETUP_VERSION);
private static final Set<String> BACKUP_DENY_LIST_SECURE_SETTINGS =
newHashSet(
diff --git a/packages/Shell/res/values-mr/strings.xml b/packages/Shell/res/values-mr/strings.xml
index 3842733..8297488 100644
--- a/packages/Shell/res/values-mr/strings.xml
+++ b/packages/Shell/res/values-mr/strings.xml
@@ -31,7 +31,7 @@
<string name="bugreport_confirm" msgid="5917407234515812495">"बग रीपोर्टांमध्ये तुम्ही संवेदनशील (अॅप-वापर आणि स्थान डेटा यासारखा) डेटा म्हणून विचार करता त्या डेटाच्या समावेशासह सिस्टीमच्या विविध लॉग फायलींमधील डेटा असतो. ज्या लोकांवर आणि अॅपवर तुमचा विश्वास आहे केवळ त्यांच्यासह हा बग रीपोर्ट शेअर करा."</string>
<string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"पुन्हा दर्शवू नका"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"बग रीपोर्ट"</string>
- <string name="bugreport_unreadable_text" msgid="586517851044535486">"बग रिपोर्ट फाइल वाचणे शक्य झाले नाही"</string>
+ <string name="bugreport_unreadable_text" msgid="586517851044535486">"बग अहवाल फाइल वाचणे शक्य झाले नाही"</string>
<string name="bugreport_add_details_to_zip_failed" msgid="1302931926486712371">"झिप फाइल मध्ये बग रिपोर्ट तपशील जोडणे शक्य झाले नाही"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"अनामित"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"तपशील"</string>
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 9de1c5e..adf441b 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -656,6 +656,10 @@
</service>
<service
+ android:name=".communal.service.CommunalService"
+ android:exported="@bool/config_communalServiceEnabled"/>
+
+ <service
android:name=".keyguard.KeyguardService"
android:exported="true" />
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
index 02cb2bc..a22a56f 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
@@ -20,171 +20,166 @@
<com.android.keyguard.KeyguardPINView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/res-auto"
- android:id="@+id/keyguard_pin_view"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/keyguard_pin_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
androidprv:layout_maxWidth="@dimen/keyguard_security_width"
android:orientation="vertical"
>
- <LinearLayout
- android:id="@+id/pin_container"
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:id="@+id/pin_container"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_marginBottom="8dp"
+ android:layout_weight="1"
+ android:layoutDirection="ltr"
+ android:orientation="vertical">
+
+ <!-- Set this to be just above key1. It would be better to introduce a barrier above
+ key1/key2/key3, then place this View above that. Sadly, that doesn't work (the Barrier
+ drops to the bottom of the page, and key1/2/3 all shoot up to the top-left). In any
+ case, the Flow should ensure that key1/2/3 all have the same top, so this should be
+ fine. -->
+ <com.android.keyguard.AlphaOptimizedRelativeLayout
+ android:id="@+id/row0"
android:layout_width="match_parent"
- android:layout_height="0dp"
- android:orientation="vertical"
- android:layout_weight="1"
- android:layoutDirection="ltr"
- android:layout_marginBottom="8dp"
- >
- <Space
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"
- />
- <com.android.keyguard.AlphaOptimizedRelativeLayout
- android:id="@+id/row0"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingBottom="@dimen/num_pad_entry_row_margin_bottom"
- >
+ android:layout_height="wrap_content"
+ android:paddingBottom="@dimen/num_pad_entry_row_margin_bottom"
+ androidprv:layout_constraintBottom_toTopOf="@id/key1"
+ androidprv:layout_constraintEnd_toEndOf="parent"
+ androidprv:layout_constraintStart_toStartOf="parent"
+
+ androidprv:layout_constraintTop_toTopOf="parent"
+ androidprv:layout_constraintVertical_bias="1.0">
+
<com.android.keyguard.PasswordTextView
- android:id="@+id/pinEntry"
- android:layout_width="@dimen/keyguard_security_width"
- android:layout_height="@dimen/keyguard_password_height"
- style="@style/Widget.TextView.Password"
- android:layout_centerHorizontal="true"
- android:layout_marginRight="72dp"
- androidprv:scaledTextSize="@integer/scaled_password_text_size"
- android:contentDescription="@string/keyguard_accessibility_pin_area"
- />
+ android:id="@+id/pinEntry"
+ style="@style/Widget.TextView.Password"
+ android:layout_width="@dimen/keyguard_security_width"
+ android:layout_height="@dimen/keyguard_password_height"
+ android:layout_centerHorizontal="true"
+ android:layout_marginRight="72dp"
+ android:contentDescription="@string/keyguard_accessibility_pin_area"
+ androidprv:scaledTextSize="@integer/scaled_password_text_size" />
</com.android.keyguard.AlphaOptimizedRelativeLayout>
- <LinearLayout
- android:id="@+id/row1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:layout_gravity="center_horizontal"
- android:layout_marginBottom="@dimen/num_pad_row_margin_bottom"
- >
- <com.android.keyguard.NumPadKey
- android:id="@+id/key1"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/num_pad_key_margin_end"
- androidprv:textView="@+id/pinEntry"
- androidprv:digit="1"
- />
- <com.android.keyguard.NumPadKey
- android:id="@+id/key2"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/num_pad_key_margin_end"
- androidprv:textView="@+id/pinEntry"
- androidprv:digit="2"
- />
- <com.android.keyguard.NumPadKey
- android:id="@+id/key3"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- androidprv:textView="@+id/pinEntry"
- androidprv:digit="3"
- />
- </LinearLayout>
- <LinearLayout
- android:id="@+id/row2"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:layout_gravity="center_horizontal"
- android:layout_marginBottom="@dimen/num_pad_row_margin_bottom"
- >
- <com.android.keyguard.NumPadKey
- android:id="@+id/key4"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/num_pad_key_margin_end"
- androidprv:textView="@+id/pinEntry"
- androidprv:digit="4"
- />
- <com.android.keyguard.NumPadKey
- android:id="@+id/key5"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/num_pad_key_margin_end"
- androidprv:textView="@+id/pinEntry"
- androidprv:digit="5"
- />
- <com.android.keyguard.NumPadKey
- android:id="@+id/key6"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- androidprv:textView="@+id/pinEntry"
- androidprv:digit="6"
- />
- </LinearLayout>
- <LinearLayout
- android:id="@+id/row3"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:layout_gravity="center_horizontal"
- android:layout_marginBottom="@dimen/num_pad_row_margin_bottom"
- >
- <com.android.keyguard.NumPadKey
- android:id="@+id/key7"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/num_pad_key_margin_end"
- androidprv:textView="@+id/pinEntry"
- androidprv:digit="7"
- />
- <com.android.keyguard.NumPadKey
- android:id="@+id/key8"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/num_pad_key_margin_end"
- androidprv:textView="@+id/pinEntry"
- androidprv:digit="8"
- />
- <com.android.keyguard.NumPadKey
- android:id="@+id/key9"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- androidprv:textView="@+id/pinEntry"
- androidprv:digit="9"
- />
- </LinearLayout>
- <LinearLayout
- android:id="@+id/row4"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:layout_gravity="center_horizontal"
- >
- <com.android.keyguard.NumPadButton
- android:id="@+id/delete_button"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/num_pad_key_margin_end"
- android:contentDescription="@string/keyboardview_keycode_delete"
- style="@style/NumPadKey.Delete"
- />
- <com.android.keyguard.NumPadKey
- android:id="@+id/key0"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/num_pad_key_margin_end"
- androidprv:textView="@+id/pinEntry"
- androidprv:digit="0"
- />
- <com.android.keyguard.NumPadButton
- android:id="@+id/key_enter"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- style="@style/NumPadKey.Enter"
- android:contentDescription="@string/keyboardview_keycode_enter"
- />
- </LinearLayout>
- </LinearLayout>
+
+ <androidx.constraintlayout.helper.widget.Flow
+ android:id="@+id/flow1"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:orientation="horizontal"
+
+ androidprv:constraint_referenced_ids="key1,key2,key3,key4,key5,key6,key7,key8,key9,delete_button,key0,key_enter"
+
+ androidprv:flow_horizontalGap="@dimen/num_pad_key_margin_end"
+
+ androidprv:flow_horizontalStyle="packed"
+ androidprv:flow_maxElementsWrap="3"
+
+ androidprv:flow_verticalGap="@dimen/num_pad_entry_row_margin_bottom"
+ androidprv:flow_verticalStyle="packed"
+ androidprv:flow_verticalBias="1.0"
+
+ androidprv:flow_wrapMode="aligned"
+
+ androidprv:layout_constraintTop_toTopOf="parent"
+ androidprv:layout_constraintBottom_toBottomOf="parent"
+ androidprv:layout_constraintEnd_toEndOf="parent"
+ androidprv:layout_constraintStart_toStartOf="parent" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key1"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ androidprv:digit="1"
+ androidprv:textView="@+id/pinEntry" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key2"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ androidprv:digit="2"
+ androidprv:textView="@+id/pinEntry" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key3"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ androidprv:digit="3"
+ androidprv:textView="@+id/pinEntry" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key4"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ androidprv:digit="4"
+ androidprv:textView="@+id/pinEntry" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key5"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ androidprv:digit="5"
+ androidprv:textView="@+id/pinEntry" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key6"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ androidprv:digit="6"
+ androidprv:textView="@+id/pinEntry" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key7"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ androidprv:digit="7"
+ androidprv:textView="@+id/pinEntry" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key8"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ androidprv:digit="8"
+ androidprv:textView="@+id/pinEntry" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key9"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ androidprv:digit="9"
+ androidprv:textView="@+id/pinEntry" />
+
+
+ <com.android.keyguard.NumPadButton
+ android:id="@+id/delete_button"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ style="@style/NumPadKey.Delete"
+ android:contentDescription="@string/keyboardview_keycode_delete"
+ />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key0"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ androidprv:digit="0"
+ androidprv:textView="@+id/pinEntry" />
+
+ <com.android.keyguard.NumPadButton
+ android:id="@+id/key_enter"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ style="@style/NumPadKey.Enter"
+ android:contentDescription="@string/keyboardview_keycode_enter"
+ />
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+
+
+
<include layout="@layout/keyguard_eca"
android:id="@+id/keyguard_selector_fade_container"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res-keyguard/values-land/donottranslate.xml b/packages/SystemUI/res-keyguard/values-land/donottranslate.xml
new file mode 100644
index 0000000..9912b69
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/values-land/donottranslate.xml
@@ -0,0 +1,19 @@
+<?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">
+ <string name="num_pad_key_ratio">1.51</string>
+</resources>
diff --git a/packages/SystemUI/res-keyguard/values/donottranslate.xml b/packages/SystemUI/res-keyguard/values/donottranslate.xml
index 1934457..052d329 100644
--- a/packages/SystemUI/res-keyguard/values/donottranslate.xml
+++ b/packages/SystemUI/res-keyguard/values/donottranslate.xml
@@ -29,4 +29,6 @@
<!-- Skeleton string format for displaying the time in 24-hour format. -->
<string name="clock_24hr_format">Hm</string>
+
+ <string name="num_pad_key_ratio">1</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml
index 72b027a..ea769c6 100644
--- a/packages/SystemUI/res-keyguard/values/styles.xml
+++ b/packages/SystemUI/res-keyguard/values/styles.xml
@@ -37,6 +37,10 @@
<item name="android:colorControlNormal">@null</item>
<item name="android:colorControlHighlight">?android:attr/colorAccent</item>
<item name="android:background">@drawable/num_pad_key_background</item>
+
+ <!-- Default values for NumPadKey used in a ConstraintLayout. -->
+ <item name="layout_constraintDimensionRatio">@string/num_pad_key_ratio</item>
+ <item name="layout_constraintWidth_max">@dimen/num_pad_key_width</item>
</style>
<style name="Widget.TextView.NumPadKey.Digit"
parent="@android:style/Widget.DeviceDefault.TextView">
diff --git a/packages/SystemUI/res/layout/communal_host_view.xml b/packages/SystemUI/res/layout/communal_host_view.xml
new file mode 100644
index 0000000..d3698be
--- /dev/null
+++ b/packages/SystemUI/res/layout/communal_host_view.xml
@@ -0,0 +1,26 @@
+<?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.
+ -->
+
+<!-- This is a view that shows general status information in Keyguard. -->
+<com.android.systemui.communal.CommunalHostView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/communal_host"
+ android:orientation="vertical"
+ systemui:layout_constraintEnd_toEndOf="parent"
+ android:layout_width="0dp"
+ android:layout_height="0dp"/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_carrier.xml b/packages/SystemUI/res/layout/qs_carrier.xml
index d4594d1..a854660 100644
--- a/packages/SystemUI/res/layout/qs_carrier.xml
+++ b/packages/SystemUI/res/layout/qs_carrier.xml
@@ -39,6 +39,13 @@
android:singleLine="true"
android:maxEms="7"/>
+ <View
+ android:id="@+id/spacer"
+ android:layout_width="@dimen/qs_carrier_margin_width"
+ android:layout_height="match_parent"
+ android:visibility="gone"
+ />
+
<include
layout="@layout/mobile_signal_group"
android:layout_width="wrap_content"
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 03189fa..df02730 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
@@ -55,7 +55,7 @@
android:clipChildren="false"
android:clipToPadding="false"
android:focusable="true"
- android:paddingBottom="10dp"
+ android:paddingBottom="24dp"
android:importantForAccessibility="yes" />
</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index cf91a2b..da0010e 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -106,6 +106,9 @@
systemui:layout_constraintEnd_toEndOf="parent"
/>
+ <include layout="@layout/communal_host_view"
+ android:visibility="gone"/>
+
<include layout="@layout/ambient_indication"
android:id="@+id/ambient_indication_container" />
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index c5578f2..b2274a6 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Dit deblokkeer toegang vir alle programme en dienste wat toegelaat word om jou kamera te gebruik."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Dit deblokkeer toegang vir alle programme en dienste wat toegelaat word om jou kamera of mikrofoon te gebruik."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Toestel"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Swiep op om programme te wissel"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Sleep regs om programme vinnig te wissel"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Wissel oorsig"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Gelaai"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Laai tans"</string>
diff --git a/packages/SystemUI/res/values-af/strings_tv.xml b/packages/SystemUI/res/values-af/strings_tv.xml
index 2e9400e..5420779 100644
--- a/packages/SystemUI/res/values-af/strings_tv.xml
+++ b/packages/SystemUI/res/values-af/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Kennisgewings"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Geen kennisgewings nie"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 4be2cee..abb4ef9 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"ይህ ካሜራዎን እንዲጠቀሙ ለተፈቀደላቸው ሁሉም መተግበሪያዎች እና አገልግሎቶች መዳረሻን እገዳ ያነሳል።"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"ይህ የእርስዎን ካሜራ ወይም ማይክሮፎን እንዲጠቀሙ የተፈቀደላቸው የሁሉም መተግበሪያዎች እና አገልግሎቶች መዳረሻ እገዳን ያነሳል።"</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"መሣሪያ"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"መተግበሪያዎችን ለመቀየር ወደ ላይ ያንሸራትቱ"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"መተግበሪያዎችን በፍጥነት ለመቀየር ወደ ቀኝ ይጎትቱ"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"አጠቃላይ እይታን ቀያይር"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"ባትሪ ሞልቷል"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"ኃይል በመሙላት ላይ"</string>
diff --git a/packages/SystemUI/res/values-am/strings_tv.xml b/packages/SystemUI/res/values-am/strings_tv.xml
index 71d887d..ede0b78 100644
--- a/packages/SystemUI/res/values-am/strings_tv.xml
+++ b/packages/SystemUI/res/values-am/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"በ<xliff:g id="VPN_APP">%1$s</xliff:g> በኩል"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"ማሳወቂያዎች"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"ምንም ማሳወቂያዎች የሉም"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 300f3c6..ad4402b 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -441,8 +441,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"يؤدي هذا الخيار إلى إزالة حظر الوصول بالنسبة إلى كل التطبيقات والخدمات المسموح لها باستخدام الكاميرا."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"يؤدي هذا الخيار إلى إزالة حظر الوصول بالنسبة إلى كل التطبيقات والخدمات المسموح لها باستخدام الكاميرا أو الميكروفون."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"الجهاز"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"مرّر سريعًا لأعلى لتبديل التطبيقات"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"اسحب لليسار للتبديل السريع بين التطبيقات"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"تبديل \"النظرة العامة\""</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"تم الشحن"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"جارٍ الشحن"</string>
diff --git a/packages/SystemUI/res/values-ar/strings_tv.xml b/packages/SystemUI/res/values-ar/strings_tv.xml
index 769999f..f6c4aef 100644
--- a/packages/SystemUI/res/values-ar/strings_tv.xml
+++ b/packages/SystemUI/res/values-ar/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"عبر <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"الإشعارات"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"ما من إشعارات"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index b06e010..17149a1 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"এইটোৱে আপোনাৰ কেমেৰা ব্যৱহাৰ কৰিবলৈ অনুমতি দিয়া আটাইবোৰ এপ্ আৰু সেৱাৰ বাবে এক্সেছ অৱৰোধৰ পৰা আঁতৰায়।"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"এইটোৱে আপোনাৰ কেমেৰা অথবা মাইক্ৰ\'ফ\'ন ব্যৱহাৰ কৰিবলৈ অনুমতি দিয়া আটাইবোৰ এপ্ আৰু সেৱাৰ বাবে এক্সেছ অৱৰোধৰ পৰা আঁতৰায়।"</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"ডিভাইচ"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"আনটো এপ্ ব্য়ৱহাৰ কৰিবলৈ ওপৰলৈ ছোৱাইপ কৰক"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"খৰতকীয়াকৈ আনটো এপ্ ব্য়ৱহাৰ কৰিবলৈ সোঁফালে টানক"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"অৱলোকন ট’গল কৰক"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"চ্চার্জ হ’ল"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"চ্চার্জ হৈ আছে"</string>
diff --git a/packages/SystemUI/res/values-as/strings_tv.xml b/packages/SystemUI/res/values-as/strings_tv.xml
index 859ea2c..6ceee80 100644
--- a/packages/SystemUI/res/values-as/strings_tv.xml
+++ b/packages/SystemUI/res/values-as/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g>ৰ জৰিয়তে"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"জাননী"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"কোনো জাননী নাই"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 4b9dfa5..c1d520c 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Kamera və mikrofon istifadə edən bütün tətbiq və xidmətlərə giriş verir."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Kamera və mikrofon istifadə edən bütün tətbiq və xidmətlərə giriş verir."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Cihaz"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Tətbiqi dəyişmək üçün yuxarı sürüşdürün"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Tətbiqləri cəld dəyişmək üçün sağa çəkin"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"İcmala Keçin"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Enerji yığılıb"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Enerji doldurulur"</string>
diff --git a/packages/SystemUI/res/values-az/strings_tv.xml b/packages/SystemUI/res/values-az/strings_tv.xml
index 1f1b649..d141ad6 100644
--- a/packages/SystemUI/res/values-az/strings_tv.xml
+++ b/packages/SystemUI/res/values-az/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> vasitəsilə"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Bildirişlər"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Bildiriş yoxdur"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 3c29f85..0d6a635 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -435,8 +435,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Ovim će se odblokirati pristup za sve aplikacije i usluge koje imaju dozvolu za korišćenje kamere."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Ovim će se odblokirati pristup za sve aplikacije i usluge koje imaju dozvolu za korišćenje kamere ili mikrofona."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Uređaj"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Prevucite nagore da biste menjali aplikacije"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Prevucite udesno da biste brzo promenili aplikacije"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Uključi/isključi pregled"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Napunjena je"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Puni se"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings_tv.xml b/packages/SystemUI/res/values-b+sr+Latn/strings_tv.xml
index 2eaa499..04a7e81 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings_tv.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Preko: <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Obaveštenja"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Nema obaveštenja"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index aefeb47..f810bbf 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -437,8 +437,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Доступ адкрыецца для ўсіх праграм і сэрвісаў, якім дазволена выкарыстоўваць камеру."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Доступ адкрыецца для ўсіх праграм і сэрвісаў, якім дазволена выкарыстоўваць камеру ці мікрафон."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Прылада"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Правядзіце ўверх, каб пераключыць праграмы"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Каб хутка пераключыцца паміж праграмамі, перацягніце ўправа"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Уключыць/выключыць агляд"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Зараджаны"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Зарадка"</string>
diff --git a/packages/SystemUI/res/values-be/strings_tv.xml b/packages/SystemUI/res/values-be/strings_tv.xml
index 21a2e6e..5aa771f 100644
--- a/packages/SystemUI/res/values-be/strings_tv.xml
+++ b/packages/SystemUI/res/values-be/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Праз <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Апавяшчэнні"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Апавяшчэнняў няма"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 015504d..8ac8dad 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Това действие отблокира достъпа за всички приложения и услуги, които имат разрешение да използват камерата ви."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Това действие отблокира достъпа за всички приложения и услуги, които имат разрешение да използват камерата или микрофона ви."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Устройство"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Прекарайте пръст нагоре, за да превключите между приложенията"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Плъзнете надясно за бързо превключване между приложенията"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Превключване на общия преглед"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Заредена"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Зарежда се"</string>
diff --git a/packages/SystemUI/res/values-bg/strings_tv.xml b/packages/SystemUI/res/values-bg/strings_tv.xml
index b7af7cb..49bf014 100644
--- a/packages/SystemUI/res/values-bg/strings_tv.xml
+++ b/packages/SystemUI/res/values-bg/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Чрез <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Известия"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Няма известия"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index c8a4366..eca5467 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"এটার জন্য ক্যামেরার অ্যাক্সেস সেই সব অ্যাপ এবং পরিষেবার জন্য আনব্লক হয়ে যাবে, যাতে আপনার ক্যামেরা ব্যবহারের অনুমতি দেওয়া হয়েছে।"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"এটার জন্য ক্যামেরা অথবা মাইক্রোফোনের অ্যাক্সেস সেই সব অ্যাপ এবং পরিষেবার জন্য আনব্লক হয়ে যাবে, যাতে আপনার ক্যামেরা অথবা মাইক্রোফোন ব্যবহারের অনুমতি দেওয়া হয়েছে।"</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"ডিভাইস"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"অন্য অ্যাপে যেতে উপরের দিকে সোয়াইপ করুন"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"একটি অ্যাপ ছেড়ে দ্রুত অন্য অ্যাপে যেতে ডান দিকে টেনে আনুন"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"\'এক নজরে\' বৈশিষ্ট্যটি চালু বা বন্ধ করুন"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"চার্জ হয়েছে"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"চার্জ হচ্ছে"</string>
diff --git a/packages/SystemUI/res/values-bn/strings_tv.xml b/packages/SystemUI/res/values-bn/strings_tv.xml
index 38c24ac..5a9b456 100644
--- a/packages/SystemUI/res/values-bn/strings_tv.xml
+++ b/packages/SystemUI/res/values-bn/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g>-এর মাধ্যমে"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"বিজ্ঞপ্তি"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"কোনও বিজ্ঞপ্তি নেই"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 20fc2c6..3ed40e7 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -435,8 +435,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Ovim se deblokira pristup za sve aplikacije i usluge kojima je dozvoljeno da koriste vašu kameru."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Ovim se deblokira pristup za sve aplikacije i usluge kojima je dozvoljeno da koriste vašu kameru ili mikrofon."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Uređaj"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Prevucite prema gore za promjenu aplikacije"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Prevucite udesno za brzu promjenu aplikacija"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Pregled uključivanja/isključivanja"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Napunjeno"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Punjenje"</string>
diff --git a/packages/SystemUI/res/values-bs/strings_tv.xml b/packages/SystemUI/res/values-bs/strings_tv.xml
index 01916a1..92c5e2a 100644
--- a/packages/SystemUI/res/values-bs/strings_tv.xml
+++ b/packages/SystemUI/res/values-bs/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Putem: <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Obavještenja"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Nema obavještenja"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index ae12615..cceb9a8 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Aquesta opció desbloqueja l\'accés de tots els serveis i aplicacions que tenen permís per utilitzar la càmera."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Aquesta opció desbloqueja l\'accés de tots els serveis i aplicacions que tenen permís per utilitzar la càmera o el micròfon."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Dispositiu"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Llisca cap amunt per canviar d\'aplicació"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Arrossega el dit cap a la dreta per canviar ràpidament d\'aplicació"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Activa o desactiva Aplicacions recents"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Carregada"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"S\'està carregant"</string>
diff --git a/packages/SystemUI/res/values-ca/strings_tv.xml b/packages/SystemUI/res/values-ca/strings_tv.xml
index a060785..dac4a1a 100644
--- a/packages/SystemUI/res/values-ca/strings_tv.xml
+++ b/packages/SystemUI/res/values-ca/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Mitjançant <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Notificacions"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Cap notificació"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index b4937c6..adf156d 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -437,8 +437,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Tímto odblokujete přístup všem aplikacím a službám, které mají povoleno používat váš fotoaparát."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Tímto odblokujete přístup všem aplikacím a službám, které mají povoleno používat váš fotoaparát či mikrofon."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Zařízení"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Přejetím nahoru přepnete aplikace"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Přetažením doprava rychle přepnete aplikace"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Přepnout přehled"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Nabito"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Nabíjení"</string>
diff --git a/packages/SystemUI/res/values-cs/strings_tv.xml b/packages/SystemUI/res/values-cs/strings_tv.xml
index eeab0d9..e9f4a10 100644
--- a/packages/SystemUI/res/values-cs/strings_tv.xml
+++ b/packages/SystemUI/res/values-cs/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Přes <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Oznámení"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Žádná oznámení"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 9ee6edc..2753f65 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Dette fjerner adgangsblokeringen for alle apps og tjenester, der har tilladelse til at bruge dit kamera."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Dette fjerner adgangsblokeringen for alle apps og tjenester, der har tilladelse til at bruge dit kamera eller din mikrofon."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Enhed"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Stryg opad for at skifte apps"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Træk til højre for hurtigt at skifte app"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Slå Oversigt til/fra"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Opladet"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Oplader"</string>
diff --git a/packages/SystemUI/res/values-da/strings_tv.xml b/packages/SystemUI/res/values-da/strings_tv.xml
index fb0bc2d..9534776 100644
--- a/packages/SystemUI/res/values-da/strings_tv.xml
+++ b/packages/SystemUI/res/values-da/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Notifikationer"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Ingen notifikationer"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 5b31275..c4fa1d7 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Dadurch wird die Blockierung des Zugriffs für alle Apps und Dienste aufgehoben, die deine Kamera verwenden dürfen."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Dadurch wird die Blockierung des Zugriffs für alle Apps und Dienste aufgehoben, die deine Kamera oder dein Mikrofon verwenden dürfen."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Gerät"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Nach oben wischen, um Apps zu wechseln"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Zum schnellen Wechseln der Apps nach rechts ziehen"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Übersicht ein-/ausblenden"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Aufgeladen"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Wird aufgeladen"</string>
diff --git a/packages/SystemUI/res/values-de/strings_tv.xml b/packages/SystemUI/res/values-de/strings_tv.xml
index 0345c80..ec162ef 100644
--- a/packages/SystemUI/res/values-de/strings_tv.xml
+++ b/packages/SystemUI/res/values-de/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Über <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Benachrichtigungen"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Keine Benachrichtigungen"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 1c1e806..8cf0629 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Με αυτόν τον τρόπο καταργείται ο αποκλεισμός της πρόσβασης για όλες τις εφαρμογές και υπηρεσίες που επιτρέπεται να χρησιμοποιούν την κάμερά σας."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Με αυτόν τον τρόπο καταργείται ο αποκλεισμός της πρόσβασης για όλες τις εφαρμογές και υπηρεσίες που επιτρέπεται να χρησιμοποιούν την κάμερα ή το μικρόφωνό σας."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Συσκευή"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Σύρετε προς τα επάνω για εναλλαγή των εφαρμογών"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Σύρετε προς τα δεξιά για γρήγορη εναλλαγή εφαρμογών"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Εναλλαγή επισκόπησης"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Φορτίστηκε"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Φόρτιση"</string>
diff --git a/packages/SystemUI/res/values-el/strings_tv.xml b/packages/SystemUI/res/values-el/strings_tv.xml
index cd92772..175c402 100644
--- a/packages/SystemUI/res/values-el/strings_tv.xml
+++ b/packages/SystemUI/res/values-el/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Μέσω <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Ειδοποιήσεις"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Δεν υπάρχουν ειδοποιήσεις."</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 38630e1..9dd95c7 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"This unblocks access for all apps and services allowed to use your camera."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"This unblocks access for all apps and services allowed to use your camera or microphone."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Device"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Swipe up to switch apps"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Drag right to quickly switch apps"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Toggle Overview"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Charged"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Charging"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings_tv.xml b/packages/SystemUI/res/values-en-rAU/strings_tv.xml
index 3b3e2d6..08fc8a6 100644
--- a/packages/SystemUI/res/values-en-rAU/strings_tv.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings_tv.xml
@@ -26,4 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Notifications"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"No notifications"</string>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Microphone is recording"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Camera is recording"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Camera and microphone are recording"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Microphone stopped recording"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Camera stopped recording"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Camera and microphone stopped recording"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 0669461..03e596d 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"This unblocks access for all apps and services allowed to use your camera."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"This unblocks access for all apps and services allowed to use your camera or microphone."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Device"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Swipe up to switch apps"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Drag right to quickly switch apps"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Toggle Overview"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Charged"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Charging"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings_tv.xml b/packages/SystemUI/res/values-en-rCA/strings_tv.xml
index 3b3e2d6..08fc8a6 100644
--- a/packages/SystemUI/res/values-en-rCA/strings_tv.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings_tv.xml
@@ -26,4 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Notifications"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"No notifications"</string>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Microphone is recording"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Camera is recording"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Camera and microphone are recording"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Microphone stopped recording"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Camera stopped recording"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Camera and microphone stopped recording"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 38630e1..9dd95c7 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"This unblocks access for all apps and services allowed to use your camera."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"This unblocks access for all apps and services allowed to use your camera or microphone."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Device"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Swipe up to switch apps"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Drag right to quickly switch apps"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Toggle Overview"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Charged"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Charging"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings_tv.xml b/packages/SystemUI/res/values-en-rGB/strings_tv.xml
index 3b3e2d6..08fc8a6 100644
--- a/packages/SystemUI/res/values-en-rGB/strings_tv.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings_tv.xml
@@ -26,4 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Notifications"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"No notifications"</string>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Microphone is recording"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Camera is recording"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Camera and microphone are recording"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Microphone stopped recording"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Camera stopped recording"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Camera and microphone stopped recording"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 38630e1..9dd95c7 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"This unblocks access for all apps and services allowed to use your camera."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"This unblocks access for all apps and services allowed to use your camera or microphone."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Device"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Swipe up to switch apps"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Drag right to quickly switch apps"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Toggle Overview"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Charged"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Charging"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings_tv.xml b/packages/SystemUI/res/values-en-rIN/strings_tv.xml
index 3b3e2d6..08fc8a6 100644
--- a/packages/SystemUI/res/values-en-rIN/strings_tv.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings_tv.xml
@@ -26,4 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Notifications"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"No notifications"</string>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Microphone is recording"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Camera is recording"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Camera and microphone are recording"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Microphone stopped recording"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Camera stopped recording"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Camera and microphone stopped recording"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 5668317..1b9a302 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"This unblocks access for all apps and services allowed to use your camera."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"This unblocks access for all apps and services allowed to use your camera or microphone."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Device"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Swipe up to switch apps"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Drag right to quickly switch apps"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Toggle Overview"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Charged"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Charging"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings_tv.xml b/packages/SystemUI/res/values-en-rXC/strings_tv.xml
index 34882b3..c030833 100644
--- a/packages/SystemUI/res/values-en-rXC/strings_tv.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings_tv.xml
@@ -26,4 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Notifications"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"No Notifications"</string>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Microphone is recording"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Camera is recording"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Camera and Microphone are recording"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Microphone stopped recording"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Camera stopped recording"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Camera and Microphone stopped recording"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index c04d600..f03bfd7 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Esta acción desbloquea el acceso para todos los servicios y las apps que tengan permitido usar la cámara."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Esta acción permite que todas las aplicaciones y servicios que tengan permiso puedan usar la cámara o el micrófono."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Dispositivo"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Desliza el dedo hacia arriba para cambiar de app"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Arrastra a la derecha para cambiar aplicaciones rápidamente"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Ocultar o mostrar Recientes"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Cargada"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Cargando"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings_tv.xml b/packages/SystemUI/res/values-es-rUS/strings_tv.xml
index a0a355b..680e7cc 100644
--- a/packages/SystemUI/res/values-es-rUS/strings_tv.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"A través de <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Notificaciones"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"No hay notificaciones"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index bbaf208..f2943ae 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Si lo haces, todas las aplicaciones y servicios que tengan permiso podrán usar tu cámara."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Si lo haces, todas las aplicaciones y servicios que tengan permiso podrán usar tu cámara o tu micrófono."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Dispositivo"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Desliza el dedo hacia arriba para cambiar de aplicación"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Arrastra hacia la derecha para cambiar rápidamente de aplicación"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Mostrar u ocultar aplicaciones recientes"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Cargada"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Cargando"</string>
diff --git a/packages/SystemUI/res/values-es/strings_tv.xml b/packages/SystemUI/res/values-es/strings_tv.xml
index 4607ad5..16154a4 100644
--- a/packages/SystemUI/res/values-es/strings_tv.xml
+++ b/packages/SystemUI/res/values-es/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"A través de <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Notificaciones"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Sin notificaciones"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index b23b283..a1ab2c4 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Sellega tühistatakse juurdepääsu blokeerimine kõikide rakenduste ja teenuste puhul, millel on lubatud kaamerat kasutada."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Sellega tühistatakse juurdepääsu blokeerimine kõikide rakenduste ja teenuste puhul, millel on lubatud kaamerat või mikrofoni kasutada."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Seade"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Rakenduste vahetamiseks pühkige üles"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Lohistage paremale, et rakendusi kiiresti vahetada"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Lehe Ülevaade sisse- ja väljalülitamine"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Laetud"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Laadimine"</string>
diff --git a/packages/SystemUI/res/values-et/strings_tv.xml b/packages/SystemUI/res/values-et/strings_tv.xml
index 593298e..3732020 100644
--- a/packages/SystemUI/res/values-et/strings_tv.xml
+++ b/packages/SystemUI/res/values-et/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Teenuse <xliff:g id="VPN_APP">%1$s</xliff:g> kaudu"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Märguanded"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Märguandeid pole"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 6344f62..177270a 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Kamera atzitzeko baimena duten aplikazio eta zerbitzu guztiek erabili ahalko dute."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Kamera edo mikrofonoa atzitzeko baimena duten aplikazio eta zerbitzu guztiek erabili ahalko dituzte."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Gailua"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Egin gora aplikazioa aldatzeko"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Arrastatu eskuinera aplikazioa azkar aldatzeko"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Aldatu ikuspegi orokorra"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Kargatuta"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Kargatzen"</string>
diff --git a/packages/SystemUI/res/values-eu/strings_tv.xml b/packages/SystemUI/res/values-eu/strings_tv.xml
index e1c4fcc..524165e 100644
--- a/packages/SystemUI/res/values-eu/strings_tv.xml
+++ b/packages/SystemUI/res/values-eu/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> bidez"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Jakinarazpenak"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Ez dago jakinarazpenik"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 6988df2..e06764d 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"با این کار دسترسی برای همه برنامهها و سرویسهایی که مجاز هستند از دوربینتان استفاده کنند لغو انسداد میشود."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"با این کار دسترسی برای همه برنامهها و دستگاههایی که مجاز هستند از دوربین یا میکروفونتان استفاده کنند لغو انسداد میشود."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"دستگاه"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"برای تغییر برنامهها، تند بهبالا بکشید"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"برای جابهجایی سریع میان برنامهها، به چپ بکشید"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"تغییر وضعیت نمای کلی"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"شارژ کامل شد"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"در حال شارژ شدن"</string>
diff --git a/packages/SystemUI/res/values-fa/strings_tv.xml b/packages/SystemUI/res/values-fa/strings_tv.xml
index 5ad12df..8038755 100644
--- a/packages/SystemUI/res/values-fa/strings_tv.xml
+++ b/packages/SystemUI/res/values-fa/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"ازطریق <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"اعلانها"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"اعلانی ندارید"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 29304c89..548d34c 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Tämä kumoaa kaikkien sellaisten sovellusten ja palveluiden eston, joilla on lupa käyttää kameraasi."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Tämä kumoaa eston kaikkien sellaisten sovellusten ja palveluiden osalta, joilla on lupa käyttää kameraasi tai mikrofoniasi."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Laite"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Vaihda sovellusta pyyhkäisemällä ylös"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Vaihda sovellusta nopeasti vetämällä oikealle"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Näytä/piilota viimeisimmät"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Ladattu"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Ladataan"</string>
diff --git a/packages/SystemUI/res/values-fi/strings_tv.xml b/packages/SystemUI/res/values-fi/strings_tv.xml
index 61cd5ab..17797d7 100644
--- a/packages/SystemUI/res/values-fi/strings_tv.xml
+++ b/packages/SystemUI/res/values-fi/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Palvelun <xliff:g id="VPN_APP">%1$s</xliff:g> kautta"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Ilmoitukset"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Ei ilmoituksia"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index a479e83..7f942cc 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Cette action débloque l\'accès pour toutes les applications et pour tous les services autorisés à utiliser l\'appareil photo."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Cette action débloque l\'accès pour toutes les applications et tous les services autorisés à utiliser l\'appareil photo ou le microphone."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Appareil"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Balayez vers le haut pour changer d\'application"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Balayez l\'écran vers la droite pour changer rapidement d\'application"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Basculer l\'aperçu"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Chargée"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Charge en cours..."</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings_tv.xml b/packages/SystemUI/res/values-fr-rCA/strings_tv.xml
index a667d76..7f45411 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings_tv.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Par <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Notifications"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Aucune notification"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index fef652b..f540cfe 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Cette action débloque l\'accès à tous les services et applis autorisés à utiliser votre appareil photo."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Cette action débloque l\'accès pour tous les services et applis autorisés à utiliser votre appareil photo ou votre micro."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Appareil"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Balayer l\'écran vers le haut pour changer d\'application"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Déplacer vers la droite pour changer rapidement d\'application"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Activer/Désactiver l\'aperçu"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Chargé"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"En charge"</string>
diff --git a/packages/SystemUI/res/values-fr/strings_tv.xml b/packages/SystemUI/res/values-fr/strings_tv.xml
index 25fab4e..99bab80 100644
--- a/packages/SystemUI/res/values-fr/strings_tv.xml
+++ b/packages/SystemUI/res/values-fr/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Notifications"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Aucune notification"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 9e91ae5..9b9c4f1 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Con esta acción desbloquearase o acceso á cámara para todas as aplicacións e servizos que teñan permiso para utilizala."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Con esta acción desbloquearase o acceso á cámara ou ao micrófono para todas as aplicacións e servizos que teñan permiso para utilizalos."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Dispositivo"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Pasar o dedo cara arriba para cambiar de aplicación"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Arrastra cara á dereita para cambiar de aplicacións rapidamente"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Activar/desactivar Visión xeral"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Cargado"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Cargando"</string>
diff --git a/packages/SystemUI/res/values-gl/strings_tv.xml b/packages/SystemUI/res/values-gl/strings_tv.xml
index cd12b94..0d35c4d 100644
--- a/packages/SystemUI/res/values-gl/strings_tv.xml
+++ b/packages/SystemUI/res/values-gl/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"A través de <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Notificacións"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Non hai notificacións"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index e099447..32c6a534 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"આ તમારા કૅમેરાનો ઉપયોગ કરવાની મંજૂરી ધરાવતી તમામ ઍપ અને સેવાઓ માટે ઍક્સેસને અનબ્લૉક કરે છે."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"આ તમારા કૅમેરા અથવા માઇક્રોફોનનો ઉપયોગ કરવાની મંજૂરી ધરાવતી તમામ ઍપ અને સેવાઓ માટે ઍક્સેસને અનબ્લૉક કરે છે."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"ડિવાઇસ"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"ઍપ સ્વિચ કરવા માટે ઉપરની તરફ સ્વાઇપ કરો"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"ઍપને ઝડપથી સ્વિચ કરવા માટે જમણે ખેંચો"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"ઝલકને ટૉગલ કરો"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"ચાર્જ થઈ ગયું"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"ચાર્જ થઈ રહ્યું છે"</string>
diff --git a/packages/SystemUI/res/values-gu/strings_tv.xml b/packages/SystemUI/res/values-gu/strings_tv.xml
index a53e983..c2c8ad6 100644
--- a/packages/SystemUI/res/values-gu/strings_tv.xml
+++ b/packages/SystemUI/res/values-gu/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> મારફતે"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"નોટિફિકેશન"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"કોઈ નોટિફિકેશન નથી"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index fde2a39..c9636c2 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"ऐसा करने से, कैमरे का ऐक्सेस उन सभी ऐप्लिकेशन और सेवाओं के लिए अनब्लॉक हो जाएगा जिन्हें कैमरे का इस्तेमाल करने की अनुमति दी गई है."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"ऐसा करने से, कैमरा या माइक्रोफ़ोन का ऐक्सेस उन सभी ऐप्लिकेशन और सेवाओं के लिए अनब्लॉक हो जाएगा जिन्हें ये इस्तेमाल करने की अनुमति है."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"डिवाइस"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"ऐप्लिकेशन बदलने के लिए ऊपर स्वाइप करें"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"ऐप्लिकेशन को झटपट स्विच करने के लिए उसे दाईं ओर खींचें और छोड़ें"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"खास जानकारी टॉगल करें"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"चार्ज हो गई है"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"चार्ज हो रही है"</string>
diff --git a/packages/SystemUI/res/values-hi/strings_tv.xml b/packages/SystemUI/res/values-hi/strings_tv.xml
index fedaae3..eb8f150 100644
--- a/packages/SystemUI/res/values-hi/strings_tv.xml
+++ b/packages/SystemUI/res/values-hi/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> के ज़रिए"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"सूचनाएं"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"कोई सूचना नहीं है"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index bbba1a8..e341049 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -435,8 +435,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Time se deblokira pristup za sve aplikacije i usluge kojima je dopuštena upotreba vašeg fotoaparata."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Time se deblokira pristup za sve aplikacije i usluge kojima je dopuštena upotreba vašeg fotoaparata ili mikrofona."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Uređaj"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Prijeđite prstom prema gore da biste promijenili aplikaciju"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Povucite udesno da biste brzo promijenili aplikaciju"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Uključivanje/isključivanje pregleda"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Napunjeno"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Punjenje"</string>
diff --git a/packages/SystemUI/res/values-hr/strings_tv.xml b/packages/SystemUI/res/values-hr/strings_tv.xml
index 3bfdf70..241195b 100644
--- a/packages/SystemUI/res/values-hr/strings_tv.xml
+++ b/packages/SystemUI/res/values-hr/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Putem mreže <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Obavijesti"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Nema obavijesti"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 7eb5ec1..02eb298 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Ezzel feloldja a hozzáférés letiltását az összes olyan alkalmazás és szolgáltatás esetében, amelyek számára engedélyezte a kamera használatát."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Ezzel feloldja a hozzáférés letiltását az összes olyan alkalmazás és szolgáltatás esetében, amelyek számára engedélyezte a kamera vagy a mikrofon használatát."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Eszköz"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Váltás az alkalmazások között felfelé csúsztatással"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Húzza jobbra az ujját az alkalmazások közötti gyors váltáshoz"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Áttekintés be- és kikapcsolása"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Feltöltve"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Töltés"</string>
diff --git a/packages/SystemUI/res/values-hu/strings_tv.xml b/packages/SystemUI/res/values-hu/strings_tv.xml
index 91183af..e825584 100644
--- a/packages/SystemUI/res/values-hu/strings_tv.xml
+++ b/packages/SystemUI/res/values-hu/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Ezzel: <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Értesítések"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Nincs értesítés"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 95b2d6a..c3a3bb8 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Սա բացում է մուտքը բոլոր հավելվածների և ծառայությունների համար, որոնք ունեն ձեր տեսախցիկն օգտագործելու թույլտվություն։"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Սա բացում է մուտքը բոլոր հավելվածների և ծառայությունների համար, որոնք ունեն ձեր տեսախցիկը կամ խոսափողն օգտագործելու թույլտվություն։"</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Սարք"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Սահեցրեք վերև՝ մյուս հավելվածին անցնելու համար"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Քաշեք աջ՝ հավելվածների միջև անցնելու համար"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Միացնել/անջատել համատեսքը"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Լիցքավորված է"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Լիցքավորվում է"</string>
diff --git a/packages/SystemUI/res/values-hy/strings_tv.xml b/packages/SystemUI/res/values-hy/strings_tv.xml
index cf4eb90..0fab090 100644
--- a/packages/SystemUI/res/values-hy/strings_tv.xml
+++ b/packages/SystemUI/res/values-hy/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g>-ի միջոցով"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Ծանուցումներ"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Ծանուցումներ չկան"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 193628a..0444ee4 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Ini akan berhenti memblokir akses untuk semua aplikasi dan layanan yang diizinkan menggunakan kamera."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Langkah ini akan berhenti memblokir akses untuk semua aplikasi dan layanan yang diizinkan menggunakan kamera atau mikrofon."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Perangkat"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Geser ke atas untuk beralih aplikasi"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Tarik ke kanan untuk beralih aplikasi dengan cepat"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Aktifkan Ringkasan"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Terisi penuh"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Mengisi daya"</string>
diff --git a/packages/SystemUI/res/values-in/strings_tv.xml b/packages/SystemUI/res/values-in/strings_tv.xml
index 3b446ad..c787ca2 100644
--- a/packages/SystemUI/res/values-in/strings_tv.xml
+++ b/packages/SystemUI/res/values-in/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Melalui <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Notifikasi"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Tidak Ada Notifikasi"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index dbc7c05..b57b93a 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Þetta veitir öllum forritum og þjónustum aðgang að myndavélinni þinni."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Þetta veitir öllum forritum og þjónustum aðgang að myndavélinni og hljóðnemanum þínum."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Tæki"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Strjúktu upp til að skipta á milli forrita"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Dragðu til hægri til að skipta hratt á milli forrita"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Kveikja/slökkva á yfirliti"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Fullhlaðin"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Í hleðslu"</string>
diff --git a/packages/SystemUI/res/values-is/strings_tv.xml b/packages/SystemUI/res/values-is/strings_tv.xml
index 7c23e62..6d7c91c 100644
--- a/packages/SystemUI/res/values-is/strings_tv.xml
+++ b/packages/SystemUI/res/values-is/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Í gegnum <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Tilkynningar"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Engar tilkynningar"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 6f160b9..270c214 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Viene sbloccato l\'accesso per tutti i servizi e le app autorizzati a usare la fotocamera."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Viene sbloccato l\'accesso per tutti i servizi e le app autorizzati a usare la fotocamera o il microfono."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Dispositivo"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Scorri verso l\'alto per passare ad altre app"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Trascina verso destra per cambiare velocemente app"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Attiva/disattiva la panoramica"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Carica"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"In carica"</string>
diff --git a/packages/SystemUI/res/values-it/strings_tv.xml b/packages/SystemUI/res/values-it/strings_tv.xml
index 57931b0..c676029 100644
--- a/packages/SystemUI/res/values-it/strings_tv.xml
+++ b/packages/SystemUI/res/values-it/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Tramite <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Notifiche"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Nessuna notifica"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 9dccc98..899aca2 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -437,8 +437,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"הפעולה הזו מבטלת את חסימת הגישה של כל האפליקציות והשירותים שמורשים להשתמש במצלמה."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"הפעולה הזו מבטלת את חסימת הגישה של כל האפליקציות והשירותים שמורשים להשתמש במצלמה או במיקרופון."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"מכשיר"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"יש להחליק מעלה כדי להחליף אפליקציות"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"יש לגרור ימינה כדי לעבור במהירות בין אפליקציות"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"החלפת מצב של מסכים אחרונים"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"הסוללה טעונה"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"בטעינה"</string>
diff --git a/packages/SystemUI/res/values-iw/strings_tv.xml b/packages/SystemUI/res/values-iw/strings_tv.xml
index f01321e..46e61d0 100644
--- a/packages/SystemUI/res/values-iw/strings_tv.xml
+++ b/packages/SystemUI/res/values-iw/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"דרך <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"התראות"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"אין התראות"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 1e8020f..e67841d 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"カメラの使用が許可されているすべてのアプリとサービスでアクセスのブロックが解除されます。"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"カメラやマイクの使用が許可されているすべてのアプリとサービスでアクセスのブロックが解除されます。"</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"デバイス"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"アプリを切り替えるには上にスワイプ"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"右にドラッグするとアプリを素早く切り替えることができます"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"概要を切り替え"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"充電が完了しました"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"充電しています"</string>
diff --git a/packages/SystemUI/res/values-ja/strings_tv.xml b/packages/SystemUI/res/values-ja/strings_tv.xml
index 7f676b5..798caec 100644
--- a/packages/SystemUI/res/values-ja/strings_tv.xml
+++ b/packages/SystemUI/res/values-ja/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> 経由"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"通知"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"通知はありません"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 8177464..65813c6 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"ამ მოქმედების მეშვეობით განიბლოკება ყველა აპსა და მომსახურებაზე წვდომა, რომელთაც აქვთ თქვენი კამერის გამოყენების უფლება."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"ამ მოქმედების მეშვეობით განიბლოკება ყველა აპსა და მომსახურებაზე წვდომა, რომელთაც აქვთ თქვენი კამერის ან მიკროფონის გამოყენების უფლება."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"მოწყობილობა"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"გადაფურცლეთ ზემოთ აპების გადასართავად"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"აპების სწრაფად გადასართავად ჩავლებით გადაიტანეთ მარჯვნივ"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"მიმოხილვის გადართვა"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"დატენილია"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"მიმდინარეობს დატენვა"</string>
diff --git a/packages/SystemUI/res/values-ka/strings_tv.xml b/packages/SystemUI/res/values-ka/strings_tv.xml
index 0819781..b158e5c 100644
--- a/packages/SystemUI/res/values-ka/strings_tv.xml
+++ b/packages/SystemUI/res/values-ka/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g>-ის მიერ"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"შეტყობინებები"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"შეტყობინებები არ არის"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 983e4b8..c902051 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Камераңызды пайдалануға рұқсат берілген барлық қолданба мен қызметтің бөгеуі алынады."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Камераңызды немесе микрофоныңызды пайдалануға рұқсат берілген барлық қолданба мен қызметтің бөгеуі алынады."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Құрылғы"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Қолданбалар арасында ауысу үшін жоғары сырғытыңыз"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Қолданбаларды жылдам ауыстырып қосу үшін оңға қарай сүйреңіз"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Шолуды қосу/өшіру"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Зарядталды"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Зарядталуда"</string>
diff --git a/packages/SystemUI/res/values-kk/strings_tv.xml b/packages/SystemUI/res/values-kk/strings_tv.xml
index 768e3ac..36440c9 100644
--- a/packages/SystemUI/res/values-kk/strings_tv.xml
+++ b/packages/SystemUI/res/values-kk/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> арқылы жалғанған"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Хабарландырулар"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Хабарландырулар жоқ"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 183712b..299187d 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"ការធ្វើបែបនេះនឹងឈប់ទប់ស្កាត់ការចូលប្រើសម្រាប់កម្មវិធី និងសេវាកម្មទាំងអស់ ដែលត្រូវបានអនុញ្ញាតឱ្យប្រើកាមេរ៉ារបស់អ្នក។"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"ការធ្វើបែបនេះនឹងឈប់ទប់ស្កាត់ការចូលប្រើសម្រាប់កម្មវិធី និងសេវាកម្មទាំងអស់ ដែលត្រូវបានអនុញ្ញាតឱ្យប្រើកាមេរ៉ា ឬមីក្រូហ្វូនរបស់អ្នក។"</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"ឧបករណ៍"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"អូសឡើងលើដើម្បីប្តូរកម្មវិធី"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"អូសទៅស្ដាំដើម្បីប្ដូរកម្មវិធីបានរហ័ស"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"បិទ/បើកទិដ្ឋភាពរួម"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"បានសាកថ្មពេញ"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"កំពុងសាកថ្ម"</string>
diff --git a/packages/SystemUI/res/values-km/strings_tv.xml b/packages/SystemUI/res/values-km/strings_tv.xml
index 0dec2d6..b04cc2b 100644
--- a/packages/SystemUI/res/values-km/strings_tv.xml
+++ b/packages/SystemUI/res/values-km/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"តាមរយៈ <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"ការជូនដំណឹង"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"គ្មានការជូនដំណឹងទេ"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index e48c842..aadf662 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"ಇದು ಎಲ್ಲಾ ಆ್ಯಪ್ಗಳಿಗೆ ಹಾಗೂ ಸೇವೆಗಳಿಗೆ ನಿಮ್ಮ ಕ್ಯಾಮರಾವನ್ನು ಬಳಸುವುದಕ್ಕಾಗಿ ಇರುವ ಪ್ರವೇಶದ ನಿರ್ಬಂಧವನ್ನು ತೆಗೆದುಹಾಕುತ್ತದೆ."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"ಇದು ಎಲ್ಲಾ ಆ್ಯಪ್ಗಳಿಗೆ ಹಾಗೂ ಸೇವೆಗಳಿಗೆ ನಿಮ್ಮ ಕ್ಯಾಮರಾ ಅಥವಾ ಮೈಕ್ರೋಫೋನ್ ಬಳಸುವುದಕ್ಕಾಗಿ ಇರುವ ಪ್ರವೇಶದ ನಿರ್ಬಂಧವನ್ನು ತೆಗೆದುಹಾಕುತ್ತದೆ."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"ಸಾಧನ"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ಬದಲಾಯಿಸಲು ಸ್ವೈಪ್ ಮಾಡಿ"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ಬದಲಿಸಲು ತ್ವರಿತವಾಗಿ ಬಲಕ್ಕೆ ಡ್ರ್ಯಾಗ್ ಮಾಡಿ"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"ಟಾಗಲ್ ನ ಅವಲೋಕನ"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"ಚಾರ್ಜ್ ಆಗಿದೆ"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ"</string>
diff --git a/packages/SystemUI/res/values-kn/strings_tv.xml b/packages/SystemUI/res/values-kn/strings_tv.xml
index ef10e3a..e4b3314 100644
--- a/packages/SystemUI/res/values-kn/strings_tv.xml
+++ b/packages/SystemUI/res/values-kn/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> ಮೂಲಕ"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"ಅಧಿಸೂಚನೆಗಳು"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"ಯಾವುದೇ ಅಧಿಸೂಚನೆಗಳಿಲ್ಲ"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 6f896c7..e592f5a 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"카메라를 사용할 수 있는 모든 앱 및 서비스에 대해 액세스가 차단 해제됩니다."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"카메라 또는 마이크를 사용할 수 있는 모든 앱 및 서비스에 대해 액세스가 차단 해제됩니다."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"기기"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"위로 스와이프하여 앱 전환"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"앱을 빠르게 전환하려면 오른쪽으로 드래그"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"최근 사용 버튼 전환"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"충전됨"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"충전 중"</string>
diff --git a/packages/SystemUI/res/values-ko/strings_tv.xml b/packages/SystemUI/res/values-ko/strings_tv.xml
index f9c723a..8849265 100644
--- a/packages/SystemUI/res/values-ko/strings_tv.xml
+++ b/packages/SystemUI/res/values-ko/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g>에 연결됨"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"알림"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"알림 없음"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 20ec715..7cbc889 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Камераны колдонууга уруксат алган бардык колдонмолор менен кызматтар бөгөттөн чыгат."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Камераңызды же микрофонуңузду колдонууга уруксат алган бардык колдонмолор менен кызматтар бөгөттөн чыгат."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Түзмөк"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Башка колдонмого которулуу үчүн өйдө сүрүңүз"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Колдонмолорду тез которуштуруу үчүн, оңго сүйрөңүз"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Назар режимин өчүрүү/күйгүзүү"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Кубатталды"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Кубатталууда"</string>
diff --git a/packages/SystemUI/res/values-ky/strings_tv.xml b/packages/SystemUI/res/values-ky/strings_tv.xml
index 1dba865..128c7e0 100644
--- a/packages/SystemUI/res/values-ky/strings_tv.xml
+++ b/packages/SystemUI/res/values-ky/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> аркылуу"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Билдирмелер"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Билдирме жок"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index de3afd3..6e0a9b3 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"ນີ້ຈະຍົກເລີກການບລັອກການເຂົ້າເຖິງແອັບ ແລະ ບໍລິການທັງໝົດທີ່ອະນຸຍາດໃຫ້ໃຊ້ກ້ອງຖ່າຍຮູບຂອງທ່ານ."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"ນີ້ຈະປົດບລັອກການເຂົ້າເຖິງແອັບ ແລະ ບໍລິການທັງໝົດທີ່ອະນຸຍາດໃຫ້ໃຊ້ກ້ອງຖ່າຍຮູບ ຫຼື ໄມໂຄຣໂຟນຂອງທ່ານ."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"ອຸປະກອນ"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"ປັດຂື້ນເພື່ອສະຫຼັບແອັບ"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"ລາກໄປຂວາເພື່ອສະຫຼັບແອັບດ່ວນ"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"ສະຫຼັບພາບຮວມ"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"ສາກເຕັມແລ້ວ."</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"ກຳລັງສາກໄຟ"</string>
diff --git a/packages/SystemUI/res/values-lo/strings_tv.xml b/packages/SystemUI/res/values-lo/strings_tv.xml
index a45fb45..b852456 100644
--- a/packages/SystemUI/res/values-lo/strings_tv.xml
+++ b/packages/SystemUI/res/values-lo/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"ຜ່ານ <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"ການແຈ້ງເຕືອນ"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"ບໍ່ມີການແຈ້ງເຕືອນ"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 230ee19..01498b9 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -437,8 +437,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Tai atlikus visų programų ir paslaugų prieigos blokavimas panaikinamas ir joms leidžiama naudoti fotoaparatą."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Tai atlikus visų programų ir paslaugų prieigos blokavimas panaikinamas ir joms leidžiama naudoti fotoaparatą ar mikrofoną."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Įrenginys"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Perbraukite aukštyn, kad perjungtumėte programas"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Vilkite į dešinę, kad greitai perjungtumėte programas"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Perjungti apžvalgą"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Įkrautas"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Kraunamas"</string>
diff --git a/packages/SystemUI/res/values-lt/strings_tv.xml b/packages/SystemUI/res/values-lt/strings_tv.xml
index 8c329f9..7cd7507 100644
--- a/packages/SystemUI/res/values-lt/strings_tv.xml
+++ b/packages/SystemUI/res/values-lt/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Per „<xliff:g id="VPN_APP">%1$s</xliff:g>“"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Pranešimai"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Nėra jokių pranešimų"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index c454f2a..c320321 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -435,8 +435,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Visas lietotnes un pakalpojumi, kuriem ir atļauts izmantot kameru, varēs tai piekļūt."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Visas lietotnes un pakalpojumi, kuriem ir atļauts izmantot kameru vai mikrofonu, varēs tiem piekļūt."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Ierīce"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Velciet augšup, lai pārslēgtu lietotnes"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Lai ātri pārslēgtu lietotnes, velciet pa labi"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Pārskata pārslēgšana"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Akumulators uzlādēts"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Notiek uzlāde"</string>
diff --git a/packages/SystemUI/res/values-lv/strings_tv.xml b/packages/SystemUI/res/values-lv/strings_tv.xml
index 758d28c..4c64843 100644
--- a/packages/SystemUI/res/values-lv/strings_tv.xml
+++ b/packages/SystemUI/res/values-lv/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Izmantojot: <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Paziņojumi"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Nav paziņojumu"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index fc1a69a..f2d40fe 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Ова ќе го одблокира пристапот за сите апликации и услуги на кои им е дозволено користење на камерата."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Ова ќе го одблокира пристапот за сите апликации и услуги на кои им е дозволено користење на камерата или микрофонот."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Уред"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Повлечете нагоре за да се префрлите од една на друга апликација"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Повлечете надесно за брзо префрлање меѓу апликациите"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Вклучи/исклучи преглед"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Наполнета"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Се полни"</string>
diff --git a/packages/SystemUI/res/values-mk/strings_tv.xml b/packages/SystemUI/res/values-mk/strings_tv.xml
index 0dfbd79..55d9df7 100644
--- a/packages/SystemUI/res/values-mk/strings_tv.xml
+++ b/packages/SystemUI/res/values-mk/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Преку <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Известувања"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Нема известувања"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 1c3837f..340dae0 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"നിങ്ങളുടെ ക്യാമറ ഉപയോഗിക്കാൻ അനുവദിച്ചിരിക്കുന്ന എല്ലാ ആപ്പുകൾക്കും സേവനങ്ങൾക്കുമുള്ള ആക്സസ് ഇത് അൺബ്ലോക്ക് ചെയ്യുന്നു."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"നിങ്ങളുടെ ക്യാമറയോ മൈക്രോഫോണോ ഉപയോഗിക്കാൻ അനുവദിച്ചിരിക്കുന്ന എല്ലാ ആപ്പുകൾക്കും സേവനങ്ങൾക്കുമുള്ള ആക്സസ് ഇത് അൺബ്ലോക്ക് ചെയ്യുന്നു."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"ഉപകരണം"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"ആപ്പുകൾ മാറാൻ മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്യുക"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"ആപ്പുകൾ പെട്ടെന്ന് മാറാൻ വലത്തോട്ട് വലിച്ചിടുക"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"അവലോകനം മാറ്റുക"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"ചാർജായി"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"ചാർജ് ചെയ്യുന്നു"</string>
diff --git a/packages/SystemUI/res/values-ml/strings_tv.xml b/packages/SystemUI/res/values-ml/strings_tv.xml
index 70cced8..6ae342cf 100644
--- a/packages/SystemUI/res/values-ml/strings_tv.xml
+++ b/packages/SystemUI/res/values-ml/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> വഴി"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"അറിയിപ്പുകൾ"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"അറിയിപ്പുകൾ ഒന്നുമില്ല"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 4e04c61..155f1a3 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Энэ нь таны камерыг ашиглах зөвшөөрөлтэй бүх апп болон үйлчилгээний хандалтыг блокоос гаргана."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Энэ нь таны камер эсвэл микрофоныг ашиглах зөвшөөрөлтэй бүх апп болон үйлчилгээний хандалтыг блокоос гаргана."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Төхөөрөмж"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Апп сэлгэхийн тулд дээш шударна уу"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Аппуудыг хурдан сэлгэхийн тулд баруун тийш чирнэ үү"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Тоймыг асаах/унтраах"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Цэнэглэгдсэн"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Цэнэглэж байна"</string>
diff --git a/packages/SystemUI/res/values-mn/strings_tv.xml b/packages/SystemUI/res/values-mn/strings_tv.xml
index 221d8ae..bbb302f 100644
--- a/packages/SystemUI/res/values-mn/strings_tv.xml
+++ b/packages/SystemUI/res/values-mn/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g>-р"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Мэдэгдэл"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Мэдэгдэл байхгүй байна"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 5785b41..721b28f3 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"हे तुमचा कॅमेरा वापरण्याची परवानगी असलेल्या सर्व ॲप्स आणि सेवांसाठी अॅक्सेस अनब्लॉक करते."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"हे तुमचा कॅमेरा आणि मायक्रोफोन वापरण्याची परवानगी असलेल्या सर्व ॲप्स व सेवांसाठी अॅक्सेस अनब्लॉक करते."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"डिव्हाइस"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"अॅप्स स्विच करण्यासाठी वर स्वाइप करा"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"अॅप्स वर झटपट स्विच करण्यासाठी उजवीकडे ड्रॅग करा"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"अवलोकन टॉगल करा."</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"चार्ज झाली"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"चार्ज होत आहे"</string>
diff --git a/packages/SystemUI/res/values-mr/strings_tv.xml b/packages/SystemUI/res/values-mr/strings_tv.xml
index ac0cad1..d596d95 100644
--- a/packages/SystemUI/res/values-mr/strings_tv.xml
+++ b/packages/SystemUI/res/values-mr/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> द्वारे"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"सूचना"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"सूचना नाहीत"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 6b6a6b7..10d8b1e 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Tindakan ini menyahsekat akses bagi semua apl dan perkhidmatan yang dibenarkan untuk menggunakan kamera anda."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Tindakan ini menyahsekat akses bagi semua apl dan perkhidmatan yang dibenarkan untuk menggunakan kamera atau mikrofon anda."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Peranti"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Leret ke atas untuk menukar apl"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Seret ke kanan untuk beralih apl dengan pantas"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Togol Ikhtisar"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Sudah dicas"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Mengecas"</string>
diff --git a/packages/SystemUI/res/values-ms/strings_tv.xml b/packages/SystemUI/res/values-ms/strings_tv.xml
index 46e345e..e28d032 100644
--- a/packages/SystemUI/res/values-ms/strings_tv.xml
+++ b/packages/SystemUI/res/values-ms/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Melalui <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Pemberitahuan"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Tiada Pemberitahuan"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index ba643f0..9cc4ee2 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"၎င်းက သင့်ကင်မရာသုံးရန် ခွင့်ပြုထားသော အက်ပ်နှင့် ဝန်ဆောင်မှုအားလုံးအတွက် သုံးခွင့်ကို ပြန်ဖွင့်ပေးသည်။"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"၎င်းက သင့်ကင်မရာ (သို့) မိုက်ခရိုဖုန်းသုံးရန် ခွင့်ပြုထားသော အက်ပ်နှင့် ဝန်ဆောင်မှုအားလုံးအတွက် သုံးခွင့်ကို ပြန်ဖွင့်ပေးသည်။"</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"စက်"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"အက်ပ်များကို ဖွင့်ရန် အပေါ်သို့ ပွတ်ဆွဲပါ"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"အက်ပ်များကို ပြောင်းရန် ညာဘက်သို့ ဖိဆွဲပါ"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"ဖွင့်၊ ပိတ် အနှစ်ချုပ်"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"အားသွင်းပြီး"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"အားသွင်းနေ"</string>
diff --git a/packages/SystemUI/res/values-my/strings_tv.xml b/packages/SystemUI/res/values-my/strings_tv.xml
index 268c554..848c403 100644
--- a/packages/SystemUI/res/values-my/strings_tv.xml
+++ b/packages/SystemUI/res/values-my/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> မှတစ်ဆင့်"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"အကြောင်းကြားချက်များ"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"အကြောင်းကြားချက်များ မရှိပါ"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 7a42d3e..e091c34 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Dette opphever blokkeringen av tilgang for alle apper og tjenester som har tillatelse til å bruke kameraet."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Dette opphever blokkeringen av tilgang for alle apper og tjenester som har tillatelse til å bruke kameraet eller mikrofonen."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Enhet"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Sveip opp for å bytte apper"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Dra til høyre for å bytte apper raskt"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Slå oversikten av eller på"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Oppladet"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Lader"</string>
diff --git a/packages/SystemUI/res/values-nb/strings_tv.xml b/packages/SystemUI/res/values-nb/strings_tv.xml
index c5767dd..11de50a 100644
--- a/packages/SystemUI/res/values-nb/strings_tv.xml
+++ b/packages/SystemUI/res/values-nb/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Varsler"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Ingen varsler"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index c46d705..b271ba6 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"यसो गर्नुभयो भने क्यामेरा प्रयोग गर्ने अनुमति दिइएका सबै एप तथा सेवाहरूका लागि सो अनुमति अनब्लक गरिन्छ।"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"यसो गर्नुभयो भने क्यामेरा वा माइक्रोफोन प्रयोग गर्ने अनुमति दिइएका सबै एप तथा सेवाहरूका लागि सो अनुमति अनब्लक गरिन्छ।"</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"यन्त्र"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"एपहरू बदल्न माथितिर स्वाइप गर्नुहोस्"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"एपहरू बदल्न द्रुत गतिमा दायाँतिर ड्र्याग गर्नुहोस्"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"परिदृश्य टगल गर्नुहोस्"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"चार्ज भयो"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"चार्ज हुँदै छ"</string>
diff --git a/packages/SystemUI/res/values-ne/strings_tv.xml b/packages/SystemUI/res/values-ne/strings_tv.xml
index 925f7b76..0bcc1cc 100644
--- a/packages/SystemUI/res/values-ne/strings_tv.xml
+++ b/packages/SystemUI/res/values-ne/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> मार्फत"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"सूचनाहरू"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"कुनै पनि सूचना छैन"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index f0cc269..7331087 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Hiermee hef je de toegangsblokkering op voor alle apps en services die rechten hebben om je camera te gebruiken."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Hiermee hef je de toegangsblokkering op voor alle apps en services die rechten hebben om je camera of microfoon te gebruiken."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Apparaat"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Swipe omhoog om te schakelen tussen apps"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Sleep naar rechts om snel tussen apps te schakelen"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Overzicht aan- of uitzetten"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Opgeladen"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Opladen"</string>
diff --git a/packages/SystemUI/res/values-nl/strings_tv.xml b/packages/SystemUI/res/values-nl/strings_tv.xml
index 22d3b88..02c00ec 100644
--- a/packages/SystemUI/res/values-nl/strings_tv.xml
+++ b/packages/SystemUI/res/values-nl/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Meldingen"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Geen meldingen"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 2fcc505..6ff3814 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"ଆପଣଙ୍କ କ୍ୟାମେରାକୁ ବ୍ୟବହାର କରିବା ପାଇଁ ଅନୁମତି ଦିଆଯାଇଥିବା ସମସ୍ତ ଆପ୍ ଓ ସେବା ପାଇଁ ଏହା ଆକ୍ସେସକୁ ଅନବ୍ଲକ୍ କରେ।"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"ଆପଣଙ୍କ କ୍ୟାମେରା କିମ୍ବା ମାଇକ୍ରୋଫୋନକୁ ବ୍ୟବହାର କରିବା ପାଇଁ ଅନୁମତି ଦିଆଯାଇଥିବା ସମସ୍ତ ଆପ୍ ଓ ସେବା ପାଇଁ ଏହା ଆକ୍ସେସକୁ ଅନବ୍ଲକ୍ କରେ।"</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"ଡିଭାଇସ୍"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"ଆପ୍କୁ ବଦଳ କରିବା ପାଇଁ ସ୍ଵାଇପ୍ କରନ୍ତୁ"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"ଆପ୍ଗୁଡ଼ିକ ମଧ୍ୟରେ ଶୀଘ୍ର ବଦଳ କରିବା ପାଇଁ ଡାହାଣକୁ ଡ୍ରାଗ୍ କରନ୍ତୁ"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"ସଂକ୍ଷିପ୍ତ ବିବରଣୀକୁ ଟୋଗଲ୍ କରନ୍ତୁ"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"ଚାର୍ଜ ହୋଇଗଲା"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"ଚାର୍ଜ କରାଯାଉଛି"</string>
diff --git a/packages/SystemUI/res/values-or/strings_tv.xml b/packages/SystemUI/res/values-or/strings_tv.xml
index 707c49e..8289068 100644
--- a/packages/SystemUI/res/values-or/strings_tv.xml
+++ b/packages/SystemUI/res/values-or/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> ମାଧ୍ୟମରେ"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"କୌଣସି ବିଜ୍ଞପ୍ତି ନାହିଁ"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 3dad773..542f341 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"ਇਹ ਉਹਨਾਂ ਐਪਾਂ ਅਤੇ ਸੇਵਾਵਾਂ ਲਈ ਪਹੁੰਚ ਨੂੰ ਅਣਬਲਾਕ ਕਰਦਾ ਹੈ ਜਿਨ੍ਹਾਂ ਨੂੰ ਤੁਹਾਡਾ ਕੈਮਰਾ ਵਰਤਣ ਦੀ ਆਗਿਆ ਦਿੱਤੀ ਗਈ ਹੈ।"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"ਇਹ ਉਹਨਾਂ ਐਪਾਂ ਅਤੇ ਸੇਵਾਵਾਂ ਲਈ ਪਹੁੰਚ ਨੂੰ ਅਣਬਲਾਕ ਕਰਦਾ ਹੈ ਜਿਨ੍ਹਾਂ ਨੂੰ ਤੁਹਾਡਾ ਕੈਮਰਾ ਜਾਂ ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਵਰਤਣ ਦੀ ਆਗਿਆ ਦਿੱਤੀ ਗਈ ਹੈ।"</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"ਡੀਵਾਈਸ"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"ਐਪਾਂ ਵਿਚਾਲੇ ਅਦਲਾ-ਬਦਲੀ ਕਰਨ ਲਈ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰੋ"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"ਐਪਾਂ ਵਿਚਾਲੇ ਤੇਜ਼ੀ ਨਾਲ ਅਦਲਾ-ਬਦਲੀ ਕਰਨ ਲਈ ਸੱਜੇ ਪਾਸੇ ਵੱਲ ਘਸੀਟੋ"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"ਰੂਪ-ਰੇਖਾ ਨੂੰ ਟੌਗਲ ਕਰੋ"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"ਚਾਰਜ ਹੋਇਆ"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"ਚਾਰਜ ਕਰ ਰਿਹਾ ਹੈ"</string>
diff --git a/packages/SystemUI/res/values-pa/strings_tv.xml b/packages/SystemUI/res/values-pa/strings_tv.xml
index c076194..22fcce8 100644
--- a/packages/SystemUI/res/values-pa/strings_tv.xml
+++ b/packages/SystemUI/res/values-pa/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> ਰਾਹੀਂ"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"ਸੂਚਨਾਵਾਂ"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"ਕੋਈ ਸੂਚਨਾ ਨਹੀਂ"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 30d6f05..2d13f98 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -437,8 +437,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Spowoduje to odblokowanie dostępu dla wszystkich aplikacji i usług, które mają uprawnienia do korzystania z aparatu."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Spowoduje to odblokowanie dostępu dla wszystkich aplikacji i usług, które mają uprawnienia do korzystania z aparatu lub mikrofonu."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Urządzenie"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Przesuń w górę, by przełączyć aplikacje"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Szybko przeciągnij w prawo, by przełączyć aplikacje"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Przełącz Przegląd"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Naładowana"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Ładowanie"</string>
diff --git a/packages/SystemUI/res/values-pl/strings_tv.xml b/packages/SystemUI/res/values-pl/strings_tv.xml
index e63aade..2371b5e 100644
--- a/packages/SystemUI/res/values-pl/strings_tv.xml
+++ b/packages/SystemUI/res/values-pl/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Przez: <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Powiadomienia"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Brak powiadomień"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 24015d8..cea977f 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Essa ação desbloqueia o acesso para todos os apps e serviços com autorização para usar sua câmera."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Essa ação desbloqueia o acesso para todos os apps e serviços com autorização para usar sua câmera ou seu microfone."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Dispositivo"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Deslize para cima para mudar de app"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Arraste para a direita para mudar rapidamente de app"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Alternar Visão geral"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Carregado"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Carregando"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings_tv.xml b/packages/SystemUI/res/values-pt-rBR/strings_tv.xml
index 2ea8152..d29bc6a 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings_tv.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings_tv.xml
@@ -26,4 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Notificações"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Nenhuma notificação"</string>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"O microfone está gravando"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"A câmera está gravando"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"A câmera e o microfone estão gravando"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"O microfone parou de gravar"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"A câmera parou de gravar"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"A câmera e o microfone pararam de gravar"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 362d656..72bc64b 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Isto desbloqueia o acesso a todas as apps e serviços com autorização para utilizar a sua câmara."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Isto desbloqueia o acesso a todas as apps e serviços com autorização para utilizar a sua câmara ou microfone."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Dispositivo"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Deslizar rapidamente para cima para mudar de app"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Arraste para a direita para mudar rapidamente de app."</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Ativar/desativar Vista geral"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Carregada"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"A carregar"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings_tv.xml b/packages/SystemUI/res/values-pt-rPT/strings_tv.xml
index 8ce3e30..883fa3a 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings_tv.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Através de <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Notificações"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Sem notificações"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 24015d8..cea977f 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Essa ação desbloqueia o acesso para todos os apps e serviços com autorização para usar sua câmera."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Essa ação desbloqueia o acesso para todos os apps e serviços com autorização para usar sua câmera ou seu microfone."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Dispositivo"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Deslize para cima para mudar de app"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Arraste para a direita para mudar rapidamente de app"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Alternar Visão geral"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Carregado"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Carregando"</string>
diff --git a/packages/SystemUI/res/values-pt/strings_tv.xml b/packages/SystemUI/res/values-pt/strings_tv.xml
index 2ea8152..d29bc6a 100644
--- a/packages/SystemUI/res/values-pt/strings_tv.xml
+++ b/packages/SystemUI/res/values-pt/strings_tv.xml
@@ -26,4 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Notificações"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Nenhuma notificação"</string>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"O microfone está gravando"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"A câmera está gravando"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"A câmera e o microfone estão gravando"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"O microfone parou de gravar"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"A câmera parou de gravar"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"A câmera e o microfone pararam de gravar"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 452664f..8a0edce 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -435,8 +435,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Astfel, deblocați accesul pentru toate aplicațiile și serviciile care au permisiunea de a folosi camera."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Astfel, deblocați accesul pentru toate aplicațiile și serviciile care au permisiunea de a folosi camera sau microfonul."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Dispozitiv"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Glisați în sus pentru a comuta între aplicații"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Glisați la dreapta pentru a comuta rapid între aplicații"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Comutați secțiunea Recente"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Încărcată"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Se încarcă"</string>
diff --git a/packages/SystemUI/res/values-ro/strings_tv.xml b/packages/SystemUI/res/values-ro/strings_tv.xml
index c64a492..9f28693 100644
--- a/packages/SystemUI/res/values-ro/strings_tv.xml
+++ b/packages/SystemUI/res/values-ro/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Prin <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Notificări"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Nicio notificare"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 7ebbb43..cb852f6a 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -437,8 +437,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Будет снята блокировка доступа для всех приложений и сервисов с разрешением на использование камеры."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Будет снята блокировка доступа для всех приложений и сервисов с разрешением на использование камеры или микрофона."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Устройство"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Чтобы переключиться между приложениями, проведите по экрану вверх."</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Перетащите вправо, чтобы быстро переключиться между приложениями"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Переключить режим обзора"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Батарея заряжена"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Зарядка батареи"</string>
diff --git a/packages/SystemUI/res/values-ru/strings_tv.xml b/packages/SystemUI/res/values-ru/strings_tv.xml
index 8ce0dc2..e2162ea 100644
--- a/packages/SystemUI/res/values-ru/strings_tv.xml
+++ b/packages/SystemUI/res/values-ru/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Через приложение <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Уведомления"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Уведомлений нет."</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 6cf9f9b..e8bc947 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"මෙය ඔබගේ කැමරාව භාවිතා කිරීමට ඉඩ දී ඇති සියලු යෙදුම් සහ සේවා සඳහා ප්රවේශය අවහිර කිරීම ඉවත් කරයි."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"මෙය ඔබගේ කැමරාව හෝ මයික්රෆෝනය භාවිත කිරීමට ඉඩ දී ඇති සියලු යෙදුම් සහ සේවා සඳහා ප්රවේශය අවහිර කිරීම ඉවත් කරයි."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"උපාංගය"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"යෙදුම් මාරු කිරීමට ස්වයිප් කරන්න"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"ඉක්මනින් යෙදුම් මාරු කිරීමට දකුණට අදින්න"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"දළ විශ්ලේෂණය ටොගල කරන්න"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"අරෝපිතයි"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"ආරෝපණය වෙමින්"</string>
diff --git a/packages/SystemUI/res/values-si/strings_tv.xml b/packages/SystemUI/res/values-si/strings_tv.xml
index 3067be3..b750988 100644
--- a/packages/SystemUI/res/values-si/strings_tv.xml
+++ b/packages/SystemUI/res/values-si/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> හරහා"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"දැනුම්දීම්"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"දැනුම්දීම් නැත"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 5893223..4a646b3 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -437,8 +437,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Táto akcia odblokuje prístup všetkým aplikáciám a službám, ktoré majú povolené používať fotoaparát."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Táto akcia odblokuje prístup všetkým aplikáciám a službám, ktoré majú povolené používať fotoaparát alebo mikrofón."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Zariadenie"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Potiahnutím nahor prepnete aplikácie"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Presunutím doprava rýchlo prepnete aplikácie"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Prepnúť prehľad"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Nabitá"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Nabíja sa"</string>
diff --git a/packages/SystemUI/res/values-sk/strings_tv.xml b/packages/SystemUI/res/values-sk/strings_tv.xml
index b37648d..2b74267 100644
--- a/packages/SystemUI/res/values-sk/strings_tv.xml
+++ b/packages/SystemUI/res/values-sk/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Cez: <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Upozornenia"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Žiadne upozornenia"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 6bc27d0..627359a 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -437,8 +437,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"S tem boste odblokirali dostop za vse aplikacije in storitve, ki imajo dovoljenje za uporabo fotoaparata."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"S tem boste odblokirali dostop za vse aplikacije in storitve, ki imajo dovoljenje za uporabo fotoaparata ali mikrofona."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Naprava"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Za preklop aplikacij povlecite navzgor"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Povlecite v desno za hiter preklop med aplikacijami"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Vklop/izklop pregleda"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Baterija napolnjena"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Polnjenje"</string>
diff --git a/packages/SystemUI/res/values-sl/strings_tv.xml b/packages/SystemUI/res/values-sl/strings_tv.xml
index 1f66138..2ef9705 100644
--- a/packages/SystemUI/res/values-sl/strings_tv.xml
+++ b/packages/SystemUI/res/values-sl/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Prek storitve <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Obvestila"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Ni obvestil"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 1600d03..eb49af0 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Kjo zhbllokon qasjen për të gjitha aplikacionet dhe shërbimet që lejohen të përdorin kamerën tënde."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Kjo zhbllokon qasjen për të gjitha aplikacionet dhe shërbimet që lejohen të përdorin kamerën ose mikrofonin tënd."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Pajisja"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Rrëshqit shpejt lart për të ndërruar aplikacionet"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Zvarrit djathtas për të ndërruar aplikacionet me shpejtësi"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Kalo te përmbledhja"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"I karikuar"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Po karikohet"</string>
diff --git a/packages/SystemUI/res/values-sq/strings_tv.xml b/packages/SystemUI/res/values-sq/strings_tv.xml
index fb74e38..ece5982 100644
--- a/packages/SystemUI/res/values-sq/strings_tv.xml
+++ b/packages/SystemUI/res/values-sq/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Nëpërmjet <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Njoftimet"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Asnjë njoftim"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 0670a9c..91ccdc2 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -435,8 +435,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Овим ће се одблокирати приступ за све апликације и услуге које имају дозволу за коришћење камере."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Овим ће се одблокирати приступ за све апликације и услуге које имају дозволу за коришћење камере или микрофона."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Уређај"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Превуците нагоре да бисте мењали апликације"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Превуците удесно да бисте брзо променили апликације"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Укључи/искључи преглед"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Напуњена је"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Пуни се"</string>
diff --git a/packages/SystemUI/res/values-sr/strings_tv.xml b/packages/SystemUI/res/values-sr/strings_tv.xml
index 59151da..38b106b 100644
--- a/packages/SystemUI/res/values-sr/strings_tv.xml
+++ b/packages/SystemUI/res/values-sr/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Преко: <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Обавештења"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Нема обавештења"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 4ba8999..a73dad2 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Detta återaktiverar åtkomsten för alla appar och tjänster som tillåts att använda kameran."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Detta återaktiverar åtkomsten för alla appar och tjänster som tillåts att använda kameran eller mikrofonen."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Enhet"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Byt appar genom att svepa uppåt"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Tryck och dra åt höger för att snabbt byta mellan appar"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Aktivera och inaktivera översikten"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Laddat"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Laddar"</string>
diff --git a/packages/SystemUI/res/values-sv/strings_tv.xml b/packages/SystemUI/res/values-sv/strings_tv.xml
index fd8fa4b..22f6baa 100644
--- a/packages/SystemUI/res/values-sv/strings_tv.xml
+++ b/packages/SystemUI/res/values-sv/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Aviseringar"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Inga aviseringar"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 0ba5d05..3eb941d 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Hatua hii huruhusu programu na huduma zote zenye idhini zitumie kamera yako."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Hatua hii huruhusu programu na huduma zote zenye idhini zitumie kamera au maikrofoni yako."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Kifaa"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Telezesha kidole juu ili ubadilishe programu"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Buruta kulia ili ubadilishe programu haraka"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Washa Muhtasari"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Betri imejaa"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Inachaji"</string>
diff --git a/packages/SystemUI/res/values-sw/strings_tv.xml b/packages/SystemUI/res/values-sw/strings_tv.xml
index 8f6880d..086a098 100644
--- a/packages/SystemUI/res/values-sw/strings_tv.xml
+++ b/packages/SystemUI/res/values-sw/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Kupitia <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Arifa"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Hakuna Arifa"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 4de2ab5..6a3cf34 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"உங்கள் கேமராவைப் பயன்படுத்த அனுமதிக்கப்பட்டுள்ள அனைத்து ஆப்ஸ் மற்றும் சேவைகளை அணுகுவதற்கான தடுப்பை இது நீக்கும்."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"உங்கள் கேமராவையோ மைக்ரோஃபோனையோ பயன்படுத்த அனுமதிக்கப்பட்டுள்ள அனைத்து ஆப்ஸ் மற்றும் சேவைகளை அணுகுவதற்கான தடுப்பை இது நீக்கும்."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"சாதனம்"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"ஆப்ஸிற்கு இடையே மாற்றுவதற்கு, மேல்நோக்கி ஸ்வைப் செய்க"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"ஆப்ஸை வேகமாக மாற்ற, வலப்புறம் இழுக்கவும்"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"மேலோட்டப் பார்வையை நிலைமாற்று"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"சார்ஜ் செய்யப்பட்டது"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"சார்ஜ் ஆகிறது"</string>
diff --git a/packages/SystemUI/res/values-ta/strings_tv.xml b/packages/SystemUI/res/values-ta/strings_tv.xml
index 9c62d8cf..398ffe9 100644
--- a/packages/SystemUI/res/values-ta/strings_tv.xml
+++ b/packages/SystemUI/res/values-ta/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> வழியாக"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"அறிவிப்புகள்"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"அறிவிப்புகள் எதுவுமில்லை"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 6cdaa22..7828d4f 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"మీ కెమెరాను ఉపయోగించడానికి అనుమతి పొందిన అన్ని యాప్లు, సర్వీస్లకు యాక్సెస్ను ఇది అన్బ్లాక్ చేస్తుంది."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"మీ కెమెరాను లేదా మైక్రోఫోన్ను ఉపయోగించడానికి అనుమతి పొందిన అన్ని యాప్లు, సర్వీస్లకు యాక్సెస్ను ఇది అన్బ్లాక్ చేస్తుంది."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"పరికరం"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"యాప్లను మార్చడం కోసం ఎగువకు స్వైప్ చేయండి"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"యాప్లను శీఘ్రంగా స్విచ్ చేయడానికి కుడి వైపుకు లాగండి"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"స్థూలదృష్టిని టోగుల్ చేయి"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"ఛార్జ్ చేయబడింది"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"ఛార్జ్ అవుతోంది"</string>
diff --git a/packages/SystemUI/res/values-te/strings_tv.xml b/packages/SystemUI/res/values-te/strings_tv.xml
index 1879edd..33c9ec9 100644
--- a/packages/SystemUI/res/values-te/strings_tv.xml
+++ b/packages/SystemUI/res/values-te/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> ద్వారా"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"నోటిఫికేషన్లు"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"నోటిఫికేషన్లు లేవు"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index f2fce1e..a530ef4 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"การดำเนินการนี้จะเลิกบล็อกสิทธิ์เข้าถึงของแอปและบริการทั้งหมดที่ได้รับอนุญาตให้ใช้กล้องของคุณ"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"การดำเนินการนี้จะเลิกบล็อกสิทธิ์เข้าถึงของแอปและบริการทั้งหมดที่ได้รับอนุญาตให้ใช้กล้องหรือไมโครโฟนของคุณ"</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"อุปกรณ์"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"เลื่อนขึ้นเพื่อสลับแอป"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"ลากไปทางขวาเพื่อสลับแอปอย่างรวดเร็ว"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"สลับภาพรวม"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"ชาร์จแล้ว"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"กำลังชาร์จ"</string>
diff --git a/packages/SystemUI/res/values-th/strings_tv.xml b/packages/SystemUI/res/values-th/strings_tv.xml
index 0724821..57cff1f 100644
--- a/packages/SystemUI/res/values-th/strings_tv.xml
+++ b/packages/SystemUI/res/values-th/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"ผ่าน <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"การแจ้งเตือน"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"ไม่มีการแจ้งเตือน"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 3ef994e..7bf902f 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Ina-unblock nito ang access para sa lahat ng app at serbisyong pinapayagang gumamit ng iyong camera."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Ina-unblock nito ang access para sa lahat ng app at serbisyong pinapayagang gumamit ng iyong camera o mikropono."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Device"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Mag-swipe pataas upang lumipat ng app"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"I-drag pakanan para mabilisang magpalipat-lipat ng app"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"I-toggle ang Overview"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Tapos nang mag-charge"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Nagcha-charge"</string>
diff --git a/packages/SystemUI/res/values-tl/strings_tv.xml b/packages/SystemUI/res/values-tl/strings_tv.xml
index 8dcc22f..8be6a86 100644
--- a/packages/SystemUI/res/values-tl/strings_tv.xml
+++ b/packages/SystemUI/res/values-tl/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Sa pamamagitan ng <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Mga Notification"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Walang Notification"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index d9afda18..2c51cc4 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Bu işlem, kameranızı kullanmasına izin verilen tüm uygulama ve hizmetlere erişimin engellemesini kaldırır."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Bu işlem, kamera veya mikrofonunuzu kullanmasına izin verilen tüm uygulama ve hizmetlere erişimin engellemesini kaldırır."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Cihaz"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Uygulamalar arasında geçiş yapmak için yukarı kaydırın"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Uygulamaları hızlıca değiştirmek için sağa kaydırın"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Genel bakışı aç/kapat"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Şarj oldu"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Şarj oluyor"</string>
diff --git a/packages/SystemUI/res/values-tr/strings_tv.xml b/packages/SystemUI/res/values-tr/strings_tv.xml
index 49e76af..28b2d77 100644
--- a/packages/SystemUI/res/values-tr/strings_tv.xml
+++ b/packages/SystemUI/res/values-tr/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> üzerinden"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Bildirimler"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Bildirim Yok"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 50a0f52..ae4772b 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -437,8 +437,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Усі додатки та сервіси, яким дозволено користуватися вашою камерою, отримають доступ."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Усі додатки та сервіси, яким дозволено користуватися вашою камерою чи мікрофоном, отримають доступ."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Пристрій"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Проводьте пальцем угору, щоб переходити між додатками"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Перетягуйте праворуч, щоб швидко переходити між додатками"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Увімкнути або вимкнути огляд"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Заряджено"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Заряджається"</string>
diff --git a/packages/SystemUI/res/values-uk/strings_tv.xml b/packages/SystemUI/res/values-uk/strings_tv.xml
index 170b068..c86cf31 100644
--- a/packages/SystemUI/res/values-uk/strings_tv.xml
+++ b/packages/SystemUI/res/values-uk/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Через <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Сповіщення"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Немає сповіщень"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 62b09f2..9cad711 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"اس سے آپ کا کیمرا استعمال کرنے کے لیے اجازت یافتہ سبھی ایپس اور سروسز کے لیے رسائی غیر مسدود ہو جاتی ہے۔"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"اس سے آپ کا کیمرا یا مائیکروفون استعمال کرنے کے لیے اجازت یافتہ سبھی ایپس اور سروسز کے لیے رسائی غیر مسدود ہو جاتی ہے۔"</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"آلہ"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"ایپس سوئچ کرنے کیلئے اوپر سوائپ کریں"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"تیزی سے ایپس کو سوئچ کرنے کے لیے دائیں طرف گھسیٹیں"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"مجموعی جائزہ ٹوگل کریں"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"چارج ہوگئی"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"چارج ہو رہی ہے"</string>
diff --git a/packages/SystemUI/res/values-ur/strings_tv.xml b/packages/SystemUI/res/values-ur/strings_tv.xml
index fbaa3f6..5810482 100644
--- a/packages/SystemUI/res/values-ur/strings_tv.xml
+++ b/packages/SystemUI/res/values-ur/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"بذریعہ <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"اطلاعات"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"کوئی اطلاع نہیں ہے"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index fae90c8..874af0f 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Kamerangizdan foydalanishga ruxsat berilgan barcha ilovalar va xizmatlar uchun ruxsatni blokdan chiqaradi."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Kamera va mikrofoningizdan foydalanishga ruxsat berilgan barcha ilovalar va xizmatlar uchun ruxsatni blokdan chiqaradi."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Qurilma"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Ilovalarni almashtirish uchun ekranni tepaga suring"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Ilovalarni tezkor almashtirish uchun o‘ngga torting"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Umumiy nazar rejimini almashtirish"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Quvvat oldi"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Quvvat olmoqda"</string>
diff --git a/packages/SystemUI/res/values-uz/strings_tv.xml b/packages/SystemUI/res/values-uz/strings_tv.xml
index f4b4b08..afa82bc 100644
--- a/packages/SystemUI/res/values-uz/strings_tv.xml
+++ b/packages/SystemUI/res/values-uz/strings_tv.xml
@@ -26,4 +26,10 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> orqali"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Bildirishnomalar"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Bildirishnomalar yoʻq"</string>
+ <string name="mic_recording_announcement" msgid="7587123608060316575">"Mikrofon yozib olmoqda"</string>
+ <string name="camera_recording_announcement" msgid="7240177719403759112">"Kamera yozib olmoqda"</string>
+ <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"Kamera va mikrofon yozib olmoqda"</string>
+ <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"Mikrofon yozib olishni toʻxtatdi"</string>
+ <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"Kamera yozib olishni toʻxtatdi"</string>
+ <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"Kamera va mikrofon yozib olishni toʻxtatdi"</string>
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 1ef805f..3506385f 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Thao tác này sẽ bỏ chặn quyền truy cập cho mọi ứng dụng và dịch vụ được phép sử dụng máy ảnh của bạn."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Thao tác này sẽ bỏ chặn quyền truy cập cho mọi ứng dụng và dịch vụ được phép sử dụng máy ảnh hoặc micrô của bạn."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Thiết bị"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Vuốt lên để chuyển đổi ứng dụng"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Kéo sang phải để chuyển đổi nhanh giữa các ứng dụng"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Bật/tắt chế độ xem Tổng quan"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Đã sạc đầy"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Đang sạc"</string>
diff --git a/packages/SystemUI/res/values-vi/strings_tv.xml b/packages/SystemUI/res/values-vi/strings_tv.xml
index 3dfc8c1..21f5471 100644
--- a/packages/SystemUI/res/values-vi/strings_tv.xml
+++ b/packages/SystemUI/res/values-vi/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Thông qua <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Thông báo"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Không có thông báo"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index a8b8285..62a4133 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"这将会为所有获准使用您摄像头的应用和服务启用这项权限。"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"这将会为所有获准使用您的摄像头或麦克风的应用和服务启用这项权限。"</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"设备"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"向上滑动可切换应用"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"向右拖动可快速切换应用"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"切换概览"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"已充满"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"正在充电"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings_tv.xml b/packages/SystemUI/res/values-zh-rCN/strings_tv.xml
index 1e599ca..ca814a3 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings_tv.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"通过“<xliff:g id="VPN_APP">%1$s</xliff:g>”"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"通知"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"没有通知"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 9e498f6..42badd4 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"解除封鎖後,凡有存取權的應用程式和服務都可使用您的相機。"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"解除封鎖後,凡有存取權的應用程式和服務都可使用您的相機或麥克風。"</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"裝置"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"向上滑動即可切換應用程式"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"向右拖曳即可快速切換應用程式"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"切換概覽"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"已完成充電"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"充電中"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings_tv.xml b/packages/SystemUI/res/values-zh-rHK/strings_tv.xml
index 92b1762..f992b62 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings_tv.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"透過 <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"通知"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"沒有通知"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 1b0fa10..ea5aac6 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"這麼做可允許所有應用程式和服務使用相機。"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"這麼做可允許所有應用程式和服務使用相機或麥克風。"</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"裝置"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"向上滑動即可切換應用程式"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"向右拖曳即可快速切換應用程式"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"切換總覽"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"已充飽"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"充電中"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings_tv.xml b/packages/SystemUI/res/values-zh-rTW/strings_tv.xml
index db0781a..94135d2 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings_tv.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"透過「<xliff:g id="VPN_APP">%1$s</xliff:g>」"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"通知"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"沒有通知"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index a14229a..de986d2 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -433,8 +433,6 @@
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Lokhu kuvulela ukufinyelela kwawo wonke ama-app namasevisi avunyelwe ukusebenzisa ikhamera yakho."</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Lokhu kuvulela ukufinyelela kwawo wonke ama-app namasevisi avunyelwe ukusebenzisa ikhamera yakho noma imakrofoni."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Idivayisi"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Swayiphela phezulu ukuze ushintshe izinhlelo zokusebenza"</string>
- <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Hudula ngqo ukuze ushintshe ngokushesha izinhlelo zokusebenza"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Guqula ukubuka konke"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Kushajiwe"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Iyashaja"</string>
diff --git a/packages/SystemUI/res/values-zu/strings_tv.xml b/packages/SystemUI/res/values-zu/strings_tv.xml
index a9b7597..79a6575 100644
--- a/packages/SystemUI/res/values-zu/strings_tv.xml
+++ b/packages/SystemUI/res/values-zu/strings_tv.xml
@@ -26,4 +26,16 @@
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Nge-<xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Izaziso"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Azikho Izaziso"</string>
+ <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
+ <skip />
+ <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
+ <skip />
+ <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
+ <skip />
+ <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
+ <skip />
+ <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
+ <skip />
+ <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index bf29cf4..30537df 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -666,4 +666,10 @@
1 - Override the setting to always bypass keyguard
2 - Override the setting to never bypass keyguard -->
<integer name="config_face_unlock_bypass_override">0</integer>
+
+ <!-- Whether the communal service should be enabled -->
+ <bool name="config_communalServiceEnabled">false</bool>
+
+ <!-- Component name of communal source service -->
+ <string name="config_communalSourceComponent" translatable="false">@null</string>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 22035f4..798242a 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -931,6 +931,7 @@
<dimen name="keyguard_lock_padding">20dp</dimen>
<dimen name="keyguard_indication_margin_bottom">32dp</dimen>
+ <dimen name="lock_icon_margin_bottom">98dp</dimen>
<!-- The text size for battery level -->
<dimen name="battery_level_text_size">12sp</dimen>
@@ -1275,6 +1276,8 @@
<!-- Three privacy items. This value must not be exceeded -->
<dimen name="ongoing_appops_chip_max_width">76dp</dimen>
<dimen name="ongoing_appops_dot_diameter">6dp</dimen>
+ <!-- Total minimum padding to enforce to ensure that the dot can always show -->
+ <dimen name="ongoing_appops_dot_min_padding">20dp</dimen>
<dimen name="ongoing_appops_dialog_side_margins">@dimen/notification_shade_content_margin_horizontal</dimen>
diff --git a/packages/SystemUI/res/values/flags.xml b/packages/SystemUI/res/values/flags.xml
index efa8754..c2b87a5 100644
--- a/packages/SystemUI/res/values/flags.xml
+++ b/packages/SystemUI/res/values/flags.xml
@@ -24,9 +24,6 @@
<bool name="flag_monet">false</bool>
- <!-- b/171917882 -->
- <bool name="flag_notification_twocolumn">false</bool>
-
<!-- AOD/Lockscreen alternate layout -->
<bool name="flag_keyguard_layout">true</bool>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index ec951ff..a8812bf 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1064,6 +1064,9 @@
<!-- Message shown when lock screen is tapped or face authentication fails. [CHAR LIMIT=60] -->
<string name="keyguard_unlock">Swipe up to open</string>
+ <!-- Message shown when lock screen is tapped or face authentication fails. Provides extra instructions for how the user can enter their device (unlock or proceed to home) [CHAR LIMIT=60] -->
+ <string name="keyguard_unlock_press">Press to open</string>
+
<!-- Message shown when face authentication fails and the pin pad is visible. [CHAR LIMIT=60] -->
<string name="keyguard_retry">Swipe up to try again</string>
diff --git a/packages/SystemUI/shared/Android.bp b/packages/SystemUI/shared/Android.bp
index b2ae2a0..3a23094 100644
--- a/packages/SystemUI/shared/Android.bp
+++ b/packages/SystemUI/shared/Android.bp
@@ -47,6 +47,7 @@
static_libs: [
"PluginCoreLib",
+ "androidx.dynamicanimation_dynamicanimation",
],
java_version: "1.8",
min_sdk_version: "26",
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/communal/ICommunalHost.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/communal/ICommunalHost.aidl
new file mode 100644
index 0000000..b76be4f
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/communal/ICommunalHost.aidl
@@ -0,0 +1,33 @@
+/*
+ * 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.shared.communal;
+
+import com.android.systemui.shared.communal.ICommunalSource;
+
+/**
+* An interface, implemented by SystemUI, for hosting a shared, communal surface on the lock
+* screen. Clients declare themselves sources (as defined by ICommunalSource). ICommunalHost is
+* meant only for the input of said sources. The lifetime scope and interactions that follow after
+* are bound to source.
+*/
+oneway interface ICommunalHost {
+ /**
+ * Invoked to specify the CommunalSource that should be consulted for communal surfaces to be
+ * displayed.
+ */
+ void setSource(in ICommunalSource source) = 1;
+}
\ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/communal/ICommunalSource.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/communal/ICommunalSource.aidl
new file mode 100644
index 0000000..7ef403b
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/communal/ICommunalSource.aidl
@@ -0,0 +1,34 @@
+/*
+ * 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.shared.communal;
+
+import com.android.systemui.shared.communal.ICommunalSurfaceCallback;
+
+/**
+ * An interface, implemented by clients of CommunalHost, to provide communal surfaces for SystemUI.
+ * The associated binder proxy will be retained by SystemUI and called on-demand when a communal
+ * surface is needed (either new instantiation or update).
+ */
+oneway interface ICommunalSource {
+ /**
+ * Called by the CommunalHost when a new communal surface is needed. The provided arguments
+ * match the arguments necessary to construct a SurfaceControlViewHost for producing a
+ * SurfacePackage to return.
+ */
+ void getCommunalSurface(in IBinder hostToken, in int width, in int height, in int displayId,
+ in ICommunalSurfaceCallback callback) = 1;
+}
\ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/communal/ICommunalSurfaceCallback.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/communal/ICommunalSurfaceCallback.aidl
new file mode 100644
index 0000000..58acce0
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/communal/ICommunalSurfaceCallback.aidl
@@ -0,0 +1,30 @@
+/*
+ * 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.shared.communal;
+
+import android.view.SurfaceControlViewHost;
+
+/**
+* An interface for receiving the result of a surface request. ICommunalSurfaceCallback is
+* implemented by the CommunalHost (SystemUI) to process the results of a new communal surface.
+*/
+interface ICommunalSurfaceCallback {
+ /**
+ * Invoked when the CommunalSurface has generated the SurfacePackage to be displayed.
+ */
+ void onSurface(in SurfaceControlViewHost.SurfacePackage surfacePackage) = 1;
+}
\ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginEnabler.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginEnabler.java
index 01b012d..1c5da82 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginEnabler.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginEnabler.java
@@ -24,9 +24,9 @@
int ENABLED = 0;
int DISABLED_MANUALLY = 1;
- int DISABLED_INVALID_VERSION = 1;
- int DISABLED_FROM_EXPLICIT_CRASH = 2;
- int DISABLED_FROM_SYSTEM_CRASH = 3;
+ int DISABLED_INVALID_VERSION = 2;
+ int DISABLED_FROM_EXPLICIT_CRASH = 3;
+ int DISABLED_FROM_SYSTEM_CRASH = 4;
@IntDef({ENABLED, DISABLED_MANUALLY, DISABLED_INVALID_VERSION, DISABLED_FROM_EXPLICIT_CRASH,
DISABLED_FROM_SYSTEM_CRASH})
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
index f5ed9da..2b4cdd6 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
@@ -197,10 +197,12 @@
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ filter.addDataScheme("package");
+ mContext.registerReceiver(this, filter);
filter.addAction(PLUGIN_CHANGED);
filter.addAction(DISABLE_PLUGIN);
filter.addDataScheme("package");
- mContext.registerReceiver(this, filter);
+ mContext.registerReceiver(this, filter, PluginInstanceManager.PLUGIN_PERMISSION, null);
filter = new IntentFilter(Intent.ACTION_USER_UNLOCKED);
mContext.registerReceiver(this, filter);
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
index 3eea99a..7f2d252 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
@@ -29,6 +29,7 @@
import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
+import android.content.ComponentName;
import android.graphics.Rect;
import android.os.IBinder;
import android.os.Parcelable;
@@ -166,7 +167,7 @@
}
/** Adds a filter check that restricts this remote transition to home open transitions. */
- public void addHomeOpenCheck() {
+ public void addHomeOpenCheck(ComponentName homeActivity) {
if (mFilter == null) {
mFilter = new TransitionFilter();
}
@@ -174,6 +175,7 @@
new TransitionFilter.Requirement[]{new TransitionFilter.Requirement(),
new TransitionFilter.Requirement()};
mFilter.mRequirements[0].mActivityType = ACTIVITY_TYPE_HOME;
+ mFilter.mRequirements[0].mTopActivity = homeActivity;
mFilter.mRequirements[0].mModes = new int[]{TRANSIT_OPEN, TRANSIT_TO_FRONT};
mFilter.mRequirements[0].mOrder = CONTAINER_ORDER_TOP;
mFilter.mRequirements[1].mActivityType = ACTIVITY_TYPE_STANDARD;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackController.java b/packages/SystemUI/shared/src/com/android/systemui/statusbar/policy/CallbackController.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackController.java
rename to packages/SystemUI/shared/src/com/android/systemui/statusbar/policy/CallbackController.java
diff --git a/packages/SystemUI/shared/src/com/android/unfold/UnfoldTransitionFactory.kt b/packages/SystemUI/shared/src/com/android/unfold/UnfoldTransitionFactory.kt
new file mode 100644
index 0000000..7594f50
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/unfold/UnfoldTransitionFactory.kt
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+@file:JvmName("UnfoldTransitionFactory")
+
+package com.android.unfold
+
+import android.content.Context
+import android.hardware.SensorManager
+import android.hardware.devicestate.DeviceStateManager
+import android.os.Handler
+import com.android.unfold.updates.screen.ScreenStatusProvider
+import com.android.unfold.config.ANIMATION_MODE_HINGE_ANGLE
+import com.android.unfold.config.ResourceUnfoldTransitionConfig
+import com.android.unfold.config.UnfoldTransitionConfig
+import com.android.unfold.progress.FixedTimingTransitionProgressProvider
+import com.android.unfold.progress.PhysicsBasedUnfoldTransitionProgressProvider
+import com.android.unfold.updates.DeviceFoldStateProvider
+import com.android.unfold.updates.hinge.EmptyHingeAngleProvider
+import com.android.unfold.updates.hinge.RotationSensorHingeAngleProvider
+import java.lang.IllegalStateException
+import java.util.concurrent.Executor
+
+fun createUnfoldTransitionProgressProvider(
+ context: Context,
+ config: UnfoldTransitionConfig,
+ screenStatusProvider: ScreenStatusProvider,
+ deviceStateManager: DeviceStateManager,
+ sensorManager: SensorManager,
+ mainHandler: Handler,
+ mainExecutor: Executor
+): UnfoldTransitionProgressProvider {
+
+ if (!config.isEnabled) {
+ throw IllegalStateException("Trying to create " +
+ "UnfoldTransitionProgressProvider when the transition is disabled")
+ }
+
+ val hingeAngleProvider =
+ if (config.mode == ANIMATION_MODE_HINGE_ANGLE) {
+ RotationSensorHingeAngleProvider(sensorManager)
+ } else {
+ EmptyHingeAngleProvider()
+ }
+
+ val foldStateProvider = DeviceFoldStateProvider(
+ context,
+ hingeAngleProvider,
+ screenStatusProvider,
+ deviceStateManager,
+ mainExecutor
+ )
+
+ return if (config.mode == ANIMATION_MODE_HINGE_ANGLE) {
+ PhysicsBasedUnfoldTransitionProgressProvider(
+ mainHandler,
+ foldStateProvider
+ )
+ } else {
+ FixedTimingTransitionProgressProvider(foldStateProvider)
+ }
+}
+
+fun createConfig(context: Context): UnfoldTransitionConfig =
+ ResourceUnfoldTransitionConfig(context)
diff --git a/packages/SystemUI/shared/src/com/android/unfold/UnfoldTransitionProgressProvider.kt b/packages/SystemUI/shared/src/com/android/unfold/UnfoldTransitionProgressProvider.kt
new file mode 100644
index 0000000..2ddb49c
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/unfold/UnfoldTransitionProgressProvider.kt
@@ -0,0 +1,38 @@
+/*
+ * 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.unfold
+
+import android.annotation.FloatRange
+import com.android.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
+import com.android.systemui.statusbar.policy.CallbackController
+
+/**
+ * Interface that allows to receive unfold transition progress updates.
+ * It can be used to update view properties based on the current animation progress.
+ * onTransitionProgress callback could be called on each frame.
+ *
+ * Use [createUnfoldTransitionProgressProvider] to create instances of this interface
+ */
+interface UnfoldTransitionProgressProvider : CallbackController<TransitionProgressListener> {
+
+ fun destroy()
+
+ interface TransitionProgressListener {
+ fun onTransitionStarted()
+ fun onTransitionFinished()
+ fun onTransitionProgress(@FloatRange(from = 0.0, to = 1.0) progress: Float)
+ }
+}
diff --git a/packages/SystemUI/shared/src/com/android/unfold/config/ResourceUnfoldTransitionConfig.kt b/packages/SystemUI/shared/src/com/android/unfold/config/ResourceUnfoldTransitionConfig.kt
new file mode 100644
index 0000000..bde87a5
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/unfold/config/ResourceUnfoldTransitionConfig.kt
@@ -0,0 +1,41 @@
+/*
+ * 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.unfold.config
+
+import android.content.Context
+import android.os.SystemProperties
+
+internal class ResourceUnfoldTransitionConfig(
+ private val context: Context
+) : UnfoldTransitionConfig {
+
+ override val isEnabled: Boolean
+ get() = readIsEnabled() && mode != ANIMATION_MODE_DISABLED
+
+ @AnimationMode
+ override val mode: Int
+ get() = SystemProperties.getInt(UNFOLD_TRANSITION_MODE_PROPERTY_NAME,
+ ANIMATION_MODE_FIXED_TIMING)
+
+ private fun readIsEnabled(): Boolean = context.resources
+ .getBoolean(com.android.internal.R.bool.config_unfoldTransitionEnabled)
+}
+
+/**
+ * Temporary persistent property to control unfold transition mode
+ * See [com.android.unfold.config.AnimationMode]
+ */
+private const val UNFOLD_TRANSITION_MODE_PROPERTY_NAME = "persist.unfold.transition_mode"
diff --git a/packages/SystemUI/shared/src/com/android/unfold/config/UnfoldTransitionConfig.kt b/packages/SystemUI/shared/src/com/android/unfold/config/UnfoldTransitionConfig.kt
new file mode 100644
index 0000000..f000c69
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/unfold/config/UnfoldTransitionConfig.kt
@@ -0,0 +1,38 @@
+/*
+ * 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.unfold.config
+
+import android.annotation.IntDef
+
+interface UnfoldTransitionConfig {
+ val isEnabled: Boolean
+
+ @AnimationMode
+ val mode: Int
+}
+
+@IntDef(prefix = ["ANIMATION_MODE_"], value = [
+ ANIMATION_MODE_DISABLED,
+ ANIMATION_MODE_FIXED_TIMING,
+ ANIMATION_MODE_HINGE_ANGLE
+])
+
+@Retention(AnnotationRetention.SOURCE)
+annotation class AnimationMode
+
+const val ANIMATION_MODE_DISABLED = 0
+const val ANIMATION_MODE_FIXED_TIMING = 1
+const val ANIMATION_MODE_HINGE_ANGLE = 2
diff --git a/packages/SystemUI/shared/src/com/android/unfold/progress/FixedTimingTransitionProgressProvider.kt b/packages/SystemUI/shared/src/com/android/unfold/progress/FixedTimingTransitionProgressProvider.kt
new file mode 100644
index 0000000..acfe073
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/unfold/progress/FixedTimingTransitionProgressProvider.kt
@@ -0,0 +1,117 @@
+/*
+ * 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.unfold.progress
+
+import android.animation.Animator
+import android.animation.ObjectAnimator
+import android.util.FloatProperty
+import com.android.unfold.UnfoldTransitionProgressProvider
+import com.android.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
+import com.android.unfold.updates.FOLD_UPDATE_FINISH_CLOSED
+import com.android.unfold.updates.FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE
+import com.android.unfold.updates.FoldStateProvider
+import com.android.unfold.updates.FoldStateProvider.FoldUpdate
+
+/**
+ * Emits animation progress with fixed timing after unfolding
+ */
+internal class FixedTimingTransitionProgressProvider(
+ private val foldStateProvider: FoldStateProvider
+) : UnfoldTransitionProgressProvider, FoldStateProvider.FoldUpdatesListener {
+
+ private val animatorListener = AnimatorListener()
+ private val animator =
+ ObjectAnimator.ofFloat(this, AnimationProgressProperty, 0f, 1f)
+ .apply {
+ duration = TRANSITION_TIME_MILLIS
+ addListener(animatorListener)
+ }
+
+
+ private var transitionProgress: Float = 0.0f
+ set(value) {
+ listeners.forEach { it.onTransitionProgress(value) }
+ field = value
+ }
+
+ private val listeners: MutableList<TransitionProgressListener> = mutableListOf()
+
+ init {
+ foldStateProvider.addCallback(this)
+ foldStateProvider.start()
+ }
+
+ override fun destroy() {
+ animator.cancel()
+ foldStateProvider.removeCallback(this)
+ foldStateProvider.stop()
+ }
+
+ override fun onFoldUpdate(@FoldUpdate update: Int) {
+ when (update) {
+ FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE ->
+ animator.start()
+ FOLD_UPDATE_FINISH_CLOSED ->
+ animator.cancel()
+ }
+ }
+
+ override fun addCallback(listener: TransitionProgressListener) {
+ listeners.add(listener)
+ }
+
+ override fun removeCallback(listener: TransitionProgressListener) {
+ listeners.remove(listener)
+ }
+
+ override fun onHingeAngleUpdate(angle: Float) {
+ }
+
+ private object AnimationProgressProperty :
+ FloatProperty<FixedTimingTransitionProgressProvider>("animation_progress") {
+
+ override fun setValue(
+ provider: FixedTimingTransitionProgressProvider,
+ value: Float
+ ) {
+ provider.transitionProgress = value
+ }
+
+ override fun get(provider: FixedTimingTransitionProgressProvider): Float =
+ provider.transitionProgress
+ }
+
+ private inner class AnimatorListener : Animator.AnimatorListener {
+
+ override fun onAnimationStart(animator: Animator) {
+ listeners.forEach { it.onTransitionStarted() }
+ }
+
+ override fun onAnimationEnd(animator: Animator) {
+ listeners.forEach { it.onTransitionFinished() }
+ }
+
+ override fun onAnimationRepeat(animator: Animator) {
+ }
+
+ override fun onAnimationCancel(animator: Animator) {
+ }
+ }
+
+ private companion object {
+ private const val TRANSITION_TIME_MILLIS = 400L
+ }
+}
diff --git a/packages/SystemUI/shared/src/com/android/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt b/packages/SystemUI/shared/src/com/android/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
new file mode 100644
index 0000000..d9d037f
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
@@ -0,0 +1,184 @@
+/*
+ * 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.unfold.progress
+
+import android.os.Handler
+import androidx.dynamicanimation.animation.DynamicAnimation
+import androidx.dynamicanimation.animation.FloatPropertyCompat
+import androidx.dynamicanimation.animation.SpringAnimation
+import androidx.dynamicanimation.animation.SpringForce
+import com.android.unfold.UnfoldTransitionProgressProvider
+import com.android.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
+import com.android.unfold.updates.FOLD_UPDATE_FINISH_CLOSED
+import com.android.unfold.updates.FOLD_UPDATE_FINISH_FULL_OPEN
+import com.android.unfold.updates.FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE
+import com.android.unfold.updates.FoldStateProvider
+import com.android.unfold.updates.FoldStateProvider.FoldUpdate
+import com.android.unfold.updates.FoldStateProvider.FoldUpdatesListener
+
+/**
+ * Maps fold updates to unfold transition progress using DynamicAnimation.
+ *
+ * TODO(b/193793338) Current limitations:
+ * - doesn't handle folding transition
+ * - doesn't handle postures
+ */
+internal class PhysicsBasedUnfoldTransitionProgressProvider(
+ private val handler: Handler,
+ private val foldStateProvider: FoldStateProvider
+) :
+ UnfoldTransitionProgressProvider,
+ FoldUpdatesListener,
+ DynamicAnimation.OnAnimationEndListener {
+
+ private val springAnimation = SpringAnimation(this, AnimationProgressProperty)
+ .apply {
+ addEndListener(this@PhysicsBasedUnfoldTransitionProgressProvider)
+ }
+
+ private val timeoutRunnable = TimeoutRunnable()
+
+ private var isTransitionRunning = false
+ private var isAnimatedCancelRunning = false
+
+ private var transitionProgress: Float = 0.0f
+ set(value) {
+ if (isTransitionRunning) {
+ listeners.forEach { it.onTransitionProgress(value) }
+ }
+ field = value
+ }
+
+ private val listeners: MutableList<TransitionProgressListener> = mutableListOf()
+
+ init {
+ foldStateProvider.addCallback(this)
+ foldStateProvider.start()
+ }
+
+ override fun destroy() {
+ foldStateProvider.stop()
+ }
+
+ override fun onHingeAngleUpdate(angle: Float) {
+ if (!isTransitionRunning || isAnimatedCancelRunning) return
+ springAnimation.animateToFinalPosition(angle / 180f)
+ }
+
+ override fun onFoldUpdate(@FoldUpdate update: Int) {
+ when (update) {
+ FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE -> {
+ onStartTransition()
+ startTransition(startValue = 0f)
+ }
+ FOLD_UPDATE_FINISH_FULL_OPEN -> {
+ cancelTransition(endValue = 1f, animate = true)
+ }
+ FOLD_UPDATE_FINISH_CLOSED -> {
+ cancelTransition(endValue = 0f, animate = false)
+ }
+ }
+ }
+
+ private fun cancelTransition(endValue: Float, animate: Boolean) {
+ handler.removeCallbacks(timeoutRunnable)
+
+ if (animate) {
+ isAnimatedCancelRunning = true
+ springAnimation.animateToFinalPosition(endValue)
+ } else {
+ transitionProgress = endValue
+ isAnimatedCancelRunning = false
+ isTransitionRunning = false
+ springAnimation.cancel()
+
+ listeners.forEach {
+ it.onTransitionFinished()
+ }
+ }
+ }
+
+ override fun onAnimationEnd(
+ animation: DynamicAnimation<out DynamicAnimation<*>>,
+ canceled: Boolean,
+ value: Float,
+ velocity: Float
+ ) {
+ if (isAnimatedCancelRunning) {
+ cancelTransition(value, animate = false)
+ }
+ }
+
+ private fun onStartTransition() {
+ listeners.forEach {
+ it.onTransitionStarted()
+ }
+ isTransitionRunning = true
+ }
+
+ private fun startTransition(startValue: Float) {
+ if (!isTransitionRunning) onStartTransition()
+
+ springAnimation.apply {
+ spring = SpringForce().apply {
+ finalPosition = startValue
+ dampingRatio = SpringForce.DAMPING_RATIO_NO_BOUNCY
+ stiffness = SPRING_STIFFNESS
+ }
+ minimumVisibleChange = MINIMAL_VISIBLE_CHANGE
+ setStartValue(startValue)
+ setMinValue(0f)
+ setMaxValue(1f)
+ }
+
+ springAnimation.start()
+
+ handler.postDelayed(timeoutRunnable, TRANSITION_TIMEOUT_MILLIS)
+ }
+
+ override fun addCallback(listener: TransitionProgressListener) {
+ listeners.add(listener)
+ }
+
+ override fun removeCallback(listener: TransitionProgressListener) {
+ listeners.remove(listener)
+ }
+
+ private inner class TimeoutRunnable : Runnable {
+
+ override fun run() {
+ cancelTransition(endValue = 1f, animate = true)
+ }
+ }
+
+ private object AnimationProgressProperty :
+ FloatPropertyCompat<PhysicsBasedUnfoldTransitionProgressProvider>("animation_progress") {
+
+ override fun setValue(
+ provider: PhysicsBasedUnfoldTransitionProgressProvider,
+ value: Float
+ ) {
+ provider.transitionProgress = value
+ }
+
+ override fun getValue(provider: PhysicsBasedUnfoldTransitionProgressProvider): Float =
+ provider.transitionProgress
+ }
+}
+
+private const val TRANSITION_TIMEOUT_MILLIS = 2000L
+private const val SPRING_STIFFNESS = 200.0f
+private const val MINIMAL_VISIBLE_CHANGE = 0.001f
diff --git a/packages/SystemUI/shared/src/com/android/unfold/updates/DeviceFoldStateProvider.kt b/packages/SystemUI/shared/src/com/android/unfold/updates/DeviceFoldStateProvider.kt
new file mode 100644
index 0000000..3a21b80
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/unfold/updates/DeviceFoldStateProvider.kt
@@ -0,0 +1,124 @@
+/*
+ * 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.unfold.updates
+
+import android.content.Context
+import android.hardware.devicestate.DeviceStateManager
+import androidx.core.util.Consumer
+import com.android.unfold.updates.screen.ScreenStatusProvider
+import com.android.unfold.updates.FoldStateProvider.FoldUpdate
+import com.android.unfold.updates.FoldStateProvider.FoldUpdatesListener
+import com.android.unfold.updates.hinge.FULLY_OPEN_DEGREES
+import com.android.unfold.updates.hinge.HingeAngleProvider
+import java.util.concurrent.Executor
+
+internal class DeviceFoldStateProvider(
+ context: Context,
+ private val hingeAngleProvider: HingeAngleProvider,
+ private val screenStatusProvider: ScreenStatusProvider,
+ private val deviceStateManager: DeviceStateManager,
+ private val mainExecutor: Executor
+) : FoldStateProvider {
+
+ private val outputListeners: MutableList<FoldUpdatesListener> = mutableListOf()
+
+ @FoldUpdate
+ private var lastFoldUpdate: Int? = null
+
+ private val hingeAngleListener = HingeAngleListener()
+ private val screenListener = ScreenStatusListener()
+ private val foldStateListener = FoldStateListener(context)
+
+ private var isFolded = false
+
+ override fun start() {
+ deviceStateManager.registerCallback(
+ mainExecutor,
+ foldStateListener
+ )
+ screenStatusProvider.addCallback(screenListener)
+ hingeAngleProvider.addCallback(hingeAngleListener)
+ }
+
+ override fun stop() {
+ screenStatusProvider.removeCallback(screenListener)
+ deviceStateManager.unregisterCallback(foldStateListener)
+ hingeAngleProvider.removeCallback(hingeAngleListener)
+ hingeAngleProvider.stop()
+ }
+
+ override fun addCallback(listener: FoldUpdatesListener) {
+ outputListeners.add(listener)
+ }
+
+ override fun removeCallback(listener: FoldUpdatesListener) {
+ outputListeners.remove(listener)
+ }
+
+ private fun onHingeAngle(angle: Float) {
+ when (lastFoldUpdate) {
+ FOLD_UPDATE_FINISH_FULL_OPEN -> {
+ if (FULLY_OPEN_DEGREES - angle > MOVEMENT_THRESHOLD_DEGREES) {
+ lastFoldUpdate = FOLD_UPDATE_START_CLOSING
+ outputListeners.forEach { it.onFoldUpdate(FOLD_UPDATE_START_CLOSING) }
+ }
+ }
+ FOLD_UPDATE_START_OPENING, FOLD_UPDATE_START_CLOSING -> {
+ if (FULLY_OPEN_DEGREES - angle < FULLY_OPEN_THRESHOLD_DEGREES) {
+ lastFoldUpdate = FOLD_UPDATE_FINISH_FULL_OPEN
+ outputListeners.forEach { it.onFoldUpdate(FOLD_UPDATE_FINISH_FULL_OPEN) }
+ }
+ }
+ }
+
+ outputListeners.forEach { it.onHingeAngleUpdate(angle) }
+ }
+
+ private inner class FoldStateListener(context: Context) :
+ DeviceStateManager.FoldStateListener(context, { folded: Boolean ->
+ isFolded = folded
+
+ if (folded) {
+ lastFoldUpdate = FOLD_UPDATE_FINISH_CLOSED
+ outputListeners.forEach { it.onFoldUpdate(FOLD_UPDATE_FINISH_CLOSED) }
+ hingeAngleProvider.stop()
+ } else {
+ lastFoldUpdate = FOLD_UPDATE_START_OPENING
+ outputListeners.forEach { it.onFoldUpdate(FOLD_UPDATE_START_OPENING) }
+ hingeAngleProvider.start()
+ }
+ })
+
+ private inner class ScreenStatusListener :
+ ScreenStatusProvider.ScreenListener {
+
+ override fun onScreenTurnedOn() {
+ if (!isFolded) {
+ outputListeners.forEach { it.onFoldUpdate(FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE) }
+ }
+ }
+ }
+
+ private inner class HingeAngleListener : Consumer<Float> {
+
+ override fun accept(angle: Float) {
+ onHingeAngle(angle)
+ }
+ }
+}
+
+private const val MOVEMENT_THRESHOLD_DEGREES = 10f
+private const val FULLY_OPEN_THRESHOLD_DEGREES = 10f
\ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/unfold/updates/FoldStateProvider.kt b/packages/SystemUI/shared/src/com/android/unfold/updates/FoldStateProvider.kt
new file mode 100644
index 0000000..2c3a6ec
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/unfold/updates/FoldStateProvider.kt
@@ -0,0 +1,55 @@
+/*
+ * 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.unfold.updates
+
+import android.annotation.FloatRange
+import android.annotation.IntDef
+import com.android.unfold.updates.FoldStateProvider.FoldUpdatesListener
+import com.android.systemui.statusbar.policy.CallbackController
+
+/**
+ * Allows to subscribe to main events related to fold/unfold process such as hinge angle update,
+ * start folding/unfolding, screen availability
+ */
+internal interface FoldStateProvider : CallbackController<FoldUpdatesListener> {
+ fun start()
+ fun stop()
+
+ interface FoldUpdatesListener {
+ fun onHingeAngleUpdate(@FloatRange(from = 0.0, to = 180.0) angle: Float)
+ fun onFoldUpdate(@FoldUpdate update: Int)
+ }
+
+ @IntDef(prefix = ["FOLD_UPDATE_"], value = [
+ FOLD_UPDATE_START_OPENING,
+ FOLD_UPDATE_HALF_OPEN,
+ FOLD_UPDATE_START_CLOSING,
+ FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE,
+ FOLD_UPDATE_FINISH_HALF_OPEN,
+ FOLD_UPDATE_FINISH_FULL_OPEN,
+ FOLD_UPDATE_FINISH_CLOSED
+ ])
+ @Retention(AnnotationRetention.SOURCE)
+ annotation class FoldUpdate
+}
+
+const val FOLD_UPDATE_START_OPENING = 0
+const val FOLD_UPDATE_HALF_OPEN = 1
+const val FOLD_UPDATE_START_CLOSING = 2
+const val FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE = 3
+const val FOLD_UPDATE_FINISH_HALF_OPEN = 4
+const val FOLD_UPDATE_FINISH_FULL_OPEN = 5
+const val FOLD_UPDATE_FINISH_CLOSED = 6
diff --git a/packages/SystemUI/shared/src/com/android/unfold/updates/hinge/EmptyHingeAngleProvider.kt b/packages/SystemUI/shared/src/com/android/unfold/updates/hinge/EmptyHingeAngleProvider.kt
new file mode 100644
index 0000000..905b086
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/unfold/updates/hinge/EmptyHingeAngleProvider.kt
@@ -0,0 +1,17 @@
+package com.android.unfold.updates.hinge
+
+import androidx.core.util.Consumer
+
+internal class EmptyHingeAngleProvider : HingeAngleProvider {
+ override fun start() {
+ }
+
+ override fun stop() {
+ }
+
+ override fun removeCallback(listener: Consumer<Float>) {
+ }
+
+ override fun addCallback(listener: Consumer<Float>) {
+ }
+}
diff --git a/packages/SystemUI/shared/src/com/android/unfold/updates/hinge/HingeAngleProvider.kt b/packages/SystemUI/shared/src/com/android/unfold/updates/hinge/HingeAngleProvider.kt
new file mode 100644
index 0000000..4196f60
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/unfold/updates/hinge/HingeAngleProvider.kt
@@ -0,0 +1,12 @@
+package com.android.unfold.updates.hinge
+
+import androidx.core.util.Consumer
+import com.android.systemui.statusbar.policy.CallbackController
+
+internal interface HingeAngleProvider : CallbackController<Consumer<Float>> {
+ fun start()
+ fun stop()
+}
+
+const val FULLY_OPEN_DEGREES = 180f
+const val FULLY_CLOSED_DEGREES = 0f
diff --git a/packages/SystemUI/shared/src/com/android/unfold/updates/hinge/RotationSensorHingeAngleProvider.kt b/packages/SystemUI/shared/src/com/android/unfold/updates/hinge/RotationSensorHingeAngleProvider.kt
new file mode 100644
index 0000000..011582e
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/unfold/updates/hinge/RotationSensorHingeAngleProvider.kt
@@ -0,0 +1,67 @@
+package com.android.unfold.updates.hinge
+
+import android.hardware.Sensor
+import android.hardware.SensorEvent
+import android.hardware.SensorEventListener
+import android.hardware.SensorManager
+import androidx.core.util.Consumer
+import com.android.systemui.shared.recents.utilities.Utilities
+
+/**
+ * Temporary hinge angle provider that uses rotation sensor instead.
+ * It requires to have the device in a certain position to work correctly
+ * (flat to the ground)
+ */
+internal class RotationSensorHingeAngleProvider(
+ private val sensorManager: SensorManager
+) : HingeAngleProvider {
+
+ private val sensorListener = HingeAngleSensorListener()
+ private val listeners: MutableList<Consumer<Float>> = arrayListOf()
+
+ override fun start() {
+ val sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GAME_ROTATION_VECTOR)
+ sensorManager.registerListener(sensorListener, sensor, SensorManager.SENSOR_DELAY_FASTEST)
+ }
+
+ override fun stop() {
+ sensorManager.unregisterListener(sensorListener)
+ }
+
+ override fun removeCallback(listener: Consumer<Float>) {
+ listeners.remove(listener)
+ }
+
+ override fun addCallback(listener: Consumer<Float>) {
+ listeners.add(listener)
+ }
+
+ private fun onHingeAngle(angle: Float) {
+ listeners.forEach { it.accept(angle) }
+ }
+
+ private inner class HingeAngleSensorListener : SensorEventListener {
+
+ override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
+ }
+
+ override fun onSensorChanged(event: SensorEvent) {
+ // Jumbojack sends incorrect sensor reading 1.0f event in the beginning, let's ignore it
+ if (event.values[3] == 1.0f) return
+
+ val angleRadians = event.values.convertToAngle()
+ val hingeAngleDegrees = Math.toDegrees(angleRadians).toFloat()
+ val angle = Utilities.clamp(hingeAngleDegrees, FULLY_CLOSED_DEGREES, FULLY_OPEN_DEGREES)
+ onHingeAngle(angle)
+ }
+
+ private val rotationMatrix = FloatArray(9)
+ private val resultOrientation = FloatArray(9)
+
+ private fun FloatArray.convertToAngle(): Double {
+ SensorManager.getRotationMatrixFromVector(rotationMatrix, this)
+ SensorManager.getOrientation(rotationMatrix, resultOrientation)
+ return resultOrientation[2] + Math.PI
+ }
+ }
+}
diff --git a/packages/SystemUI/shared/src/com/android/unfold/updates/screen/ScreenStatusProvider.kt b/packages/SystemUI/shared/src/com/android/unfold/updates/screen/ScreenStatusProvider.kt
new file mode 100644
index 0000000..a65e888
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/unfold/updates/screen/ScreenStatusProvider.kt
@@ -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.
+ */
+package com.android.unfold.updates.screen
+
+import com.android.unfold.updates.screen.ScreenStatusProvider.ScreenListener
+import com.android.systemui.statusbar.policy.CallbackController
+
+interface ScreenStatusProvider : CallbackController<ScreenListener> {
+
+ interface ScreenListener {
+ /**
+ * Called when the screen is on and ready (windows are drawn and screen blocker is removed)
+ */
+ fun onScreenTurnedOn()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java b/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java
index c89cda9..92f89d6 100644
--- a/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java
+++ b/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java
@@ -134,11 +134,15 @@
};
@Override
+ protected void onInit() {
+ mIsDozing = mStatusBarStateController.isDozing();
+ }
+
+ @Override
protected void onViewAttached() {
updateLocale();
mBroadcastDispatcher.registerReceiver(mLocaleBroadcastReceiver,
new IntentFilter(Intent.ACTION_LOCALE_CHANGED));
- mIsDozing = mStatusBarStateController.isDozing();
mDozeAmount = mStatusBarStateController.getDozeAmount();
mBatteryController.addCallback(mBatteryCallback);
mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
index 8fc4240..82ade7a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
@@ -22,15 +22,14 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AnimationUtils;
-import android.widget.LinearLayout;
+
+import androidx.constraintlayout.widget.ConstraintLayout;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.settingslib.animation.AppearAnimationUtils;
import com.android.settingslib.animation.DisappearAnimationUtils;
import com.android.systemui.R;
-import java.util.List;
-
/**
* Displays a PIN pad for unlocking.
*/
@@ -40,10 +39,6 @@
private final DisappearAnimationUtils mDisappearAnimationUtils;
private final DisappearAnimationUtils mDisappearAnimationUtilsLocked;
private ViewGroup mContainer;
- private ViewGroup mRow0;
- private ViewGroup mRow1;
- private ViewGroup mRow2;
- private ViewGroup mRow3;
private int mDisappearYTranslation;
private View[][] mViews;
@@ -82,30 +77,38 @@
}
private void updateMargins() {
+ // Re-apply everything to the keys...
int bottomMargin = mContext.getResources().getDimensionPixelSize(
- R.dimen.num_pad_row_margin_bottom);
-
- for (ViewGroup vg : List.of(mRow1, mRow2, mRow3)) {
- ((LinearLayout.LayoutParams) vg.getLayoutParams()).setMargins(0, 0, 0, bottomMargin);
- }
-
- bottomMargin = mContext.getResources().getDimensionPixelSize(
R.dimen.num_pad_entry_row_margin_bottom);
- ((LinearLayout.LayoutParams) mRow0.getLayoutParams()).setMargins(0, 0, 0, bottomMargin);
+ int rightMargin = mContext.getResources().getDimensionPixelSize(
+ R.dimen.num_pad_key_margin_end);
+ String ratio = mContext.getResources().getString(R.string.num_pad_key_ratio);
- if (mEcaView != null) {
- int ecaTopMargin = mContext.getResources().getDimensionPixelSize(
- R.dimen.keyguard_eca_top_margin);
- int ecaBottomMargin = mContext.getResources().getDimensionPixelSize(
- R.dimen.keyguard_eca_bottom_margin);
- ((LinearLayout.LayoutParams) mEcaView.getLayoutParams()).setMargins(0, ecaTopMargin,
- 0, ecaBottomMargin);
+ // mView contains all Views that make up the PIN pad; row0 = the entry test field, then
+ // rows 1-4 contain the buttons. Iterate over all views that make up the buttons in the pad,
+ // and re-set all the margins.
+ for (int row = 1; row < 5; row++) {
+ for (int column = 0; column < 3; column++) {
+ View key = mViews[row][column];
+
+ ConstraintLayout.LayoutParams lp =
+ (ConstraintLayout.LayoutParams) key.getLayoutParams();
+
+ lp.dimensionRatio = ratio;
+
+ // Don't set any margins on the last row of buttons.
+ if (row != 4) {
+ lp.bottomMargin = bottomMargin;
+ }
+
+ // Don't set margins on the rightmost buttons.
+ if (column != 2) {
+ lp.rightMargin = rightMargin;
+ }
+
+ key.setLayoutParams(lp);
+ }
}
-
- View entryView = findViewById(R.id.pinEntry);
- ViewGroup.LayoutParams lp = entryView.getLayoutParams();
- lp.height = mContext.getResources().getDimensionPixelSize(R.dimen.keyguard_password_height);
- entryView.setLayoutParams(lp);
}
@Override
@@ -113,13 +116,9 @@
super.onFinishInflate();
mContainer = findViewById(R.id.pin_container);
- mRow0 = findViewById(R.id.row0);
- mRow1 = findViewById(R.id.row1);
- mRow2 = findViewById(R.id.row2);
- mRow3 = findViewById(R.id.row3);
mViews = new View[][]{
new View[]{
- mRow0, null, null
+ findViewById(R.id.row0), null, null
},
new View[]{
findViewById(R.id.key1), findViewById(R.id.key2),
@@ -188,9 +187,6 @@
private void enableClipping(boolean enable) {
mContainer.setClipToPadding(enable);
mContainer.setClipChildren(enable);
- mRow1.setClipToPadding(enable);
- mRow2.setClipToPadding(enable);
- mRow3.setClipToPadding(enable);
setClipChildren(enable);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 5a184bb..0e25fac 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -123,10 +123,13 @@
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.Set;
import java.util.TimeZone;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
@@ -469,16 +472,39 @@
List<SubscriptionInfo> subscriptionInfos = getSubscriptionInfo(true /* forceReload */);
// Hack level over 9000: Because the subscription id is not yet valid when we see the
- // first update in handleSimStateChange, we need to force refresh all all SIM states
+ // first update in handleSimStateChange, we need to force refresh all SIM states
// so the subscription id for them is consistent.
ArrayList<SubscriptionInfo> changedSubscriptions = new ArrayList<>();
+ Set<Integer> activeSubIds = new HashSet<>();
for (int i = 0; i < subscriptionInfos.size(); i++) {
SubscriptionInfo info = subscriptionInfos.get(i);
+ activeSubIds.add(info.getSubscriptionId());
boolean changed = refreshSimState(info.getSubscriptionId(), info.getSimSlotIndex());
if (changed) {
changedSubscriptions.add(info);
}
}
+
+ // It is possible for active subscriptions to become invalid (-1), and these will not be
+ // present in the subscriptionInfo list
+ Iterator<Map.Entry<Integer, SimData>> iter = mSimDatas.entrySet().iterator();
+ while (iter.hasNext()) {
+ Map.Entry<Integer, SimData> simData = iter.next();
+ if (!activeSubIds.contains(simData.getKey())) {
+ Log.i(TAG, "Previously active sub id " + simData.getKey() + " is now invalid, "
+ + "will remove");
+ iter.remove();
+
+ SimData data = simData.getValue();
+ for (int j = 0; j < mCallbacks.size(); j++) {
+ KeyguardUpdateMonitorCallback cb = mCallbacks.get(j).get();
+ if (cb != null) {
+ cb.onSimStateChanged(data.subId, data.slotId, data.simState);
+ }
+ }
+ }
+ }
+
for (int i = 0; i < changedSubscriptions.size(); i++) {
SimData data = mSimDatas.get(changedSubscriptions.get(i).getSubscriptionId());
for (int j = 0; j < mCallbacks.size(); j++) {
@@ -3354,6 +3380,7 @@
pw.println(" trustManaged=" + getUserTrustIsManaged(userId));
pw.println(" udfpsEnrolled=" + isUdfpsEnrolled());
pw.println(" mFingerprintLockedOut=" + mFingerprintLockedOut);
+ pw.println(" mFingerprintLockedOutPermanent=" + mFingerprintLockedOutPermanent);
pw.println(" enabledByUser=" + mBiometricEnabledForUser.get(userId));
if (isUdfpsEnrolled()) {
pw.println(" shouldListenForUdfps=" + shouldListenForFingerprint(true));
@@ -3375,8 +3402,11 @@
+ getStrongAuthTracker().hasUserAuthenticatedSinceBoot());
pw.println(" disabled(DPM)=" + isFaceDisabled(userId));
pw.println(" possible=" + isUnlockWithFacePossible(userId));
+ pw.println(" listening: actual=" + mFaceRunningState
+ + " expected=(" + (shouldListenForFace() ? 1 : 0));
pw.println(" strongAuthFlags=" + Integer.toHexString(strongAuthFlags));
pw.println(" trustManaged=" + getUserTrustIsManaged(userId));
+ pw.println(" mFaceLockedOutPermanent=" + mFaceLockedOutPermanent);
pw.println(" enabledByUser=" + mBiometricEnabledForUser.get(userId));
pw.println(" mSecureCameraLaunched=" + mSecureCameraLaunched);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 8b974b4..9c8582fa 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -72,7 +72,10 @@
*/
@StatusBarComponent.StatusBarScope
public class LockIconViewController extends ViewController<LockIconView> implements Dumpable {
-
+ private static final float sDefaultDensity =
+ (float) DisplayMetrics.DENSITY_DEVICE_STABLE / (float) DisplayMetrics.DENSITY_DEFAULT;
+ private static final int sLockIconRadiusPx = (int) (sDefaultDensity * 36);
+ private static final float sDistAboveKgBottomAreaPx = sDefaultDensity * 12;
private static final AudioAttributes VIBRATION_SONIFICATION_ATTRIBUTES =
new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
@@ -111,9 +114,7 @@
private boolean mHasUdfps;
private float mHeightPixels;
private float mWidthPixels;
- private float mDensity;
- private int mAmbientIndicationHeight; // in pixels
- private int mKgIndicationHeight; // in pixels
+ private int mBottomPadding; // in pixels
private boolean mShowUnlockIcon;
private boolean mShowLockIcon;
@@ -318,11 +319,8 @@
final DisplayMetrics metrics = mView.getContext().getResources().getDisplayMetrics();
mWidthPixels = metrics.widthPixels;
mHeightPixels = metrics.heightPixels;
- mDensity = metrics.density;
- mKgIndicationHeight = mView.getContext().getResources().getDimensionPixelSize(
- R.dimen.keyguard_indication_margin_bottom)
- + mView.getContext().getResources().getDimensionPixelSize(
- R.dimen.keyguard_indication_bottom_padding);
+ mBottomPadding = mView.getContext().getResources().getDimensionPixelSize(
+ R.dimen.lock_icon_margin_bottom);
updateLockIconLocation();
}
@@ -332,26 +330,15 @@
mView.setCenterLocation(new PointF(props.sensorLocationX, props.sensorLocationY),
props.sensorRadius);
} else {
- final float distAboveKgBottomArea = 12 * mDensity;
- final float radius = 36 * mDensity;
- final int kgBottomAreaHeight = Math.max(mKgIndicationHeight, mAmbientIndicationHeight);
mView.setCenterLocation(
new PointF(mWidthPixels / 2,
- mHeightPixels - kgBottomAreaHeight - distAboveKgBottomArea
- - radius / 2), (int) radius);
+ mHeightPixels - mBottomPadding - sDistAboveKgBottomAreaPx
+ - sLockIconRadiusPx), sLockIconRadiusPx);
}
mView.getHitRect(mSensorTouchLocation);
}
- /**
- * Set the location of ambient indication if showing (ie: now playing)
- */
- public void setAmbientIndicationBottomPadding(int ambientIndicationBottomPadding) {
- mAmbientIndicationHeight = ambientIndicationBottomPadding;
- updateLockIconLocation();
- }
-
@Override
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
pw.println("mUdfpsEnrolled: " + mUdfpsEnrolled);
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
index 57407f1..99f9558 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
@@ -59,7 +59,9 @@
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// Set width/height to the same value to ensure a smooth circle for the bg, but shrink
- // the height to match the old pin bouncer
+ // the height to match the old pin bouncer.
+ // This is only used for PIN/PUK; the main PIN pad now uses ConstraintLayout, which will
+ // force our width/height to conform to the ratio in the layout.
int width = getMeasuredWidth();
boolean shortenHeight = mAnimator == null
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
index 232c6fc..e79ea9a 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
@@ -175,7 +175,9 @@
measureChildren(widthMeasureSpec, heightMeasureSpec);
// Set width/height to the same value to ensure a smooth circle for the bg, but shrink
- // the height to match the old pin bouncer
+ // the height to match the old pin bouncer.
+ // This is only used for PIN/PUK; the main PIN pad now uses ConstraintLayout, which will
+ // force our width/height to conform to the ratio in the layout.
int width = getMeasuredWidth();
boolean shortenHeight = mAnimator == null
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 45f8d82..d258eca 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -99,6 +99,7 @@
import com.android.systemui.statusbar.phone.ManagedProfileController;
import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper;
import com.android.systemui.statusbar.phone.ShadeController;
+import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarWindowController;
import com.android.systemui.statusbar.policy.AccessibilityController;
@@ -139,7 +140,6 @@
import javax.inject.Inject;
import javax.inject.Named;
-import javax.inject.Provider;
import dagger.Lazy;
@@ -199,12 +199,6 @@
public static final String ALLOW_NOTIFICATION_LONG_PRESS_NAME = "allow_notif_longpress";
/**
- * A provider of {@link EdgeBackGestureHandler}.
- */
- public static final String EDGE_BACK_GESTURE_HANDLER_PROVIDER_NAME =
- "edge_back_gesture_handler_provider";
-
- /**
* Key for getting a background Looper for background work.
*/
public static final DependencyKey<Looper> BG_LOOPER = new DependencyKey<>(BG_LOOPER_NAME);
@@ -239,12 +233,6 @@
*/
public static final DependencyKey<String> LEAK_REPORT_EMAIL =
new DependencyKey<>(LEAK_REPORT_EMAIL_NAME);
- /**
- * Key for retrieving an Provider<EdgeBackGestureHandler>.
- */
- public static final DependencyKey<Provider<EdgeBackGestureHandler>>
- EDGE_BACK_GESTURE_HANDLER_PROVIDER =
- new DependencyKey<>(EDGE_BACK_GESTURE_HANDLER_PROVIDER_NAME);
private final ArrayMap<Object, Object> mDependencies = new ArrayMap<>();
private final ArrayMap<Object, LazyDependencyCreator> mProviders = new ArrayMap<>();
@@ -369,8 +357,9 @@
@Inject Lazy<TelephonyListenerManager> mTelephonyListenerManager;
@Inject Lazy<SystemStatusAnimationScheduler> mSystemStatusAnimationSchedulerLazy;
@Inject Lazy<PrivacyDotViewController> mPrivacyDotViewControllerLazy;
- @Inject Provider<EdgeBackGestureHandler> mEdgeBackGestureHandlerProvider;
+ @Inject Lazy<EdgeBackGestureHandler.Factory> mEdgeBackGestureHandlerFactoryLazy;
@Inject Lazy<UiEventLogger> mUiEventLogger;
+ @Inject Lazy<StatusBarContentInsetsProvider> mContentInsetsProviderLazy;
@Inject Lazy<InternetDialogFactory> mInternetDialogFactory;
@Inject Lazy<FeatureFlags> mFeatureFlagsLazy;
@@ -584,9 +573,11 @@
mSystemStatusAnimationSchedulerLazy::get);
mProviders.put(PrivacyDotViewController.class, mPrivacyDotViewControllerLazy::get);
mProviders.put(InternetDialogFactory.class, mInternetDialogFactory::get);
- mProviders.put(EDGE_BACK_GESTURE_HANDLER_PROVIDER, () -> mEdgeBackGestureHandlerProvider);
+ mProviders.put(EdgeBackGestureHandler.Factory.class,
+ mEdgeBackGestureHandlerFactoryLazy::get);
mProviders.put(UiEventLogger.class, mUiEventLogger::get);
mProviders.put(FeatureFlags.class, mFeatureFlagsLazy::get);
+ mProviders.put(StatusBarContentInsetsProvider.class, mContentInsetsProviderLazy::get);
Dependency.setInstance(this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index a68f796..c8f8404 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -20,6 +20,8 @@
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.graphics.RectF;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManager.DisplayListener;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.SystemClock;
@@ -29,7 +31,6 @@
import android.util.Log;
import android.util.MathUtils;
import android.util.Size;
-import android.view.DisplayInfo;
import android.view.SurfaceHolder;
import android.view.WindowManager;
@@ -90,7 +91,7 @@
mMiniBitmap = null;
}
- class GLEngine extends Engine {
+ class GLEngine extends Engine implements DisplayListener {
// Surface is rejected if size below a threshold on some devices (ie. 8px on elfin)
// set min to 64 px (CTS covers this), please refer to ag/4867989 for detail.
@VisibleForTesting
@@ -102,15 +103,15 @@
private EglHelper mEglHelper;
private final Runnable mFinishRenderingTask = this::finishRendering;
private boolean mNeedRedraw;
- private int mWidth = 1;
- private int mHeight = 1;
+
+ private boolean mDisplaySizeValid = false;
+ private int mDisplayWidth = 1;
+ private int mDisplayHeight = 1;
+
private int mImgWidth = 1;
private int mImgHeight = 1;
- private float mPageWidth = 1.f;
- private float mPageOffset = 1.f;
- GLEngine() {
- }
+ GLEngine() { }
@VisibleForTesting
GLEngine(Handler handler) {
@@ -124,13 +125,23 @@
mRenderer = getRendererInstance();
setFixedSizeAllowed(true);
updateSurfaceSize();
- Rect window = getDisplayContext()
- .getSystemService(WindowManager.class)
- .getCurrentWindowMetrics()
- .getBounds();
- mHeight = window.height();
- mWidth = window.width();
+
mRenderer.setOnBitmapChanged(this::updateMiniBitmap);
+ getDisplayContext().getSystemService(DisplayManager.class)
+ .registerDisplayListener(this, mWorker.getThreadHandler());
+ }
+
+ @Override
+ public void onDisplayAdded(int displayId) { }
+
+ @Override
+ public void onDisplayRemoved(int displayId) { }
+
+ @Override
+ public void onDisplayChanged(int displayId) {
+ if (displayId == getDisplayContext().getDisplayId()) {
+ mDisplaySizeValid = false;
+ }
}
EglHelper getEglHelperInstance() {
@@ -154,26 +165,10 @@
if (pages == mPages) return;
mPages = pages;
if (mMiniBitmap == null || mMiniBitmap.isRecycled()) return;
- updateShift();
mWorker.getThreadHandler().post(() ->
computeAndNotifyLocalColors(new ArrayList<>(mColorAreas), mMiniBitmap));
}
- private void updateShift() {
- if (mImgHeight == 0) {
- mPageOffset = 0;
- mPageWidth = 1;
- return;
- }
- // calculate shift
- DisplayInfo displayInfo = new DisplayInfo();
- getDisplayContext().getDisplay().getDisplayInfo(displayInfo);
- int screenWidth = displayInfo.getNaturalWidth();
- float imgWidth = Math.min(mImgWidth > 0 ? screenWidth / (float) mImgWidth : 1.f, 1.f);
- mPageWidth = imgWidth;
- mPageOffset = (1 - imgWidth) / (float) (mPages - 1);
- }
-
private void updateMiniBitmap(Bitmap b) {
if (b == null) return;
int size = Math.min(b.getWidth(), b.getHeight());
@@ -204,6 +199,8 @@
@Override
public void onDestroy() {
+ getDisplayContext().getSystemService(DisplayManager.class)
+ .unregisterDisplayListener(this);
mMiniBitmap = null;
mWorker.getThreadHandler().post(() -> {
mRenderer.finish();
@@ -268,6 +265,16 @@
* (1-Wr)].
*/
private RectF pageToImgRect(RectF area) {
+ if (!mDisplaySizeValid) {
+ Rect window = getDisplayContext()
+ .getSystemService(WindowManager.class)
+ .getCurrentWindowMetrics()
+ .getBounds();
+ mDisplayWidth = window.width();
+ mDisplayHeight = window.height();
+ mDisplaySizeValid = true;
+ }
+
// Width of a page for the caller of this API.
float virtualPageWidth = 1f / (float) mPages;
float leftPosOnPage = (area.left % virtualPageWidth) / virtualPageWidth;
@@ -275,12 +282,24 @@
int currentPage = (int) Math.floor(area.centerX() / virtualPageWidth);
RectF imgArea = new RectF();
+
+ if (mImgWidth == 0 || mImgHeight == 0 || mDisplayWidth <= 0 || mDisplayHeight <= 0) {
+ return imgArea;
+ }
+
imgArea.bottom = area.bottom;
imgArea.top = area.top;
+
+ float imageScale = Math.min(((float) mImgHeight) / mDisplayHeight, 1);
+ float mappedScreenWidth = mDisplayWidth * imageScale;
+ float pageWidth = Math.min(1.0f,
+ mImgWidth > 0 ? mappedScreenWidth / (float) mImgWidth : 1.f);
+ float pageOffset = (1 - pageWidth) / (float) (mPages - 1);
+
imgArea.left = MathUtils.constrain(
- leftPosOnPage * mPageWidth + currentPage * mPageOffset, 0, 1);
+ leftPosOnPage * pageWidth + currentPage * pageOffset, 0, 1);
imgArea.right = MathUtils.constrain(
- rightPosOnPage * mPageWidth + currentPage * mPageOffset, 0, 1);
+ rightPosOnPage * pageWidth + currentPage * pageOffset, 0, 1);
if (imgArea.left > imgArea.right) {
// take full page
imgArea.left = 0;
@@ -293,7 +312,6 @@
private List<WallpaperColors> getLocalWallpaperColors(@NonNull List<RectF> areas,
Bitmap b) {
List<WallpaperColors> colors = new ArrayList<>(areas.size());
- updateShift();
for (int i = 0; i < areas.size(); i++) {
RectF area = pageToImgRect(areas.get(i));
if (area == null || !LOCAL_COLOR_BOUNDS.contains(area)) {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityButtonModeObserver.java b/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityButtonModeObserver.java
index 9bedb1e..fbb909f 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityButtonModeObserver.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityButtonModeObserver.java
@@ -17,6 +17,7 @@
package com.android.systemui.accessibility;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
+import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_GESTURE;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR;
import android.annotation.IntDef;
@@ -49,7 +50,8 @@
@Retention(RetentionPolicy.SOURCE)
@IntDef({
ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR,
- ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU
+ ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU,
+ ACCESSIBILITY_BUTTON_MODE_GESTURE
})
public @interface AccessibilityButtonMode {}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 71e2bb6..0ce1846 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -37,6 +37,7 @@
import android.hardware.biometrics.BiometricPrompt;
import android.hardware.biometrics.IBiometricSysuiReceiver;
import android.hardware.biometrics.PromptInfo;
+import android.hardware.display.DisplayManager;
import android.hardware.face.FaceManager;
import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.fingerprint.FingerprintManager;
@@ -57,6 +58,7 @@
import com.android.systemui.SystemUI;
import com.android.systemui.assist.ui.DisplayUtils;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.doze.DozeReceiver;
import com.android.systemui.statusbar.CommandQueue;
@@ -423,7 +425,9 @@
@Nullable FingerprintManager fingerprintManager,
@Nullable FaceManager faceManager,
Provider<UdfpsController> udfpsControllerFactory,
- Provider<SidefpsController> sidefpsControllerFactory) {
+ Provider<SidefpsController> sidefpsControllerFactory,
+ @NonNull DisplayManager displayManager,
+ @Main Handler handler) {
super(context);
mCommandQueue = commandQueue;
mActivityTaskManager = activityTaskManager;
@@ -432,10 +436,13 @@
mUdfpsControllerFactory = udfpsControllerFactory;
mSidefpsControllerFactory = sidefpsControllerFactory;
mWindowManager = windowManager;
- mOrientationListener = new BiometricOrientationEventListener(context, () -> {
- onOrientationChanged();
- return Unit.INSTANCE;
- });
+ mOrientationListener = new BiometricOrientationEventListener(context,
+ () -> {
+ onOrientationChanged();
+ return Unit.INSTANCE;
+ },
+ displayManager,
+ handler);
mFaceProps = mFaceManager != null ? mFaceManager.getSensorPropertiesInternal() : null;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricOrientationEventListener.kt b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricOrientationEventListener.kt
index 08ea857..98a03a1 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricOrientationEventListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricOrientationEventListener.kt
@@ -17,7 +17,10 @@
package com.android.systemui.biometrics
import android.content.Context
+import android.hardware.display.DisplayManager
+import android.os.Handler
import android.view.OrientationEventListener
+import android.view.Surface
/**
* An [OrientationEventListener] that invokes the [onOrientationChanged] callback whenever
@@ -26,20 +29,16 @@
*/
class BiometricOrientationEventListener(
private val context: Context,
- private val onOrientationChanged: () -> Unit
-) : OrientationEventListener(context) {
+ private val onOrientationChanged: () -> Unit,
+ private val displayManager: DisplayManager,
+ private val handler: Handler
+) : DisplayManager.DisplayListener {
- /** If actively listening (not available in base class). */
- var enabled: Boolean = false
- private set
+ private var lastRotation = context.display?.rotation ?: Surface.ROTATION_0
- private var lastRotation = context.display?.rotation ?: ORIENTATION_UNKNOWN
-
- override fun onOrientationChanged(orientation: Int) {
- if (orientation == ORIENTATION_UNKNOWN) {
- return
- }
-
+ override fun onDisplayAdded(displayId: Int) {}
+ override fun onDisplayRemoved(displayId: Int) {}
+ override fun onDisplayChanged(displayId: Int) {
val rotation = context.display?.rotation ?: return
if (lastRotation != rotation) {
lastRotation = rotation
@@ -48,13 +47,11 @@
}
}
- override fun enable() {
- enabled = true
- super.enable()
+ fun enable() {
+ displayManager.registerDisplayListener(this, handler)
}
- override fun disable() {
- enabled = false
- super.disable()
+ fun disable() {
+ displayManager.unregisterDisplayListener(this)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.java
index a51c2b8..8f6e249 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.java
@@ -23,9 +23,11 @@
import android.annotation.Nullable;
import android.content.Context;
import android.graphics.PixelFormat;
+import android.hardware.display.DisplayManager;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.ISidefpsController;
+import android.os.Handler;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Gravity;
@@ -93,16 +95,22 @@
@NonNull LayoutInflater inflater,
@Nullable FingerprintManager fingerprintManager,
@NonNull WindowManager windowManager,
- @Main DelayableExecutor fgExecutor) {
+ @Main DelayableExecutor fgExecutor,
+ @NonNull DisplayManager displayManager,
+ @Main Handler handler) {
mContext = context;
mInflater = inflater;
mFingerprintManager = checkNotNull(fingerprintManager);
mWindowManager = windowManager;
mFgExecutor = fgExecutor;
- mOrientationListener = new BiometricOrientationEventListener(context, () -> {
- onOrientationChanged();
- return Unit.INSTANCE;
- });
+ mOrientationListener = new BiometricOrientationEventListener(
+ context,
+ () -> {
+ onOrientationChanged();
+ return Unit.INSTANCE;
+ },
+ displayManager,
+ handler);
mSensorProps = findFirstSidefps();
checkArgument(mSensorProps != null);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index aafacd6..2309d5f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -32,6 +32,7 @@
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.RectF;
+import android.hardware.display.DisplayManager;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.IUdfpsOverlayController;
@@ -519,7 +520,9 @@
@NonNull UdfpsHapticsSimulator udfpsHapticsSimulator,
@NonNull Optional<UdfpsHbmProvider> hbmProvider,
@NonNull KeyguardStateController keyguardStateController,
- @NonNull KeyguardBypassController keyguardBypassController) {
+ @NonNull KeyguardBypassController keyguardBypassController,
+ @NonNull DisplayManager displayManager,
+ @Main Handler mainHandler) {
mContext = context;
mExecution = execution;
// TODO (b/185124905): inject main handler and vibrator once done prototyping
@@ -545,10 +548,14 @@
mHbmProvider = hbmProvider.orElse(null);
screenLifecycle.addObserver(mScreenObserver);
mScreenOn = screenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_ON;
- mOrientationListener = new BiometricOrientationEventListener(context, () -> {
- onOrientationChanged();
- return Unit.INSTANCE;
- });
+ mOrientationListener = new BiometricOrientationEventListener(
+ context,
+ () -> {
+ onOrientationChanged();
+ return Unit.INSTANCE;
+ },
+ displayManager,
+ mainHandler);
mKeyguardBypassController = keyguardBypassController;
mSensorProps = findFirstUdfps();
@@ -662,7 +669,8 @@
// Transform dimensions if the device is in landscape mode
switch (mContext.getDisplay().getRotation()) {
case Surface.ROTATION_90:
- if (animation instanceof UdfpsKeyguardViewController) {
+ if (animation instanceof UdfpsKeyguardViewController
+ && mKeyguardUpdateMonitor.isGoingToSleep()) {
break;
}
mCoreLayoutParams.x = mSensorProps.sensorLocationY - mSensorProps.sensorRadius
@@ -672,7 +680,8 @@
break;
case Surface.ROTATION_270:
- if (animation instanceof UdfpsKeyguardViewController) {
+ if (animation instanceof UdfpsKeyguardViewController
+ && mKeyguardUpdateMonitor.isGoingToSleep()) {
break;
}
mCoreLayoutParams.x = p.x - mSensorProps.sensorLocationY - mSensorProps.sensorRadius
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
index bed3fd1..9c95720 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
@@ -378,6 +378,9 @@
@Override
public boolean onTouch(MotionEvent event) {
+ if (mTransitionToFullShadeProgress != 0) {
+ return false;
+ }
return mUdfpsController.onTouch(event);
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalHostView.java b/packages/SystemUI/src/com/android/systemui/communal/CommunalHostView.java
new file mode 100644
index 0000000..6e2fcd1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalHostView.java
@@ -0,0 +1,45 @@
+/*
+ * 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.communal;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.FrameLayout;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+/**
+ * Container for communal presentation. Containing communal-related view to this parent view allows
+ * for aggregate measurement/layout adjustments and capturing said values before the communal views
+ * might be available.
+ */
+public class CommunalHostView extends FrameLayout {
+ public CommunalHostView(@NonNull Context context) {
+ this(context, null, 0);
+ }
+
+ public CommunalHostView(@NonNull Context context,
+ @Nullable AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public CommunalHostView(@NonNull Context context, @Nullable AttributeSet attrs,
+ int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalHostViewController.java b/packages/SystemUI/src/com/android/systemui/communal/CommunalHostViewController.java
new file mode 100644
index 0000000..268ba64
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalHostViewController.java
@@ -0,0 +1,205 @@
+/*
+ * 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.communal;
+
+import android.content.Context;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.notification.AnimatableProperty;
+import com.android.systemui.statusbar.notification.PropertyAnimator;
+import com.android.systemui.statusbar.notification.stack.AnimationProperties;
+import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.util.ViewController;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+import java.lang.ref.WeakReference;
+import java.util.concurrent.Executor;
+
+import javax.inject.Inject;
+
+/**
+ * Injectable controller for {@link CommunalHostView}.
+ */
+public class CommunalHostViewController extends ViewController<CommunalHostView> {
+ private static final String TAG = "CommunalController";
+ private static final boolean DEBUG = false;
+ private static final AnimationProperties ANIMATION_PROPERTIES =
+ new AnimationProperties().setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+
+ private final Executor mMainExecutor;
+ private final KeyguardStateController mKeyguardStateController;
+ private final StatusBarStateController mStatusBarStateController;
+ private WeakReference<CommunalSource> mLastSource;
+ private int mState;
+
+ private static final int STATE_KEYGUARD_SHOWING = 1 << 0;
+ private static final int STATE_DOZING = 1 << 1;
+
+ // Only show communal view when keyguard is showing and not dozing.
+ private static final int SHOW_COMMUNAL_VIEW_REQUIRED_STATES = STATE_KEYGUARD_SHOWING;
+ private static final int SHOW_COMMUNAL_VIEW_INVALID_STATES = STATE_DOZING;
+
+ private KeyguardStateController.Callback mKeyguardCallback =
+ new KeyguardStateController.Callback() {
+ @Override
+ public void onKeyguardShowingChanged() {
+ final boolean isShowing = mKeyguardStateController.isShowing();
+ if (DEBUG) {
+ Log.d(TAG, "setKeyguardShowing:" + isShowing);
+ }
+
+ setState(STATE_KEYGUARD_SHOWING, isShowing);
+ }
+ };
+
+ private StatusBarStateController.StateListener mDozeCallback =
+ new StatusBarStateController.StateListener() {
+ @Override
+ public void onDozingChanged(boolean isDozing) {
+ if (DEBUG) {
+ Log.d(TAG, "setDozing:" + isDozing);
+ }
+
+ setState(STATE_DOZING, isDozing);
+ }
+ };
+
+ @Inject
+ protected CommunalHostViewController(@Main Executor mainExecutor,
+ KeyguardStateController keyguardStateController,
+ StatusBarStateController statusBarStateController, CommunalHostView view) {
+ super(view);
+ mMainExecutor = mainExecutor;
+ mKeyguardStateController = keyguardStateController;
+ mStatusBarStateController = statusBarStateController;
+ mState = 0;
+
+ if (mKeyguardStateController.isShowing()) {
+ mState |= STATE_KEYGUARD_SHOWING;
+ }
+
+ if (mStatusBarStateController.isDozing()) {
+ mState |= STATE_DOZING;
+ }
+
+ mKeyguardStateController.addCallback(mKeyguardCallback);
+ mStatusBarStateController.addCallback(mDozeCallback);
+ }
+
+ @Override
+ protected void onViewAttached() {
+ mKeyguardStateController.removeCallback(mKeyguardCallback);
+ mKeyguardStateController.addCallback(mKeyguardCallback);
+ mStatusBarStateController.removeCallback(mDozeCallback);
+ mStatusBarStateController.addCallback(mDozeCallback);
+ }
+
+ @Override
+ protected void onViewDetached() {
+ mKeyguardStateController.removeCallback(mKeyguardCallback);
+ mStatusBarStateController.removeCallback(mDozeCallback);
+ }
+
+ private void setState(int stateFlag, boolean enabled) {
+ final int existingState = mState;
+ if (DEBUG) {
+ Log.d(TAG, "setState flag:" + stateFlag + " enabled:" + enabled);
+ }
+
+ if (enabled) {
+ mState |= stateFlag;
+ } else {
+ mState &= ~stateFlag;
+ }
+
+ if (DEBUG) {
+ Log.d(TAG, "updated state:" + mState);
+ }
+
+ if (existingState != mState) {
+ showSource();
+ }
+ }
+
+ private void showSource() {
+ // Make sure all necessary states are present for showing communal and all invalid states
+ // are absent
+ mMainExecutor.execute(() -> {
+ final CommunalSource currentSource = mLastSource != null ? mLastSource.get() : null;
+
+ if ((mState & SHOW_COMMUNAL_VIEW_REQUIRED_STATES) == SHOW_COMMUNAL_VIEW_REQUIRED_STATES
+ && (mState & SHOW_COMMUNAL_VIEW_INVALID_STATES) == 0
+ && currentSource != null) {
+ mView.removeAllViews();
+
+ // Make view visible.
+ mView.setVisibility(View.VISIBLE);
+
+ final Context context = mView.getContext();
+
+ final ListenableFuture<View> listenableFuture =
+ currentSource.requestCommunalView(context);
+
+ if (listenableFuture == null) {
+ Log.e(TAG, "could not request communal view");
+ return;
+ }
+
+ listenableFuture.addListener(() -> {
+ try {
+ final View view = listenableFuture.get();
+ view.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT));
+ mView.addView(view);
+ } catch (Exception e) {
+ Log.e(TAG, "could not obtain communal view through callback:" + e);
+ }
+ }, mMainExecutor);
+ } else {
+ mView.removeAllViews();
+ mView.setVisibility(View.INVISIBLE);
+ }
+ });
+ }
+
+ /**
+ * Instructs {@link CommunalHostViewController} to display provided source.
+ *
+ * @param source The new {@link CommunalSource}, {@code null} if not set.
+ */
+ public void show(WeakReference<CommunalSource> source) {
+ mLastSource = source;
+ showSource();
+ }
+
+ /**
+ * Sets the Y position of the {@link CommunalHostView}
+ *
+ * @param y Offset from parent top.
+ * @param animate Whether the change should be animated.
+ */
+ public void updatePositionY(int y, boolean animate) {
+ PropertyAnimator.setProperty(mView, AnimatableProperty.Y, y, ANIMATION_PROPERTIES, animate);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalSource.java b/packages/SystemUI/src/com/android/systemui/communal/CommunalSource.java
new file mode 100644
index 0000000..742e4b1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalSource.java
@@ -0,0 +1,63 @@
+/*
+ * 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.communal;
+
+import android.content.Context;
+import android.view.View;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * {@link CommunalSource} defines an interface for working with a source for communal data. Clients
+ * may request a communal surface that can be shown within a {@link android.view.SurfaceView}.
+ * Callbacks may also be registered to listen to state changes.
+ */
+public interface CommunalSource {
+ /**
+ * Requests a communal surface that can be displayed inside {@link CommunalHostView}.
+ *
+ * @param context The {@link View} {@link Context} to build the resulting view from
+ * @return A future that can be listened upon for the resulting {@link View}. The value will be
+ * {@code null} in case of a failure.
+ */
+ ListenableFuture<View> requestCommunalView(Context context);
+
+ /**
+ * Adds a {@link Callback} to receive future status updates regarding this
+ * {@link CommunalSource}.
+ *
+ * @param callback The {@link Callback} to be added.
+ */
+ void addCallback(Callback callback);
+
+ /**
+ * Removes a {@link Callback} from receiving future updates.
+ *
+ * @param callback The {@link Callback} to be removed.
+ */
+ void removeCallback(Callback callback);
+
+ /**
+ * An interface for receiving updates on the state of the {@link CommunalSource}.
+ */
+ interface Callback {
+ /**
+ * Invoked when the {@link CommunalSource} is no longer available for use.
+ */
+ void onDisconnected();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalSourceMonitor.java b/packages/SystemUI/src/com/android/systemui/communal/CommunalSourceMonitor.java
new file mode 100644
index 0000000..36fc5fa
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalSourceMonitor.java
@@ -0,0 +1,116 @@
+/*
+ * 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.communal;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.dagger.SysUISingleton;
+
+import com.google.android.collect.Lists;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+
+import javax.inject.Inject;
+
+/**
+ * A Monitor for reporting a {@link CommunalSource} presence.
+ */
+@SysUISingleton
+public class CommunalSourceMonitor {
+ // A list of {@link Callback} that have registered to receive updates.
+ private final ArrayList<WeakReference<Callback>> mCallbacks = Lists.newArrayList();
+
+ private CommunalSource mCurrentSource;
+
+ private CommunalSource.Callback mSourceCallback = new CommunalSource.Callback() {
+ @Override
+ public void onDisconnected() {
+ // Clear source reference.
+ setSource(null /* source */);
+ }
+ };
+
+ @VisibleForTesting
+ @Inject
+ public CommunalSourceMonitor() {
+ }
+
+ /**
+ * Sets the current {@link CommunalSource}, informing any callbacks. Any existing
+ * {@link CommunalSource} will be disconnected.
+ *
+ * @param source The new {@link CommunalSource}.
+ */
+ public void setSource(CommunalSource source) {
+ if (mCurrentSource != null) {
+ mCurrentSource.removeCallback(mSourceCallback);
+ }
+
+ mCurrentSource = source;
+
+ // If the new source is valid, inform registered Callbacks of its presence.
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ Callback cb = mCallbacks.get(i).get();
+ if (cb != null) {
+ cb.onSourceAvailable(
+ mCurrentSource != null ? new WeakReference<>(mCurrentSource) : null);
+ }
+ }
+
+ // Add callback to be informed when the source disconnects.
+ if (mCurrentSource != null) {
+ mCurrentSource.addCallback(mSourceCallback);
+ }
+ }
+
+ /**
+ * Adds a {@link Callback} to receive {@link CommunalSource} updates.
+ *
+ * @param callback The {@link Callback} to add.
+ */
+ public void addCallback(Callback callback) {
+ mCallbacks.add(new WeakReference<>(callback));
+
+ // Inform the callback of any already present CommunalSource.
+ if (mCurrentSource != null) {
+ callback.onSourceAvailable(new WeakReference<>(mCurrentSource));
+ }
+ }
+
+ /**
+ * Removes the specified {@link Callback} from receive future updates if present.
+ *
+ * @param callback The {@link Callback} to add.
+ */
+ public void removeCallback(Callback callback) {
+ mCallbacks.removeIf(el -> el.get() == callback);
+ }
+
+ /**
+ * Interface implemented to be notified when new {@link CommunalSource} become available.
+ */
+ public interface Callback {
+ /**
+ * Called when a new {@link CommunalSource} has been registered. This will also be invoked
+ * when a {@link Callback} is first registered and a {@link CommunalSource} is already
+ * registered.
+ *
+ * @param source The new {@link CommunalSource}.
+ */
+ void onSourceAvailable(WeakReference<CommunalSource> source);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.java b/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.java
new file mode 100644
index 0000000..bcc3684
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.java
@@ -0,0 +1,28 @@
+/*
+ * 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.communal.dagger;
+
+import dagger.Module;
+
+/**
+ * Dagger Module providing Communal-related functionality.
+ */
+@Module(subcomponents = {
+ CommunalViewComponent.class,
+})
+public class CommunalModule {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalViewComponent.java b/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalViewComponent.java
new file mode 100644
index 0000000..3a80a03
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalViewComponent.java
@@ -0,0 +1,38 @@
+/*
+ * 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.communal.dagger;
+
+import com.android.systemui.communal.CommunalHostView;
+import com.android.systemui.communal.CommunalHostViewController;
+
+import dagger.BindsInstance;
+import dagger.Subcomponent;
+
+/**
+ * Subcomponent for working with {@link CommunalHostView}.
+ */
+@Subcomponent
+public interface CommunalViewComponent {
+ /** Simple factory for {@link CommunalViewComponent}. */
+ @Subcomponent.Factory
+ interface Factory {
+ CommunalViewComponent build(@BindsInstance CommunalHostView view);
+ }
+
+ /** Builds a {@link CommunalHostViewController}. */
+ CommunalHostViewController getCommunalHostViewController();
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/service/CommunalService.java b/packages/SystemUI/src/com/android/systemui/communal/service/CommunalService.java
new file mode 100644
index 0000000..7c010a9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/service/CommunalService.java
@@ -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.
+ */
+
+package com.android.systemui.communal.service;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+import androidx.annotation.Nullable;
+
+import com.android.systemui.communal.CommunalSourceMonitor;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.shared.communal.ICommunalHost;
+import com.android.systemui.shared.communal.ICommunalSource;
+
+import java.util.concurrent.Executor;
+
+import javax.inject.Inject;
+
+/**
+ * CommunalService services requests to {@link ICommunalHost}, allowing clients to declare
+ * themselves as the source of communal surfaces.
+ */
+public class CommunalService extends Service {
+ final Executor mMainExecutor;
+ final CommunalSourceMonitor mMonitor;
+
+ private ICommunalHost.Stub mBinder = new ICommunalHost.Stub() {
+ @Override
+ public void setSource(ICommunalSource source) {
+ mMonitor.setSource(
+ source != null ? new CommunalSourceImpl(mMainExecutor, source) : null);
+ }
+ };
+
+ @Inject
+ CommunalService(@Main Executor mainExecutor, CommunalSourceMonitor monitor) {
+ mMainExecutor = mainExecutor;
+ mMonitor = monitor;
+ }
+
+ @Nullable
+ @Override
+ public IBinder onBind(Intent intent) {
+ // The service does not expect requests outside ICommunalHost.
+ return mBinder;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/service/CommunalSourceImpl.java b/packages/SystemUI/src/com/android/systemui/communal/service/CommunalSourceImpl.java
new file mode 100644
index 0000000..7d2006a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/service/CommunalSourceImpl.java
@@ -0,0 +1,147 @@
+/*
+ * 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.communal.service;
+
+import android.content.Context;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.SurfaceControlViewHost;
+import android.view.View;
+
+import androidx.concurrent.futures.CallbackToFutureAdapter;
+
+import com.android.systemui.communal.CommunalSource;
+import com.android.systemui.shared.communal.ICommunalSource;
+import com.android.systemui.shared.communal.ICommunalSurfaceCallback;
+
+import com.google.android.collect.Lists;
+import com.google.common.util.concurrent.ListenableFuture;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.concurrent.Executor;
+
+/**
+ * {@link CommunalSourceImpl} provides a wrapper around {@link ICommunalSource} proxies as an
+ * implementation of {@link CommunalSource}. Requests and responses for communal surfaces are
+ * translated into the proper binder calls.
+ */
+public class CommunalSourceImpl implements CommunalSource {
+ private static final String TAG = "CommunalSourceImpl";
+ private static final boolean DEBUG = false;
+ private final ICommunalSource mSourceProxy;
+ private final Executor mMainExecutor;
+
+ // mConnected is initialized to true as it is presumed instances are constructed with valid
+ // proxies. The source can never be reconnected once the proxy has died. Once this value
+ // becomes false, the source will always report disconnected to registering callbacks.
+ private boolean mConnected = true;
+
+ // A list of {@link Callback} that have registered to receive updates.
+ private final ArrayList<WeakReference<Callback>> mCallbacks = Lists.newArrayList();
+
+ public CommunalSourceImpl(Executor mainExecutor, ICommunalSource sourceProxy) {
+ mMainExecutor = mainExecutor;
+ mSourceProxy = sourceProxy;
+
+ try {
+ // Track connection status based on proxy lifetime.
+ mSourceProxy.asBinder().linkToDeath(new IBinder.DeathRecipient() {
+ @Override
+ public void binderDied() {
+ if (DEBUG) {
+ Log.d(TAG, "Source lost. Clearing reporting disconnect.");
+ }
+
+ // Set connection state and inform callbacks.
+ onDisconnected();
+ }
+ }, 0);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not link to the source proxy death:" + e);
+ }
+ }
+
+ private void onDisconnected() {
+ mConnected = false;
+ for (WeakReference<Callback> cbRef : mCallbacks) {
+ final Callback cb = cbRef.get();
+ if (cb != null) {
+ cb.onDisconnected();
+ }
+ }
+
+ mCallbacks.clear();
+ }
+
+ @Override
+ public ListenableFuture<View> requestCommunalView(Context context) {
+ if (DEBUG) {
+ Log.d(TAG, "Received request for communal view");
+ }
+ ListenableFuture<View> packageFuture =
+ CallbackToFutureAdapter.getFuture(completer -> {
+ completer.set(new CommunalSurfaceView(context, mMainExecutor, this));
+ return "CommunalSourceImpl::requestCommunalSurface::getCommunalSurface";
+ });
+
+ return packageFuture;
+ }
+
+ /**
+ * Called internally to request a new {@link android.view.SurfaceControlViewHost.SurfacePackage}
+ * for showing communal content.
+ *
+ * @param hostToken The HostToken necessary to generate a {@link SurfaceControlViewHost}.
+ * @param displayId The id of the display the surface will be shown on.
+ * @param width The width of the surface.
+ * @param height The height of the surface.
+ * @return A future that returns the resulting
+ * {@link android.view.SurfaceControlViewHost.SurfacePackage}.
+ */
+ protected ListenableFuture<SurfaceControlViewHost.SurfacePackage> requestCommunalSurface(
+ IBinder hostToken, int displayId, int width, int height) {
+ return CallbackToFutureAdapter.getFuture(completer -> {
+ mSourceProxy.getCommunalSurface(hostToken, width, height, displayId,
+ new ICommunalSurfaceCallback.Stub() {
+ @Override
+ public void onSurface(
+ SurfaceControlViewHost.SurfacePackage surfacePackage) {
+ completer.set(surfacePackage);
+ }
+ });
+ return "CommunalSourceImpl::requestCommunalSurface::getCommunalSurface";
+ });
+
+ }
+
+ @Override
+ public void addCallback(Callback callback) {
+ mCallbacks.add(new WeakReference<>(callback));
+
+ // If not connected anymore, immediately inform new callback of disconnection and remove.
+ if (!mConnected) {
+ onDisconnected();
+ }
+ }
+
+ @Override
+ public void removeCallback(Callback callback) {
+ mCallbacks.removeIf(el -> el.get() == callback);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/service/CommunalSourcePrimer.java b/packages/SystemUI/src/com/android/systemui/communal/service/CommunalSourcePrimer.java
new file mode 100644
index 0000000..bb3fef3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/service/CommunalSourcePrimer.java
@@ -0,0 +1,105 @@
+/*
+ * 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.communal.service;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.util.Log;
+
+import com.android.systemui.R;
+import com.android.systemui.SystemUI;
+import com.android.systemui.communal.CommunalSourceMonitor;
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.shared.communal.ICommunalSource;
+
+import java.util.concurrent.Executor;
+
+import javax.inject.Inject;
+
+/**
+ * The {@link CommunalSourcePrimer} is responsible for priming SystemUI with a pre-configured
+ * Communal source. The SystemUI service binds to the component to retrieve the
+ * {@link com.android.systemui.communal.CommunalSource}. {@link CommunalSourcePrimer} has no effect
+ * if there is no pre-defined value.
+ */
+@SysUISingleton
+public class CommunalSourcePrimer extends SystemUI {
+ private static final String TAG = "CommunalSourcePrimer";
+ private static final boolean DEBUG = false;
+ private final Context mContext;
+ private final Executor mMainExecutor;
+ private final CommunalSourceMonitor mMonitor;
+ private static final String ACTION_COMMUNAL_SOURCE = "android.intent.action.COMMUNAL_SOURCE";
+
+ private final ServiceConnection mConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ final ICommunalSource source = ICommunalSource.Stub.asInterface(service);
+ if (DEBUG) {
+ Log.d(TAG, "onServiceConnected. source;" + source);
+ }
+
+ mMonitor.setSource(
+ source != null ? new CommunalSourceImpl(mMainExecutor, source) : null);
+
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName className) {
+ }
+ };
+
+ @Inject
+ public CommunalSourcePrimer(Context context, @Main Executor mainExecutor,
+ CommunalSourceMonitor monitor) {
+ super(context);
+ mContext = context;
+ mMainExecutor = mainExecutor;
+ mMonitor = monitor;
+ }
+
+ @Override
+ public void start() {
+ if (DEBUG) {
+ Log.d(TAG, "start");
+ }
+ }
+
+ @Override
+ protected void onBootCompleted() {
+ super.onBootCompleted();
+ final String serviceComponent = mContext.getString(R.string.config_communalSourceComponent);
+
+ if (DEBUG) {
+ Log.d(TAG, "onBootCompleted. communal source component:" + serviceComponent);
+ }
+
+ if (serviceComponent == null || serviceComponent.isEmpty()) {
+ return;
+ }
+
+ final Intent intent = new Intent();
+ intent.setAction(ACTION_COMMUNAL_SOURCE);
+ intent.setComponent(ComponentName.unflattenFromString(serviceComponent));
+
+ mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/service/CommunalSurfaceView.java b/packages/SystemUI/src/com/android/systemui/communal/service/CommunalSurfaceView.java
new file mode 100644
index 0000000..67458a8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/service/CommunalSurfaceView.java
@@ -0,0 +1,96 @@
+/*
+ * 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.communal.service;
+
+import android.content.Context;
+import android.util.Log;
+import android.view.SurfaceControlViewHost;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+
+import androidx.annotation.NonNull;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+import java.util.concurrent.Executor;
+
+/**
+ * {@link CommunalSurfaceView} can be used to display remote surfaces returned by the
+ * {@link CommunalService}. The necessary information for the request are derived from the view's
+ * events from being attached to the parent container.
+ */
+public class CommunalSurfaceView extends SurfaceView {
+ private static final String TAG = "CommunalSurfaceView";
+ private static final boolean DEBUG = false;
+ private final Executor mMainExecutor;
+ private final CommunalSourceImpl mSource;
+
+ public CommunalSurfaceView(Context context, Executor executor, CommunalSourceImpl source) {
+ super(context);
+ mSource = source;
+ mMainExecutor = executor;
+
+ getHolder().addCallback(new SurfaceHolder.Callback() {
+ @Override
+ public void surfaceCreated(@NonNull SurfaceHolder holder) {
+ onSurfaceCreated();
+ }
+
+ @Override
+ public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width,
+ int height) {
+
+ }
+
+ @Override
+ public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
+
+ }
+ });
+ }
+
+ private void onSurfaceCreated() {
+ setWillNotDraw(false);
+
+ final ListenableFuture<SurfaceControlViewHost.SurfacePackage> surfaceFuture =
+ mSource.requestCommunalSurface(this.getHostToken(),
+ getDisplay().getDisplayId(), getMeasuredWidth(), getMeasuredHeight());
+
+ surfaceFuture.addListener(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ SurfaceControlViewHost.SurfacePackage surfacePackage = surfaceFuture.get();
+
+ if (DEBUG) {
+ Log.d(TAG, "Received surface package:" + surfacePackage);
+ }
+
+ if (surfacePackage != null) {
+ setChildSurfacePackage(surfacePackage);
+ setZOrderOnTop(true);
+ postInvalidate();
+ } else {
+ Log.e(TAG, "couldn't get the surface package");
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "An error occurred retrieving the future result:" + e);
+ }
+ }
+ }, mMainExecutor);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt
index c241c08..4104e31 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt
@@ -64,16 +64,12 @@
}
}
- override fun onStart() {
- super.onStart()
+ override fun onResume() {
+ super.onResume()
parent = requireViewById<ViewGroup>(R.id.global_actions_controls)
parent.alpha = 0f
uiController.show(parent, { finish() }, this)
- }
-
- override fun onResume() {
- super.onResume()
ControlsAnimations.enterAnimation(parent).start()
}
@@ -82,8 +78,8 @@
finish()
}
- override fun onStop() {
- super.onStop()
+ override fun onPause() {
+ super.onPause()
uiController.hide()
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java
index 596e440..17bd14c3 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java
@@ -20,11 +20,11 @@
import com.android.systemui.ImageWallpaper;
import com.android.systemui.SystemUIService;
+import com.android.systemui.communal.service.CommunalService;
import com.android.systemui.doze.DozeService;
import com.android.systemui.dump.SystemUIAuxiliaryDumpService;
import com.android.systemui.keyguard.KeyguardService;
import com.android.systemui.screenrecord.RecordingService;
-import com.android.systemui.screenshot.TakeScreenshotService;
import dagger.Binds;
import dagger.Module;
@@ -39,6 +39,12 @@
/** */
@Binds
@IntoMap
+ @ClassKey(CommunalService.class)
+ public abstract Service bindCommunalService(CommunalService service);
+
+ /** */
+ @Binds
+ @IntoMap
@ClassKey(DozeService.class)
public abstract Service bindDozeService(DozeService service);
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
index a94df9e..2d200e3 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
@@ -24,6 +24,8 @@
import android.content.Context;
import android.content.SharedPreferences;
import android.content.om.OverlayManager;
+import android.hardware.SensorManager;
+import android.hardware.devicestate.DeviceStateManager;
import android.hardware.display.AmbientDisplayConfiguration;
import android.hardware.display.ColorDisplayManager;
import android.os.Handler;
@@ -59,6 +61,7 @@
import com.android.systemui.doze.AlwaysOnDisplayPolicy;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardViewMediator;
+import com.android.systemui.keyguard.LifecycleScreenStatusProvider;
import com.android.systemui.model.SysUiState;
import com.android.systemui.navigationbar.NavigationBarA11yHelper;
import com.android.systemui.navigationbar.NavigationBarController;
@@ -77,6 +80,9 @@
import com.android.systemui.shared.system.DevicePolicyManagerWrapper;
import com.android.systemui.shared.system.TaskStackChangeListeners;
import com.android.systemui.shared.system.WindowManagerWrapper;
+import com.android.unfold.UnfoldTransitionFactory;
+import com.android.unfold.UnfoldTransitionProgressProvider;
+import com.android.unfold.config.UnfoldTransitionConfig;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShadeDepthController;
@@ -378,6 +384,37 @@
/** */
@Provides
@SysUISingleton
+ public UnfoldTransitionProgressProvider provideUnfoldTransitionProgressProvider(
+ Context context,
+ UnfoldTransitionConfig config,
+ LifecycleScreenStatusProvider screenStatusProvider,
+ DeviceStateManager deviceStateManager,
+ SensorManager sensorManager,
+ @Main Executor executor,
+ @Main Handler handler
+ ) {
+ return UnfoldTransitionFactory
+ .createUnfoldTransitionProgressProvider(
+ context,
+ config,
+ screenStatusProvider,
+ deviceStateManager,
+ sensorManager,
+ handler,
+ executor
+ );
+ }
+
+ /** */
+ @Provides
+ @SysUISingleton
+ public UnfoldTransitionConfig provideUnfoldTransitionConfig(Context context) {
+ return UnfoldTransitionFactory.createConfig(context);
+ }
+
+ /** */
+ @Provides
+ @SysUISingleton
public Choreographer providesChoreographer() {
return Choreographer.getInstance();
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
index 954ba79..4d1608f 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
@@ -41,6 +41,7 @@
import android.content.res.Resources;
import android.hardware.SensorManager;
import android.hardware.SensorPrivacyManager;
+import android.hardware.devicestate.DeviceStateManager;
import android.hardware.display.ColorDisplayManager;
import android.hardware.display.DisplayManager;
import android.hardware.face.FaceManager;
@@ -159,6 +160,12 @@
@Provides
@Singleton
+ static DeviceStateManager provideDeviceStateManager(Context context) {
+ return context.getSystemService(DeviceStateManager.class);
+ }
+
+ @Provides
+ @Singleton
static IActivityManager provideIActivityManager() {
return ActivityManager.getService();
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
index 1ed8819..30844cc 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
@@ -51,7 +51,11 @@
/**
* SystemUI objects that are injectable should go here.
*/
-@Module(includes = {RecentsModule.class, StatusBarModule.class, KeyguardModule.class})
+@Module(includes = {
+ RecentsModule.class,
+ StatusBarModule.class,
+ KeyguardModule.class,
+})
public abstract class SystemUIBinder {
/** Inject into AuthController. */
@Binds
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 556f956..b42d65a 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -31,6 +31,7 @@
import com.android.systemui.assist.AssistModule;
import com.android.systemui.biometrics.UdfpsHbmProvider;
import com.android.systemui.classifier.FalsingModule;
+import com.android.systemui.communal.dagger.CommunalModule;
import com.android.systemui.controls.dagger.ControlsModule;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.demomode.dagger.DemoModeModule;
@@ -97,6 +98,7 @@
AppOpsModule.class,
AssistModule.class,
ClockModule.class,
+ CommunalModule.class,
ControlsModule.class,
DemoModeModule.class,
FalsingModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/LifecycleScreenStatusProvider.kt b/packages/SystemUI/src/com/android/systemui/keyguard/LifecycleScreenStatusProvider.kt
new file mode 100644
index 0000000..d8905a0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/LifecycleScreenStatusProvider.kt
@@ -0,0 +1,44 @@
+/*
+ * 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.keyguard
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.unfold.updates.screen.ScreenStatusProvider
+import com.android.unfold.updates.screen.ScreenStatusProvider.ScreenListener
+import javax.inject.Inject
+
+@SysUISingleton
+class LifecycleScreenStatusProvider @Inject constructor(screenLifecycle: ScreenLifecycle) :
+ ScreenStatusProvider, ScreenLifecycle.Observer {
+
+ init {
+ screenLifecycle.addObserver(this)
+ }
+
+ private val listeners: MutableList<ScreenListener> = mutableListOf()
+
+ override fun removeCallback(listener: ScreenListener) {
+ listeners.remove(listener)
+ }
+
+ override fun addCallback(listener: ScreenListener) {
+ listeners.add(listener)
+ }
+
+ override fun onScreenTurnedOn() {
+ listeners.forEach(ScreenListener::onScreenTurnedOn)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt b/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt
index 2bf102f7..5ff624d 100644
--- a/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt
@@ -24,7 +24,6 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.media.dagger.MediaModule.KEYGUARD
import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.statusbar.FeatureFlags
import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.SysuiStatusBarStateController
@@ -45,7 +44,6 @@
private val bypassController: KeyguardBypassController,
private val statusBarStateController: SysuiStatusBarStateController,
private val notifLockscreenUserManager: NotificationLockscreenUserManager,
- private val featureFlags: FeatureFlags,
private val context: Context,
configurationController: ConfigurationController
) {
@@ -73,7 +71,7 @@
}
private fun updateResources() {
- useSplitShade = Utils.shouldUseSplitNotificationShade(featureFlags, context.resources)
+ useSplitShade = Utils.shouldUseSplitNotificationShade(context.resources)
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 683b5c3..fe2ac31 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -25,6 +25,8 @@
import static android.app.StatusBarManager.windowStateToString;
import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
+import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_GESTURE;
+import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.containsType;
@@ -290,7 +292,7 @@
@Override
public boolean shouldHideOnTouch() {
- return !mNotificationRemoteInputManager.getController().isRemoteInputActive();
+ return !mNotificationRemoteInputManager.isRemoteInputActive();
}
@Override
@@ -589,7 +591,7 @@
mDeviceProvisionedController.addCallback(mUserSetupListener);
mNotificationShadeDepthController.addListener(mDepthListener);
- setAccessibilityFloatingMenuModeIfNeeded();
+ updateAccessibilityButtonModeIfNeeded();
return barView;
}
@@ -1379,11 +1381,31 @@
updateSystemUiStateFlags(a11yFlags);
}
- private void setAccessibilityFloatingMenuModeIfNeeded() {
- if (QuickStepContract.isGesturalMode(mNavBarMode)) {
+ private void updateAccessibilityButtonModeIfNeeded() {
+ final int mode = Settings.Secure.getIntForUser(mContentResolver,
+ Settings.Secure.ACCESSIBILITY_BUTTON_MODE,
+ ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR, UserHandle.USER_CURRENT);
+
+ // ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU is compatible under gestural or non-gestural
+ // mode, so we don't need to update it.
+ if (mode == ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU) {
+ return;
+ }
+
+ // ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR is incompatible under gestural mode. Need to
+ // force update to ACCESSIBILITY_BUTTON_MODE_GESTURE.
+ if (QuickStepContract.isGesturalMode(mNavBarMode)
+ && mode == ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR) {
+ Settings.Secure.putIntForUser(mContentResolver,
+ Settings.Secure.ACCESSIBILITY_BUTTON_MODE, ACCESSIBILITY_BUTTON_MODE_GESTURE,
+ UserHandle.USER_CURRENT);
+ // ACCESSIBILITY_BUTTON_MODE_GESTURE is incompatible under non gestural mode. Need to
+ // force update to ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR.
+ } else if (!QuickStepContract.isGesturalMode(mNavBarMode)
+ && mode == ACCESSIBILITY_BUTTON_MODE_GESTURE) {
Settings.Secure.putIntForUser(mContentResolver,
Settings.Secure.ACCESSIBILITY_BUTTON_MODE,
- ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU, UserHandle.USER_CURRENT);
+ ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR, UserHandle.USER_CURRENT);
}
}
@@ -1511,7 +1533,7 @@
}
}
updateScreenPinningGestures();
- setAccessibilityFloatingMenuModeIfNeeded();
+ updateAccessibilityButtonModeIfNeeded();
if (!canShowSecondaryHandle()) {
resetSecondaryHandle();
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index b49f08c..808b7e2 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -18,7 +18,6 @@
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
-import static com.android.systemui.Dependency.EDGE_BACK_GESTURE_HANDLER_PROVIDER;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
@@ -352,7 +351,8 @@
mNavColorSampleMargin = getResources()
.getDimensionPixelSize(R.dimen.navigation_handle_sample_horizontal_margin);
- mEdgeBackGestureHandler = Dependency.get(EDGE_BACK_GESTURE_HANDLER_PROVIDER).get();
+ mEdgeBackGestureHandler = Dependency.get(EdgeBackGestureHandler.Factory.class)
+ .create(mContext);
mEdgeBackGestureHandler.setStateChangeCallback(this::updateStates);
mRegionSamplingHelper = new RegionSamplingHelper(this,
new RegionSamplingHelper.SamplingCallback() {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index 3fc6a3a..aaa3bf0 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -292,8 +292,8 @@
}
};
- @Inject
- public EdgeBackGestureHandler(Context context, OverviewProxyService overviewProxyService,
+
+ EdgeBackGestureHandler(Context context, OverviewProxyService overviewProxyService,
SysUiState sysUiState, PluginManager pluginManager, @Main Executor executor,
BroadcastDispatcher broadcastDispatcher, ProtoTracer protoTracer,
NavigationModeController navigationModeController, ViewConfiguration viewConfiguration,
@@ -942,6 +942,53 @@
proto.edgeBackGestureHandler.allowGesture = mAllowGesture;
}
+ /**
+ * Injectable instance to create a new EdgeBackGestureHandler.
+ *
+ * Necessary because we don't have good handling of per-display contexts at the moment. With
+ * this, you can pass in a specific context that knows what display it is in.
+ */
+ public static class Factory {
+ private final OverviewProxyService mOverviewProxyService;
+ private final SysUiState mSysUiState;
+ private final PluginManager mPluginManager;
+ private final Executor mExecutor;
+ private final BroadcastDispatcher mBroadcastDispatcher;
+ private final ProtoTracer mProtoTracer;
+ private final NavigationModeController mNavigationModeController;
+ private final ViewConfiguration mViewConfiguration;
+ private final WindowManager mWindowManager;
+ private final IWindowManager mWindowManagerService;
+ private final FalsingManager mFalsingManager;
+
+ @Inject
+ public Factory(OverviewProxyService overviewProxyService,
+ SysUiState sysUiState, PluginManager pluginManager, @Main Executor executor,
+ BroadcastDispatcher broadcastDispatcher, ProtoTracer protoTracer,
+ NavigationModeController navigationModeController,
+ ViewConfiguration viewConfiguration, WindowManager windowManager,
+ IWindowManager windowManagerService, FalsingManager falsingManager) {
+ mOverviewProxyService = overviewProxyService;
+ mSysUiState = sysUiState;
+ mPluginManager = pluginManager;
+ mExecutor = executor;
+ mBroadcastDispatcher = broadcastDispatcher;
+ mProtoTracer = protoTracer;
+ mNavigationModeController = navigationModeController;
+ mViewConfiguration = viewConfiguration;
+ mWindowManager = windowManager;
+ mWindowManagerService = windowManagerService;
+ mFalsingManager = falsingManager;
+ }
+
+ /** Construct a {@link EdgeBackGestureHandler}. */
+ public EdgeBackGestureHandler create(Context context) {
+ return new EdgeBackGestureHandler(context, mOverviewProxyService, mSysUiState,
+ mPluginManager, mExecutor, mBroadcastDispatcher, mProtoTracer,
+ mNavigationModeController, mViewConfiguration, mWindowManager,
+ mWindowManagerService, mFalsingManager);
+ }
+ }
private static class LogArray extends ArrayDeque<String> {
private final int mLength;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 2d7bfcd..d56fe48 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -46,7 +46,6 @@
import com.android.systemui.qs.customize.QSCustomizerController;
import com.android.systemui.qs.dagger.QSFragmentComponent;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
@@ -113,7 +112,6 @@
private QuickQSPanelController mQuickQSPanelController;
private QSCustomizerController mQSCustomizerController;
private ScrollListener mScrollListener;
- private FeatureFlags mFeatureFlags;
/**
* When true, QS will translate from outside the screen. It will be clipped with parallax
* otherwise.
@@ -137,7 +135,7 @@
StatusBarStateController statusBarStateController, CommandQueue commandQueue,
QSDetailDisplayer qsDetailDisplayer, @Named(QS_PANEL) MediaHost qsMediaHost,
@Named(QUICK_QS_PANEL) MediaHost qqsMediaHost,
- QSFragmentComponent.Factory qsComponentFactory, FeatureFlags featureFlags,
+ QSFragmentComponent.Factory qsComponentFactory,
FalsingManager falsingManager) {
mRemoteInputQuickSettingsDisabler = remoteInputQsDisabler;
mInjectionInflater = injectionInflater;
@@ -148,7 +146,6 @@
mQsComponentFactory = qsComponentFactory;
commandQueue.observe(getLifecycle(), this);
mHost = qsTileHost;
- mFeatureFlags = featureFlags;
mFalsingManager = falsingManager;
mStatusBarStateController = statusBarStateController;
}
@@ -377,7 +374,7 @@
!mQsDisabled && expandVisually ? View.VISIBLE : View.INVISIBLE);
mQsDragHandler.setVisibility((mQsExpanded || !keyguardShowing || mHeaderAnimating
|| mShowCollapsedOnKeyguard)
- && Utils.shouldUseSplitNotificationShade(mFeatureFlags, getResources())
+ && Utils.shouldUseSplitNotificationShade(getResources())
? View.VISIBLE
: View.GONE);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index f20a2db..0c65510 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -55,6 +55,8 @@
private static final String TAG = "QSPanel";
protected final Context mContext;
+ private final int mMediaTopMargin;
+ private final int mMediaTotalBottomMargin;
/**
* The index where the content starts that needs to be moved between parents
@@ -98,13 +100,14 @@
protected LinearLayout mHorizontalContentContainer;
protected QSTileLayout mTileLayout;
- private int mMediaTotalBottomMargin;
public QSPanel(Context context, AttributeSet attrs) {
super(context, attrs);
mUsingMediaPlayer = useQsMediaPlayer(context);
mMediaTotalBottomMargin = getResources().getDimensionPixelSize(
R.dimen.quick_settings_bottom_margin_media);
+ mMediaTopMargin = getResources().getDimensionPixelSize(
+ R.dimen.qs_tile_margin_vertical);
mContext = context;
setOrientation(VERTICAL);
@@ -326,7 +329,7 @@
private void updateHorizontalLinearLayoutMargins() {
if (mHorizontalLinearLayout != null && !displayMediaMarginsOnMedia()) {
LayoutParams lp = (LayoutParams) mHorizontalLinearLayout.getLayoutParams();
- lp.bottomMargin = mMediaTotalBottomMargin - getPaddingBottom();
+ lp.bottomMargin = Math.max(mMediaTotalBottomMargin - getPaddingBottom(), 0);
mHorizontalLinearLayout.setLayoutParams(lp);
}
}
@@ -341,6 +344,13 @@
return true;
}
+ /**
+ * @return true if the media view needs margin on the top to separate it from the qs tiles
+ */
+ protected boolean mediaNeedsTopMargin() {
+ return false;
+ }
+
private boolean needsDynamicRowsAndColumns() {
return true;
}
@@ -405,7 +415,9 @@
// necessary if the view isn't horizontal, since otherwise the padding is
// carried in the parent of this view (to ensure correct vertical alignment)
layoutParams.bottomMargin = !horizontal || displayMediaMarginsOnMedia()
- ? mMediaTotalBottomMargin - getPaddingBottom() : 0;
+ ? Math.max(mMediaTotalBottomMargin - getPaddingBottom(), 0) : 0;
+ layoutParams.topMargin = mediaNeedsTopMargin() && !horizontal
+ ? mMediaTopMargin : 0;
}
}
@@ -673,6 +685,7 @@
mTileLayout.setMaxColumns(horizontal ? 2 : 4);
}
updateMargins(mediaHostView);
+ mHorizontalLinearLayout.setVisibility(horizontal ? View.VISIBLE : View.GONE);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
index 7cbd45b..f3d071e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
@@ -41,7 +41,6 @@
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.settings.brightness.BrightnessController;
import com.android.systemui.settings.brightness.BrightnessSlider;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.policy.BrightnessMirrorController;
import com.android.systemui.tuner.TunerService;
@@ -102,10 +101,9 @@
QSTileRevealController.Factory qsTileRevealControllerFactory,
DumpManager dumpManager, MetricsLogger metricsLogger, UiEventLogger uiEventLogger,
QSLogger qsLogger, BrightnessController.Factory brightnessControllerFactory,
- BrightnessSlider.Factory brightnessSliderFactory, FalsingManager falsingManager,
- FeatureFlags featureFlags) {
+ BrightnessSlider.Factory brightnessSliderFactory, FalsingManager falsingManager) {
super(view, qstileHost, qsCustomizerController, usingMediaPlayer, mediaHost,
- metricsLogger, uiEventLogger, qsLogger, dumpManager, featureFlags);
+ metricsLogger, uiEventLogger, qsLogger, dumpManager);
mQsSecurityFooter = qsSecurityFooter;
mTunerService = tunerService;
mQsCustomizerController = qsCustomizerController;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
index d2d3b91..0da4814 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
@@ -35,7 +35,6 @@
import com.android.systemui.qs.customize.QSCustomizerController;
import com.android.systemui.qs.external.CustomTile;
import com.android.systemui.qs.logging.QSLogger;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.util.Utils;
import com.android.systemui.util.ViewController;
import com.android.systemui.util.animation.DisappearParameters;
@@ -67,7 +66,6 @@
private final UiEventLogger mUiEventLogger;
private final QSLogger mQSLogger;
private final DumpManager mDumpManager;
- private final FeatureFlags mFeatureFlags;
protected final ArrayList<TileRecord> mRecords = new ArrayList<>();
protected boolean mShouldUseSplitNotificationShade;
@@ -85,7 +83,7 @@
@Override
public void onConfigurationChange(Configuration newConfig) {
mShouldUseSplitNotificationShade =
- Utils.shouldUseSplitNotificationShade(mFeatureFlags, getResources());
+ Utils.shouldUseSplitNotificationShade(getResources());
if (newConfig.orientation != mLastOrientation) {
mLastOrientation = newConfig.orientation;
onScreenRotated();
@@ -118,8 +116,7 @@
MetricsLogger metricsLogger,
UiEventLogger uiEventLogger,
QSLogger qsLogger,
- DumpManager dumpManager,
- FeatureFlags featureFlags
+ DumpManager dumpManager
) {
super(view);
mHost = host;
@@ -130,9 +127,8 @@
mUiEventLogger = uiEventLogger;
mQSLogger = qsLogger;
mDumpManager = dumpManager;
- mFeatureFlags = featureFlags;
mShouldUseSplitNotificationShade =
- Utils.shouldUseSplitNotificationShade(mFeatureFlags, getResources());
+ Utils.shouldUseSplitNotificationShade(getResources());
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index 567764e..f1c1e12 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -66,6 +66,11 @@
}
@Override
+ protected boolean mediaNeedsTopMargin() {
+ return true;
+ }
+
+ @Override
protected void updatePadding() {
// QS Panel is setting a top padding by default, which we don't need.
}
@@ -174,7 +179,6 @@
LayoutParams.WRAP_CONTENT);
setLayoutParams(lp);
setMaxColumns(4);
- mLastRowPadding = true;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
index 61e9e689..74cd50c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
@@ -29,7 +29,6 @@
import com.android.systemui.qs.customize.QSCustomizerController;
import com.android.systemui.qs.dagger.QSScope;
import com.android.systemui.qs.logging.QSLogger;
-import com.android.systemui.statusbar.FeatureFlags;
import java.util.ArrayList;
import java.util.List;
@@ -58,11 +57,11 @@
@Named(QS_USING_MEDIA_PLAYER) boolean usingMediaPlayer,
@Named(QUICK_QS_PANEL) MediaHost mediaHost,
MetricsLogger metricsLogger, UiEventLogger uiEventLogger, QSLogger qsLogger,
- DumpManager dumpManager, FeatureFlags featureFlags,
+ DumpManager dumpManager,
QuickQSBrightnessController quickQSBrightnessController
) {
super(view, qsTileHost, qsCustomizerController, usingMediaPlayer, mediaHost, metricsLogger,
- uiEventLogger, qsLogger, dumpManager, featureFlags);
+ uiEventLogger, qsLogger, dumpManager);
mBrightnessController = quickQSBrightnessController;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index e82f843..0004759 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -32,6 +32,8 @@
import android.widget.LinearLayout;
import android.widget.Space;
+import androidx.annotation.NonNull;
+
import com.android.settingslib.Utils;
import com.android.systemui.BatteryMeterView;
import com.android.systemui.R;
@@ -42,6 +44,8 @@
import com.android.systemui.statusbar.policy.Clock;
import com.android.systemui.statusbar.policy.VariableDateView;
+import java.util.List;
+
/**
* View that contains the top-most bits of the QS panel (primarily the status bar with date, time,
* battery, carrier info and privacy icons) and also contains the {@link QuickQSPanel}.
@@ -89,18 +93,13 @@
private float mKeyguardExpansionFraction;
private int mTextColorPrimary = Color.TRANSPARENT;
private int mTopViewMeasureHeight;
- private boolean mProviderModel;
- private final String mMobileSlotName;
- private final String mNoCallingSlotName;
- private final String mCallStrengthSlotName;
+ @NonNull
+ private List<String> mRssiIgnoredSlots;
+ private boolean mIsSingleCarrier;
public QuickStatusBarHeader(Context context, AttributeSet attrs) {
super(context, attrs);
- mMobileSlotName = context.getString(com.android.internal.R.string.status_bar_mobile);
- mNoCallingSlotName = context.getString(com.android.internal.R.string.status_bar_no_calling);
- mCallStrengthSlotName =
- context.getString(com.android.internal.R.string.status_bar_call_strength);
}
/**
@@ -153,9 +152,9 @@
void onAttach(TintedIconManager iconManager,
QSExpansionPathInterpolator qsExpansionPathInterpolator,
- boolean providerModel) {
- mProviderModel = providerModel;
+ List<String> rssiIgnoredSlots) {
mTintedIconManager = iconManager;
+ mRssiIgnoredSlots = rssiIgnoredSlots;
int fillColor = Utils.getColorAttrDefaultColor(getContext(),
android.R.attr.textColorPrimary);
@@ -166,6 +165,15 @@
updateAnimators();
}
+ void setIsSingleCarrier(boolean isSingleCarrier) {
+ mIsSingleCarrier = isSingleCarrier;
+ updateAlphaAnimator();
+ }
+
+ public QuickQSPanel getHeaderQsPanel() {
+ return mHeaderQsPanel;
+ }
+
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
@@ -274,13 +282,9 @@
.setListener(new TouchAnimator.ListenerAdapter() {
@Override
public void onAnimationAtEnd() {
- // TODO(b/185580157): Remove the mProviderModel if the mobile slot can be
- // hidden in Provider model.
- if (mProviderModel) {
- mIconContainer.addIgnoredSlot(mNoCallingSlotName);
- mIconContainer.addIgnoredSlot(mCallStrengthSlotName);
- } else {
- mIconContainer.addIgnoredSlot(mMobileSlotName);
+ super.onAnimationAtEnd();
+ if (!mIsSingleCarrier) {
+ mIconContainer.addIgnoredSlots(mRssiIgnoredSlots);
}
// Make it gone so there's enough room for carrier names
mClockDateView.setVisibility(View.GONE);
@@ -288,30 +292,21 @@
@Override
public void onAnimationStarted() {
- if (mProviderModel) {
- mIconContainer.addIgnoredSlot(mNoCallingSlotName);
- mIconContainer.addIgnoredSlot(mCallStrengthSlotName);
- } else {
- mIconContainer.addIgnoredSlot(mMobileSlotName);
- }
-
mClockDateView.setVisibility(View.VISIBLE);
mClockDateView.setFreezeSwitching(true);
setSeparatorVisibility(false);
+ if (!mIsSingleCarrier) {
+ mIconContainer.addIgnoredSlots(mRssiIgnoredSlots);
+ }
}
@Override
public void onAnimationAtStart() {
super.onAnimationAtStart();
- if (mProviderModel) {
- mIconContainer.removeIgnoredSlot(mNoCallingSlotName);
- mIconContainer.removeIgnoredSlot(mCallStrengthSlotName);
- } else {
- mIconContainer.removeIgnoredSlot(mMobileSlotName);
- }
-
mClockDateView.setFreezeSwitching(false);
setSeparatorVisibility(mShowClockIconsSeparator);
+ // In QQS we never ignore RSSI.
+ mIconContainer.removeIgnoredSlots(mRssiIgnoredSlots);
}
});
mAlphaAnimator = builder.build();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
index 396f334..1343839 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
@@ -44,7 +44,6 @@
import com.android.systemui.statusbar.policy.VariableDateViewController;
import com.android.systemui.util.ViewController;
-import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
@@ -80,6 +79,9 @@
private boolean mMicCameraIndicatorsEnabled;
private boolean mLocationIndicatorsEnabled;
private boolean mPrivacyChipLogged;
+ private final String mCameraSlot;
+ private final String mMicSlot;
+ private final String mLocationSlot;
private SysuiColorExtractor mColorExtractor;
private ColorExtractor.OnColorsChangedListener mOnColorsChangedListener;
@@ -108,8 +110,7 @@
}
private void update() {
- StatusIconContainer iconContainer = mView.requireViewById(R.id.statusIcons);
- iconContainer.setIgnoredSlots(getIgnoredIconSlots());
+ updatePrivacyIconSlots();
setChipVisibility(!mPrivacyChip.getPrivacyList().isEmpty());
}
};
@@ -165,7 +166,7 @@
mView.requireViewById(R.id.date_clock)
);
- mIconManager = new StatusBarIconController.TintedIconManager(mIconContainer, mFeatureFlags);
+ mIconManager = new StatusBarIconController.TintedIconManager(mIconContainer, featureFlags);
mDemoModeReceiver = new ClockDemoModeReceiver(mClockView);
mColorExtractor = colorExtractor;
mOnColorsChangedListener = (extractor, which) -> {
@@ -173,6 +174,10 @@
mClockView.onColorsChanged(lightTheme);
};
mColorExtractor.addOnColorsChangedListener(mOnColorsChangedListener);
+
+ mCameraSlot = getResources().getString(com.android.internal.R.string.status_bar_camera);
+ mMicSlot = getResources().getString(com.android.internal.R.string.status_bar_microphone);
+ mLocationSlot = getResources().getString(com.android.internal.R.string.status_bar_location);
}
@Override
@@ -183,14 +188,30 @@
mLocationIndicatorsEnabled = mPrivacyItemController.getLocationAvailable();
// Ignore privacy icons because they show in the space above QQS
- mIconContainer.setIgnoredSlots(getIgnoredIconSlots());
+ updatePrivacyIconSlots();
mIconContainer.setShouldRestrictIcons(false);
mStatusBarIconController.addIconGroup(mIconManager);
setChipVisibility(mPrivacyChip.getVisibility() == View.VISIBLE);
- mView.onAttach(mIconManager, mQSExpansionPathInterpolator,
- mFeatureFlags.isCombinedStatusBarSignalIconsEnabled());
+ mView.setIsSingleCarrier(mQSCarrierGroupController.isSingleCarrier());
+ mQSCarrierGroupController
+ .setOnSingleCarrierChangedListener(mView::setIsSingleCarrier);
+
+ List<String> rssiIgnoredSlots;
+
+ if (mFeatureFlags.isCombinedStatusBarSignalIconsEnabled()) {
+ rssiIgnoredSlots = List.of(
+ getResources().getString(com.android.internal.R.string.status_bar_no_calling),
+ getResources().getString(com.android.internal.R.string.status_bar_call_strength)
+ );
+ } else {
+ rssiIgnoredSlots = List.of(
+ getResources().getString(com.android.internal.R.string.status_bar_mobile)
+ );
+ }
+
+ mView.onAttach(mIconManager, mQSExpansionPathInterpolator, rssiIgnoredSlots);
mDemoModeController.addCallback(mDemoModeReceiver);
@@ -203,6 +224,7 @@
mColorExtractor.removeOnColorsChangedListener(mOnColorsChangedListener);
mPrivacyChip.setOnClickListener(null);
mStatusBarIconController.removeIconGroup(mIconManager);
+ mQSCarrierGroupController.setOnSingleCarrierChangedListener(null);
mDemoModeController.removeCallback(mDemoModeReceiver);
setListening(false);
}
@@ -250,21 +272,25 @@
mView.setChipVisibility(chipVisible);
}
- private List<String> getIgnoredIconSlots() {
- ArrayList<String> ignored = new ArrayList<>();
+ private void updatePrivacyIconSlots() {
if (getChipEnabled()) {
if (mMicCameraIndicatorsEnabled) {
- ignored.add(mView.getResources().getString(
- com.android.internal.R.string.status_bar_camera));
- ignored.add(mView.getResources().getString(
- com.android.internal.R.string.status_bar_microphone));
+ mIconContainer.addIgnoredSlot(mCameraSlot);
+ mIconContainer.addIgnoredSlot(mMicSlot);
+ } else {
+ mIconContainer.removeIgnoredSlot(mCameraSlot);
+ mIconContainer.removeIgnoredSlot(mMicSlot);
}
if (mLocationIndicatorsEnabled) {
- ignored.add(mView.getResources().getString(
- com.android.internal.R.string.status_bar_location));
+ mIconContainer.addIgnoredSlot(mLocationSlot);
+ } else {
+ mIconContainer.removeIgnoredSlot(mLocationSlot);
}
+ } else {
+ mIconContainer.removeIgnoredSlot(mCameraSlot);
+ mIconContainer.removeIgnoredSlot(mMicSlot);
+ mIconContainer.removeIgnoredSlot(mLocationSlot);
}
- return ignored;
}
private boolean getChipEnabled() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
index 2b96a34..1a890a7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -31,7 +31,6 @@
protected int mCellMarginVertical;
protected int mSidePadding;
protected int mRows = 1;
- protected boolean mLastRowPadding = false;
protected final ArrayList<TileRecord> mRecords = new ArrayList<>();
protected boolean mListening;
@@ -168,9 +167,7 @@
}
int height = (mCellHeight + mCellMarginVertical) * mRows;
- if (!mLastRowPadding) {
- height -= mCellMarginVertical;
- }
+ height -= mCellMarginVertical;
if (height < 0) height = 0;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrier.java b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrier.java
index d6fa216..32ac733 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrier.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrier.java
@@ -25,6 +25,8 @@
import android.widget.LinearLayout;
import android.widget.TextView;
+import androidx.annotation.VisibleForTesting;
+
import com.android.settingslib.Utils;
import com.android.settingslib.graph.SignalDrawable;
import com.android.systemui.R;
@@ -37,8 +39,10 @@
private TextView mCarrierText;
private ImageView mMobileSignal;
private ImageView mMobileRoaming;
+ private View mSpacer;
private CellSignalState mLastSignalState;
private boolean mProviderModelInitialized = false;
+ private boolean mIsSingleCarrier;
public QSCarrier(Context context) {
super(context);
@@ -63,18 +67,25 @@
mMobileRoaming = findViewById(R.id.mobile_roaming);
mMobileSignal = findViewById(R.id.mobile_signal);
mCarrierText = findViewById(R.id.qs_carrier_text);
+ mSpacer = findViewById(R.id.spacer);
}
/**
* Update the state of this view
* @param state the current state of the signal for this view
+ * @param isSingleCarrier whether there is a single carrier being shown in the container
* @return true if the state was actually changed
*/
- public boolean updateState(CellSignalState state) {
- if (Objects.equals(state, mLastSignalState)) return false;
+ public boolean updateState(CellSignalState state, boolean isSingleCarrier) {
+ if (Objects.equals(state, mLastSignalState) && isSingleCarrier == mIsSingleCarrier) {
+ return false;
+ }
mLastSignalState = state;
- mMobileGroup.setVisibility(state.visible ? View.VISIBLE : View.GONE);
- if (state.visible) {
+ mIsSingleCarrier = isSingleCarrier;
+ final boolean visible = state.visible && !isSingleCarrier;
+ mMobileGroup.setVisibility(visible ? View.VISIBLE : View.GONE);
+ mSpacer.setVisibility(isSingleCarrier ? View.VISIBLE : View.GONE);
+ if (visible) {
mMobileRoaming.setVisibility(state.roaming ? View.VISIBLE : View.GONE);
ColorStateList colorStateList = Utils.getColorAttr(mContext,
android.R.attr.textColorPrimary);
@@ -125,6 +136,11 @@
com.android.settingslib.R.string.not_default_data_content_description));
}
+ @VisibleForTesting
+ View getRSSIView() {
+ return mMobileGroup;
+ }
+
public void setCarrierText(CharSequence text) {
mCarrierText.setText(text);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java
index f23c058..67c4d33 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java
@@ -37,6 +37,7 @@
import com.android.settingslib.AccessibilityContentDescriptions;
import com.android.settingslib.mobile.TelephonyIcons;
import com.android.systemui.R;
+import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
@@ -62,7 +63,8 @@
private final NetworkController mNetworkController;
private final CarrierTextManager mCarrierTextManager;
private final TextView mNoSimTextView;
- private final H mMainHandler;
+ // Non final for testing
+ private H mMainHandler;
private final Callback mCallback;
private boolean mListening;
private final CellSignalState[] mInfos =
@@ -74,6 +76,11 @@
private final boolean mProviderModel;
private final CarrierConfigTracker mCarrierConfigTracker;
+ private boolean mIsSingleCarrier;
+ private OnSingleCarrierChangedListener mOnSingleCarrierChangedListener;
+
+ private final SlotIndexResolver mSlotIndexResolver;
+
private final NetworkController.SignalCallback mSignalCallback =
new NetworkController.SignalCallback() {
@Override
@@ -207,7 +214,8 @@
@Background Handler bgHandler, @Main Looper mainLooper,
NetworkController networkController,
CarrierTextManager.Builder carrierTextManagerBuilder, Context context,
- CarrierConfigTracker carrierConfigTracker, FeatureFlags featureFlags) {
+ CarrierConfigTracker carrierConfigTracker, FeatureFlags featureFlags,
+ SlotIndexResolver slotIndexResolver) {
if (featureFlags.isCombinedStatusBarSignalIconsEnabled()) {
mProviderModel = true;
@@ -222,6 +230,7 @@
.setShowMissingSim(false)
.build();
mCarrierConfigTracker = carrierConfigTracker;
+ mSlotIndexResolver = slotIndexResolver;
View.OnClickListener onClickListener = v -> {
if (!v.isVisibleToUser()) {
return;
@@ -256,6 +265,7 @@
.toString();
mCarrierGroups[i].setOnClickListener(onClickListener);
}
+ mIsSingleCarrier = computeIsSingleCarrier();
view.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
view.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
@@ -272,10 +282,24 @@
@VisibleForTesting
protected int getSlotIndex(int subscriptionId) {
- return SubscriptionManager.getSlotIndex(subscriptionId);
+ return mSlotIndexResolver.getSlotIndex(subscriptionId);
}
- private boolean isSingleCarrier() {
+ /**
+ * Sets a {@link OnSingleCarrierChangedListener}.
+ *
+ * This will get notified when the number of carriers changes between 1 and "not one".
+ * @param listener
+ */
+ public void setOnSingleCarrierChangedListener(OnSingleCarrierChangedListener listener) {
+ mOnSingleCarrierChangedListener = listener;
+ }
+
+ public boolean isSingleCarrier() {
+ return mIsSingleCarrier;
+ }
+
+ private boolean computeIsSingleCarrier() {
int carrierCount = 0;
for (int i = 0; i < SIM_SLOTS; i++) {
@@ -315,7 +339,9 @@
return;
}
- if (isSingleCarrier()) {
+ boolean singleCarrier = computeIsSingleCarrier();
+
+ if (singleCarrier) {
for (int i = 0; i < SIM_SLOTS; i++) {
if (mInfos[i].visible
&& mInfos[i].mobileSignalIconId == R.drawable.ic_qs_sim_card) {
@@ -326,7 +352,7 @@
}
for (int i = 0; i < SIM_SLOTS; i++) {
- mCarrierGroups[i].updateState(mInfos[i]);
+ mCarrierGroups[i].updateState(mInfos[i], singleCarrier);
}
mCarrierDividers[0].setVisibility(
@@ -337,6 +363,12 @@
mCarrierDividers[1].setVisibility(
(mInfos[1].visible && mInfos[2].visible)
|| (mInfos[0].visible && mInfos[2].visible) ? View.VISIBLE : View.GONE);
+ if (mIsSingleCarrier != singleCarrier) {
+ mIsSingleCarrier = singleCarrier;
+ if (mOnSingleCarrierChangedListener != null) {
+ mOnSingleCarrierChangedListener.onSingleCarrierChanged(singleCarrier);
+ }
+ }
}
@MainThread
@@ -433,12 +465,14 @@
private final Context mContext;
private final CarrierConfigTracker mCarrierConfigTracker;
private final FeatureFlags mFeatureFlags;
+ private final SlotIndexResolver mSlotIndexResolver;
@Inject
public Builder(ActivityStarter activityStarter, @Background Handler handler,
@Main Looper looper, NetworkController networkController,
CarrierTextManager.Builder carrierTextControllerBuilder, Context context,
- CarrierConfigTracker carrierConfigTracker, FeatureFlags featureFlags) {
+ CarrierConfigTracker carrierConfigTracker, FeatureFlags featureFlags,
+ SlotIndexResolver slotIndexResolver) {
mActivityStarter = activityStarter;
mHandler = handler;
mLooper = looper;
@@ -447,6 +481,7 @@
mContext = context;
mCarrierConfigTracker = carrierConfigTracker;
mFeatureFlags = featureFlags;
+ mSlotIndexResolver = slotIndexResolver;
}
public Builder setQSCarrierGroup(QSCarrierGroup view) {
@@ -457,7 +492,43 @@
public QSCarrierGroupController build() {
return new QSCarrierGroupController(mView, mActivityStarter, mHandler, mLooper,
mNetworkController, mCarrierTextControllerBuilder, mContext,
- mCarrierConfigTracker, mFeatureFlags);
+ mCarrierConfigTracker, mFeatureFlags, mSlotIndexResolver);
+ }
+ }
+
+ /**
+ * Notify when the state changes from 1 carrier to "not one" and viceversa
+ */
+ @FunctionalInterface
+ public interface OnSingleCarrierChangedListener {
+ void onSingleCarrierChanged(boolean isSingleCarrier);
+ }
+
+ /**
+ * Interface for resolving slot index from subscription ID.
+ */
+ @FunctionalInterface
+ public interface SlotIndexResolver {
+ /**
+ * Get slot index for given sub id.
+ */
+ int getSlotIndex(int subscriptionId);
+ }
+
+ /**
+ * Default implementation for {@link SlotIndexResolver}.
+ *
+ * It retrieves the slot index using {@link SubscriptionManager#getSlotIndex}.
+ */
+ @SysUISingleton
+ public static class SubscriptionManagerSlotIndexResolver implements SlotIndexResolver {
+
+ @Inject
+ public SubscriptionManagerSlotIndexResolver() {}
+
+ @Override
+ public int getSlotIndex(int subscriptionId) {
+ return SubscriptionManager.getSlotIndex(subscriptionId);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
index 34aac49..36a1910 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
@@ -145,5 +145,4 @@
static boolean providesQSUsingMediaPlayer(Context context) {
return useQsMediaPlayer(context);
}
-
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
index de3be78..6d1bbee 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
@@ -89,5 +89,4 @@
/** */
@Binds
QSHost provideQsHost(QSTileHost controllerImpl);
-
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
index c24b5ad..92ae88d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
@@ -53,6 +53,7 @@
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.qs.tiles.dialog.InternetDialogFactory;
import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.NetworkController.AccessPointController;
import com.android.systemui.statusbar.policy.NetworkController.IconState;
import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
@@ -69,6 +70,7 @@
private static final Intent WIFI_SETTINGS = new Intent(Settings.ACTION_WIFI_SETTINGS);
protected final NetworkController mController;
+ private final AccessPointController mAccessPointController;
private final DataUsageController mDataController;
// The last updated tile state, 0: mobile, 1: wifi, 2: ethernet.
private int mLastTileState = -1;
@@ -88,6 +90,7 @@
ActivityStarter activityStarter,
QSLogger qsLogger,
NetworkController networkController,
+ AccessPointController accessPointController,
InternetDialogFactory internetDialogFactory
) {
super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
@@ -95,6 +98,7 @@
mInternetDialogFactory = internetDialogFactory;
mHandler = mainHandler;
mController = networkController;
+ mAccessPointController = accessPointController;
mDataController = mController.getMobileDataController();
mController.observe(getLifecycle(), mSignalCallback);
}
@@ -118,9 +122,8 @@
@Override
protected void handleClick(@Nullable View view) {
- mHandler.post(() -> {
- mInternetDialogFactory.create(true);
- });
+ boolean canConfigMobileData = mAccessPointController.canConfigMobileData();
+ mHandler.post(() -> mInternetDialogFactory.create(true, canConfigMobileData));
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
index ab81ac1..82b6c0c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
@@ -153,25 +153,9 @@
});
}
- @Nullable
- private CharSequence getServiceLabelSafe() {
- try {
- return mController.getWalletClient().getServiceLabel();
- } catch (RuntimeException e) {
- Log.e(TAG, "Failed to get the service label safely, recreating wallet client", e);
- mController.reCreateWalletClient();
- try {
- return mController.getWalletClient().getServiceLabel();
- } catch (RuntimeException e2) {
- Log.e(TAG, "The QAW service label is broken.", e2);
- return null;
- }
- }
- }
-
@Override
protected void handleUpdateState(State state, Object arg) {
- CharSequence label = getServiceLabelSafe();
+ CharSequence label = mController.getWalletClient().getServiceLabel();
state.label = label == null ? mLabel : label;
state.contentDescription = state.label;
Drawable tileIcon = mController.getWalletClient().getTileIcon();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
index 86fb658..ce1c2fd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
@@ -126,6 +126,7 @@
private int mListMaxHeight;
private int mDefaultDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
private boolean mIsProgressBarVisible;
+ private boolean mCanConfigMobileData;
private final ViewTreeObserver.OnGlobalLayoutListener mInternetListLayoutListener = () -> {
// Set max height for list
@@ -137,7 +138,7 @@
};
public InternetDialog(Context context, InternetDialogFactory internetDialogFactory,
- InternetDialogController internetDialogController,
+ InternetDialogController internetDialogController, boolean canConfigMobileData,
boolean aboveStatusBar, UiEventLogger uiEventLogger, @Main Handler handler) {
super(context, R.style.Theme_SystemUI_Dialog_Internet);
if (DEBUG) {
@@ -151,6 +152,7 @@
mDefaultDataSubId = mInternetDialogController.getDefaultDataSubscriptionId();
mTelephonyManager = mInternetDialogController.getTelephonyManager();
mWifiManager = mInternetDialogController.getWifiManager();
+ mCanConfigMobileData = canConfigMobileData;
mLayoutManager = new LinearLayoutManager(mContext) {
@Override
@@ -317,8 +319,13 @@
mMobileDataToggle.setChecked(mInternetDialogController.isMobileDataEnabled());
mMobileNetworkLayout.setVisibility(View.VISIBLE);
mMobileTitleText.setText(getMobileNetworkTitle());
- mMobileSummaryText.setText(
- Html.fromHtml(getMobileNetworkSummary(), Html.FROM_HTML_MODE_LEGACY));
+ if (!TextUtils.isEmpty(getMobileNetworkSummary())) {
+ mMobileSummaryText.setText(
+ Html.fromHtml(getMobileNetworkSummary(), Html.FROM_HTML_MODE_LEGACY));
+ mMobileSummaryText.setVisibility(View.VISIBLE);
+ } else {
+ mMobileSummaryText.setVisibility(View.GONE);
+ }
mSignalIcon.setImageDrawable(getSignalStrengthDrawable());
int titleColor = isCellularNetwork ? mContext.getColor(
R.color.connected_network_primary_color) : Utils.getColorAttrDefaultColor(
@@ -329,6 +336,8 @@
mMobileTitleText.setTextColor(titleColor);
mMobileSummaryText.setTextColor(summaryColor);
mMobileNetworkLayout.setBackground(isCellularNetwork ? mBackgroundOn : null);
+
+ mMobileDataToggle.setVisibility(mCanConfigMobileData ? View.VISIBLE : View.INVISIBLE);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
index e352827..edab33a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
@@ -36,6 +36,8 @@
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.provider.Settings;
+import android.telephony.AccessNetworkConstants;
+import android.telephony.NetworkRegistrationInfo;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.SubscriptionInfo;
@@ -115,7 +117,7 @@
private MobileMappings.Config mConfig = null;
private Executor mExecutor;
private AccessPointController mAccessPointController;
- private IntentFilter mWifiStateFilter;
+ private IntentFilter mConnectionStateFilter;
private InternetDialogCallback mCallback;
private List<WifiEntry> mWifiEntry;
private UiEventLogger mUiEventLogger;
@@ -171,8 +173,10 @@
mSubscriptionManager = subscriptionManager;
mBroadcastDispatcher = broadcastDispatcher;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
- mWifiStateFilter = new IntentFilter(WifiManager.NETWORK_STATE_CHANGED_ACTION);
- mWifiStateFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
+ mConnectionStateFilter = new IntentFilter();
+ mConnectionStateFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+ mConnectionStateFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
+ mConnectionStateFilter.addAction(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
mUiEventLogger = uiEventLogger;
mActivityStarter = starter;
mAccessPointController = accessPointController;
@@ -186,12 +190,16 @@
mCallback = callback;
mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateCallback);
mAccessPointController.addAccessPointCallback(this);
- mBroadcastDispatcher.registerReceiver(mWifiStateReceiver, mWifiStateFilter, mExecutor);
+ mBroadcastDispatcher.registerReceiver(mConnectionStateReceiver, mConnectionStateFilter,
+ mExecutor);
// Listen the subscription changes
mOnSubscriptionsChangedListener = new InternetOnSubscriptionChangedListener();
mSubscriptionManager.addOnSubscriptionsChangedListener(mExecutor,
mOnSubscriptionsChangedListener);
mDefaultDataSubId = getDefaultDataSubscriptionId();
+ if (DEBUG) {
+ Log.d(TAG, "Init, SubId: " + mDefaultDataSubId);
+ }
mTelephonyManager = mTelephonyManager.createForSubscriptionId(mDefaultDataSubId);
mInternetTelephonyCallback = new InternetTelephonyCallback();
mTelephonyManager.registerTelephonyCallback(mExecutor, mInternetTelephonyCallback);
@@ -206,7 +214,7 @@
if (DEBUG) {
Log.d(TAG, "onStop");
}
- mBroadcastDispatcher.unregisterReceiver(mWifiStateReceiver);
+ mBroadcastDispatcher.unregisterReceiver(mConnectionStateReceiver);
mTelephonyManager.unregisterTelephonyCallback(mInternetTelephonyCallback);
mSubscriptionManager.removeOnSubscriptionsChangedListener(
mOnSubscriptionsChangedListener);
@@ -648,13 +656,12 @@
}
boolean isDataStateInService() {
- if (mTelephonyManager == null) {
- if (DEBUG) {
- Log.d(TAG, "TelephonyManager is null, can not detect mobile state.");
- }
- return false;
- }
- return mTelephonyManager.getDataState() == TelephonyManager.DATA_CONNECTED;
+ final ServiceState serviceState = mTelephonyManager.getServiceState();
+ NetworkRegistrationInfo regInfo =
+ (serviceState == null) ? null : serviceState.getNetworkRegistrationInfo(
+ NetworkRegistrationInfo.DOMAIN_PS,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+ return (regInfo == null) ? false : regInfo.isRegistered();
}
boolean isVoiceStateInService() {
@@ -815,15 +822,7 @@
@Override
public void onSubscriptionsChanged() {
- mDefaultDataSubId = getDefaultDataSubscriptionId();
- if (SubscriptionManager.isUsableSubscriptionId(mDefaultDataSubId)) {
- mTelephonyManager.unregisterTelephonyCallback(mInternetTelephonyCallback);
-
- mTelephonyManager = mTelephonyManager.createForSubscriptionId(mDefaultDataSubId);
- mTelephonyManager.registerTelephonyCallback(mHandler::post,
- mInternetTelephonyCallback);
- mCallback.onSubscriptionsChanged(mDefaultDataSubId);
- }
+ updateListener();
}
}
@@ -839,13 +838,46 @@
}
}
- private final BroadcastReceiver mWifiStateReceiver = new BroadcastReceiver() {
+ private final BroadcastReceiver mConnectionStateReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- mCallback.onWifiStateReceived(context, intent);
+ final String action = intent.getAction();
+ if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)
+ || action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
+ mCallback.onWifiStateReceived(context, intent);
+ }
+
+ if (action.equals(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)) {
+ if (DEBUG) {
+ Log.d(TAG, "ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED");
+ }
+ updateListener();
+ }
}
};
+ private void updateListener() {
+ int defaultDataSubId = getDefaultDataSubscriptionId();
+ if (mDefaultDataSubId == getDefaultDataSubscriptionId()) {
+ if (DEBUG) {
+ Log.d(TAG, "DDS: no change");
+ }
+ return;
+ }
+
+ mDefaultDataSubId = defaultDataSubId;
+ if (DEBUG) {
+ Log.d(TAG, "DDS: defaultDataSubId:" + mDefaultDataSubId);
+ }
+ if (SubscriptionManager.isUsableSubscriptionId(mDefaultDataSubId)) {
+ mTelephonyManager.unregisterTelephonyCallback(mInternetTelephonyCallback);
+ mTelephonyManager = mTelephonyManager.createForSubscriptionId(mDefaultDataSubId);
+ mTelephonyManager.registerTelephonyCallback(mHandler::post,
+ mInternetTelephonyCallback);
+ mCallback.onSubscriptionsChanged(mDefaultDataSubId);
+ }
+ }
+
interface InternetDialogCallback {
void onRefreshCarrierInfo();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt
index 85e6160..e82e89ef1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt
@@ -41,15 +41,15 @@
}
/** Creates a [InternetDialog]. */
- fun create(aboveStatusBar: Boolean) {
+ fun create(aboveStatusBar: Boolean, canConfigMobileData: Boolean) {
if (internetDialog != null) {
if (DEBUG) {
Log.d(TAG, "InternetDialog is showing, do not create it twice.")
}
return
} else {
- internetDialog = InternetDialog(context, this, internetDialogController, aboveStatusBar,
- uiEventLogger, handler)
+ internetDialog = InternetDialog(context, this, internetDialogController,
+ canConfigMobileData, aboveStatusBar, uiEventLogger, handler)
internetDialog?.show()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
index 5a42458..b76cebf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
@@ -49,11 +49,6 @@
return mFlagReader.isEnabled(R.bool.flag_notification_pipeline2_rendering);
}
- /** b/171917882 */
- public boolean isTwoColumnNotificationShadeEnabled() {
- return mFlagReader.isEnabled(R.bool.flag_notification_twocolumn);
- }
-
public boolean isKeyguardLayoutEnabled() {
return mFlagReader.isEnabled(R.bool.flag_keyguard_layout);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 44399a1..120121c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -94,7 +94,7 @@
* Controls the indications and error messages shown on the Keyguard
*/
@SysUISingleton
-public class KeyguardIndicationController implements KeyguardStateController.Callback {
+public class KeyguardIndicationController {
private static final String TAG = "KeyguardIndication";
private static final boolean DEBUG_CHARGING_SPEED = false;
@@ -206,7 +206,7 @@
mKeyguardUpdateMonitor.registerCallback(getKeyguardCallback());
mKeyguardUpdateMonitor.registerCallback(mTickReceiver);
mStatusBarStateController.addCallback(mStatusBarStateListener);
- mKeyguardStateController.addCallback(this);
+ mKeyguardStateController.addCallback(mKeyguardStateCallback);
mStatusBarStateListener.onDozingChanged(mStatusBarStateController.isDozing());
}
@@ -827,11 +827,6 @@
mRotateTextViewController.dump(fd, pw, args);
}
- @Override
- public void onUnlockedChanged() {
- updateIndication(false);
- }
-
protected class BaseKeyguardCallback extends KeyguardUpdateMonitorCallback {
public static final int HIDE_DELAY_MS = 5000;
@@ -967,10 +962,8 @@
}
private boolean shouldSuppressFaceMsgAndShowTryFingerprintMsg() {
- // For dual biometric, don't show face auth messages unless face auth was explicitly
- // requested by the user.
+ // For dual biometric, don't show face auth messages
return mKeyguardUpdateMonitor.isFingerprintDetectionRunning()
- && !mKeyguardUpdateMonitor.isFaceAuthUserRequested()
&& mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
true /* isStrongBiometric */);
}
@@ -1068,4 +1061,20 @@
updateIndication(false);
}
};
+
+ private KeyguardStateController.Callback mKeyguardStateCallback =
+ new KeyguardStateController.Callback() {
+ @Override
+ public void onUnlockedChanged() {
+ updateIndication(false);
+ }
+
+ @Override
+ public void onKeyguardShowingChanged() {
+ if (!mKeyguardStateController.isShowing()) {
+ mTopIndicationView.clearMessages();
+ mLockScreenIndicationView.clearMessages();
+ }
+ }
+ };
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
index 538db61..8780ad8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
@@ -83,6 +83,35 @@
}
}
+class LinearLightRevealEffect(private val isVertical: Boolean) : LightRevealEffect {
+
+ private val INTERPOLATOR = Interpolators.FAST_OUT_SLOW_IN_REVERSE
+
+ override fun setRevealAmountOnScrim(amount: Float, scrim: LightRevealScrim) {
+ val interpolatedAmount = INTERPOLATOR.getInterpolation(amount)
+
+ // TODO(b/193801466): add alpha reveal in the beginning as well
+ scrim.revealGradientEndColorAlpha =
+ 1f - LightRevealEffect.getPercentPastThreshold(interpolatedAmount, threshold = 0.6f)
+
+ if (isVertical) {
+ scrim.setRevealGradientBounds(
+ left = scrim.width / 2 - (scrim.width / 2) * interpolatedAmount,
+ top = 0f,
+ right = scrim.width / 2 + (scrim.width / 2) * interpolatedAmount,
+ bottom = scrim.height.toFloat()
+ )
+ } else {
+ scrim.setRevealGradientBounds(
+ left = 0f,
+ top = scrim.height / 2 - (scrim.height / 2) * interpolatedAmount,
+ right = scrim.width.toFloat(),
+ bottom = scrim.height / 2 + (scrim.height / 2) * interpolatedAmount
+ )
+ }
+ }
+}
+
class CircleReveal(
/** X-value of the circle center of the reveal. */
val centerX: Float,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index 6f4a73e..f0da702 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -60,7 +60,6 @@
private val mediaHierarchyManager: MediaHierarchyManager,
private val scrimController: ScrimController,
private val depthController: NotificationShadeDepthController,
- private val featureFlags: FeatureFlags,
private val context: Context,
configurationController: ConfigurationController,
falsingManager: FalsingManager
@@ -134,7 +133,7 @@
R.dimen.lockscreen_shade_scrim_transition_distance)
fullTransitionDistance = context.resources.getDimensionPixelSize(
R.dimen.lockscreen_shade_qs_transition_distance)
- useSplitShade = Utils.shouldUseSplitNotificationShade(featureFlags, context.resources)
+ useSplitShade = Utils.shouldUseSplitNotificationShade(context.resources)
}
fun setStackScroller(nsslController: NotificationStackScrollLayoutController) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index bc3883c..625d9cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -70,6 +70,7 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
@@ -136,6 +137,8 @@
protected Callback mCallback;
protected final ArrayList<NotificationLifetimeExtender> mLifetimeExtenders = new ArrayList<>();
+ private final List<RemoteInputController.Callback> mControllerCallbacks = new ArrayList<>();
+
private final InteractionHandler mInteractionHandler = new InteractionHandler() {
@Override
@@ -332,6 +335,11 @@
public void setUpWithCallback(Callback callback, RemoteInputController.Delegate delegate) {
mCallback = callback;
mRemoteInputController = new RemoteInputController(delegate, mRemoteInputUriController);
+ // Register all stored callbacks from before the Controller was initialized.
+ for (RemoteInputController.Callback cb : mControllerCallbacks) {
+ mRemoteInputController.addCallback(cb);
+ }
+ mControllerCallbacks.clear();
mRemoteInputController.addCallback(new RemoteInputController.Callback() {
@Override
public void onRemoteInputSent(NotificationEntry entry) {
@@ -377,6 +385,22 @@
});
}
+ public void addControllerCallback(RemoteInputController.Callback callback) {
+ if (mRemoteInputController != null) {
+ mRemoteInputController.addCallback(callback);
+ } else {
+ mControllerCallbacks.add(callback);
+ }
+ }
+
+ public void removeControllerCallback(RemoteInputController.Callback callback) {
+ if (mRemoteInputController != null) {
+ mRemoteInputController.removeCallback(callback);
+ } else {
+ mControllerCallbacks.remove(callback);
+ }
+ }
+
/**
* Activates a given {@link RemoteInput}
*
@@ -563,17 +587,12 @@
return mLifetimeExtenders;
}
- @Nullable
- public RemoteInputController getController() {
- return mRemoteInputController;
- }
-
@VisibleForTesting
void onPerformRemoveNotification(NotificationEntry entry, final String key) {
if (mKeysKeptForRemoteInputHistory.contains(key)) {
mKeysKeptForRemoteInputHistory.remove(key);
}
- if (mRemoteInputController.isRemoteInputActive(entry)) {
+ if (isRemoteInputActive(entry)) {
entry.mRemoteEditImeVisible = false;
mRemoteInputController.removeRemoteInput(entry, null);
}
@@ -582,7 +601,9 @@
public void onPanelCollapsed() {
for (int i = 0; i < mEntriesKeptForRemoteInputActive.size(); i++) {
NotificationEntry entry = mEntriesKeptForRemoteInputActive.valueAt(i);
- mRemoteInputController.removeRemoteInput(entry, null);
+ if (mRemoteInputController != null) {
+ mRemoteInputController.removeRemoteInput(entry, null);
+ }
if (mNotificationLifetimeFinishedCallback != null) {
mNotificationLifetimeFinishedCallback.onSafeToRemove(entry.getKey());
}
@@ -598,8 +619,7 @@
if (!FORCE_REMOTE_INPUT_HISTORY) {
return false;
}
- return (mRemoteInputController.isSpinning(entry.getKey())
- || entry.hasJustSentRemoteInput());
+ return isSpinning(entry.getKey()) || entry.hasJustSentRemoteInput();
}
/**
@@ -632,8 +652,8 @@
public void checkRemoteInputOutside(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar
&& event.getX() == 0 && event.getY() == 0 // a touch outside both bars
- && mRemoteInputController.isRemoteInputActive()) {
- mRemoteInputController.closeRemoteInputs();
+ && isRemoteInputActive()) {
+ closeRemoteInputs();
}
}
@@ -715,6 +735,24 @@
return mEntriesKeptForRemoteInputActive;
}
+ public boolean isRemoteInputActive() {
+ return mRemoteInputController != null && mRemoteInputController.isRemoteInputActive();
+ }
+
+ public boolean isRemoteInputActive(NotificationEntry entry) {
+ return mRemoteInputController != null && mRemoteInputController.isRemoteInputActive(entry);
+ }
+
+ public boolean isSpinning(String entryKey) {
+ return mRemoteInputController != null && mRemoteInputController.isSpinning(entryKey);
+ }
+
+ public void closeRemoteInputs() {
+ if (mRemoteInputController != null) {
+ mRemoteInputController.closeRemoteInputs();
+ }
+ }
+
/**
* NotificationRemoteInputManager has multiple reasons to keep notification lifetime extended
* so we implement multiple NotificationLifetimeExtenders
@@ -822,7 +860,7 @@
protected class RemoteInputActiveExtender extends RemoteInputExtender {
@Override
public boolean shouldExtendLifetime(@NonNull NotificationEntry entry) {
- return mRemoteInputController.isRemoteInputActive(entry);
+ return isRemoteInputActive(entry);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
index 28bdd5f..db553e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
@@ -89,6 +89,9 @@
private var prevShadeDirection = 0
private var prevShadeVelocity = 0f
+ // Only for dumpsys
+ private var lastAppliedBlur = 0
+
@VisibleForTesting
var shadeSpring = DepthAnimation()
var shadeAnimation = DepthAnimation()
@@ -201,6 +204,7 @@
val opaque = scrimsVisible && !blursDisabledForAppLaunch
Trace.traceCounter(Trace.TRACE_TAG_APP, "shade_blur_radius", blur)
blurUtils.applyBlur(blurRoot?.viewRootImpl ?: root.viewRootImpl, blur, opaque)
+ lastAppliedBlur = blur
try {
if (root.isAttachedToWindow && root.windowToken != null) {
wallpaperManager.setWallpaperZoomOut(root.windowToken, zoomOut)
@@ -271,6 +275,11 @@
brightnessMirrorSpring.finishIfRunning()
}
}
+
+ override fun onDozeAmountChanged(linear: Float, eased: Float) {
+ wakeAndUnlockBlurRadius = blurUtils.blurRadiusOfRatio(eased)
+ scheduleUpdate()
+ }
}
init {
@@ -428,6 +437,9 @@
it.println("brightnessMirrorRadius: ${brightnessMirrorSpring.radius}")
it.println("wakeAndUnlockBlur: $wakeAndUnlockBlurRadius")
it.println("blursDisabledForAppLaunch: $blursDisabledForAppLaunch")
+ it.println("qsPanelExpansion: $qsPanelExpansion")
+ it.println("transitionToFullShadeProgress: $transitionToFullShadeProgress")
+ it.println("lastAppliedBlur: $lastAppliedBlur")
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
index 180f81c..83701a0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
@@ -25,7 +25,6 @@
import android.util.ArrayMap;
import android.util.Pair;
-import com.android.internal.util.Preconditions;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.policy.RemoteInputUriController;
import com.android.systemui.statusbar.policy.RemoteInputView;
@@ -245,6 +244,10 @@
mCallbacks.add(callback);
}
+ public void removeCallback(Callback callback) {
+ mCallbacks.remove(callback);
+ }
+
public void remoteInputSent(NotificationEntry entry) {
int N = mCallbacks.size();
for (int i = 0; i < N; i++) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
index 71f667a..a05e950 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
@@ -27,6 +27,7 @@
import com.android.systemui.media.MediaDataManager;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.qs.carrier.QSCarrierGroupController;
import com.android.systemui.statusbar.ActionClickLogger;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.FeatureFlags;
@@ -253,4 +254,9 @@
ongoingCallController.init();
return ongoingCallController;
}
+
+ /** */
+ @Binds
+ QSCarrierGroupController.SlotIndexResolver provideSlotIndexResolver(
+ QSCarrierGroupController.SubscriptionManagerSlotIndexResolver impl);
}
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 5f10e55..19a00d2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt
@@ -18,6 +18,8 @@
import android.animation.Animator
import android.annotation.UiThread
+import android.graphics.Point
+import android.graphics.Rect
import android.util.Log
import android.view.Gravity
import android.view.View
@@ -31,9 +33,16 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.StatusBarState.SHADE
import com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED
-import com.android.systemui.statusbar.phone.StatusBarLocationPublisher
-import com.android.systemui.statusbar.phone.StatusBarMarginUpdatedListener
+import com.android.systemui.statusbar.phone.StatusBarContentInsetsChangedListener
+import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider
+import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.concurrency.DelayableExecutor
+import com.android.systemui.util.leak.RotationUtils
+import com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE
+import com.android.systemui.util.leak.RotationUtils.ROTATION_NONE
+import com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE
+import com.android.systemui.util.leak.RotationUtils.ROTATION_UPSIDE_DOWN
+import com.android.systemui.util.leak.RotationUtils.Rotation
import java.lang.IllegalStateException
import java.util.concurrent.Executor
@@ -58,9 +67,10 @@
class PrivacyDotViewController @Inject constructor(
@Main private val mainExecutor: Executor,
private val stateController: StatusBarStateController,
- private val locationPublisher: StatusBarLocationPublisher,
+ private val configurationController: ConfigurationController,
+ private val contentInsetsProvider: StatusBarContentInsetsProvider,
private val animationScheduler: SystemStatusAnimationScheduler
-) {
+) : StatusBarContentInsetsChangedListener {
private var sbHeightPortrait = 0
private var sbHeightLandscape = 0
@@ -84,18 +94,22 @@
// Privacy dots are created in ScreenDecoration's UiThread, which is not the main thread
private var uiExecutor: DelayableExecutor? = null
- private val marginListener: StatusBarMarginUpdatedListener =
- object : StatusBarMarginUpdatedListener {
- override fun onStatusBarMarginUpdated(marginLeft: Int, marginRight: Int) {
- setStatusBarMargins(marginLeft, marginRight)
- }
- }
-
private val views: Sequence<View>
get() = if (!this::tl.isInitialized) sequenceOf() else sequenceOf(tl, tr, br, bl)
init {
- locationPublisher.addCallback(marginListener)
+ contentInsetsProvider.addCallback(this)
+ configurationController.addCallback(object : ConfigurationController.ConfigurationListener {
+ override fun onLayoutDirectionChanged(isRtl: Boolean) {
+ synchronized(this) {
+ val corner = selectDesignatedCorner(nextViewState.rotation, isRtl)
+ nextViewState = nextViewState.copy(
+ layoutRtl = isRtl,
+ designatedCorner = corner
+ )
+ }
+ }
+ })
stateController.addCallback(object : StatusBarStateController.StateListener {
override fun onExpandedChanged(isExpanded: Boolean) {
@@ -123,16 +137,19 @@
fun setNewRotation(rot: Int) {
dlog("updateRotation: $rot")
+ val isRtl: Boolean
synchronized(lock) {
if (rot == nextViewState.rotation) {
return
}
+
+ isRtl = nextViewState.layoutRtl
}
// If we rotated, hide all dotes until the next state resolves
setCornerVisibilities(View.INVISIBLE)
- val newCorner = selectDesignatedCorner(rot)
+ val newCorner = selectDesignatedCorner(rot, isRtl)
val index = newCorner.cornerIndex()
val h = when (rot) {
@@ -222,15 +239,77 @@
}
}
+ @UiThread
+ private fun setCornerSizes(state: ViewState) {
+ // StatusBarContentInsetsProvider can tell us the location of the privacy indicator dot
+ // in every rotation. The only thing we need to check is rtl
+ val rtl = state.layoutRtl
+ val size = Point()
+ tl.context.display.getRealSize(size)
+ val currentRotation = RotationUtils.getExactRotation(tl.context)
+
+ val displayWidth: Int
+ val displayHeight: Int
+ if (currentRotation == ROTATION_LANDSCAPE || currentRotation == ROTATION_SEASCAPE) {
+ displayWidth = size.y
+ displayHeight = size.x
+ } else {
+ displayWidth = size.x
+ displayHeight = size.y
+ }
+
+ var rot = activeRotationForCorner(tl, rtl)
+ var contentInsets = state.contentRectForRotation(rot)
+ (tl.layoutParams as FrameLayout.LayoutParams).apply {
+ height = contentInsets.height()
+ if (rtl) {
+ width = contentInsets.left
+ } else {
+ width = displayHeight - contentInsets.right
+ }
+ }
+
+ rot = activeRotationForCorner(tr, rtl)
+ contentInsets = state.contentRectForRotation(rot)
+ (tr.layoutParams as FrameLayout.LayoutParams).apply {
+ height = contentInsets.height()
+ if (rtl) {
+ width = contentInsets.left
+ } else {
+ width = displayWidth - contentInsets.right
+ }
+ }
+
+ rot = activeRotationForCorner(br, rtl)
+ contentInsets = state.contentRectForRotation(rot)
+ (br.layoutParams as FrameLayout.LayoutParams).apply {
+ height = contentInsets.height()
+ if (rtl) {
+ width = contentInsets.left
+ } else {
+ width = displayHeight - contentInsets.right
+ }
+ }
+
+ rot = activeRotationForCorner(bl, rtl)
+ contentInsets = state.contentRectForRotation(rot)
+ (bl.layoutParams as FrameLayout.LayoutParams).apply {
+ height = contentInsets.height()
+ if (rtl) {
+ width = contentInsets.left
+ } else {
+ width = displayWidth - contentInsets.right
+ }
+ }
+ }
+
// Designated view will be the one at statusbar's view.END
@UiThread
- private fun selectDesignatedCorner(r: Int): View? {
+ private fun selectDesignatedCorner(r: Int, isRtl: Boolean): View? {
if (!this::tl.isInitialized) {
return null
}
- val isRtl = tl.isLayoutRtl
-
return when (r) {
0 -> if (isRtl) tl else tr
1 -> if (isRtl) tr else br
@@ -282,6 +361,17 @@
return modded
}
+ @Rotation
+ private fun activeRotationForCorner(corner: View, rtl: Boolean): Int {
+ // Each corner will only be visible in a single rotation, based on rtl
+ return when (corner) {
+ tr -> if (rtl) ROTATION_LANDSCAPE else ROTATION_NONE
+ tl -> if (rtl) ROTATION_NONE else ROTATION_SEASCAPE
+ br -> if (rtl) ROTATION_UPSIDE_DOWN else ROTATION_LANDSCAPE
+ else /* bl */ -> if (rtl) ROTATION_SEASCAPE else ROTATION_UPSIDE_DOWN
+ }
+ }
+
private fun widthForCorner(corner: Int, left: Int, right: Int): Int {
return when (corner) {
TOP_LEFT, BOTTOM_LEFT -> left
@@ -303,15 +393,32 @@
bl = bottomLeft
br = bottomRight
- val dc = selectDesignatedCorner(0)
+ val rtl = configurationController.isLayoutRtl
+ val dc = selectDesignatedCorner(0, rtl)
+
val index = dc.cornerIndex()
mainExecutor.execute {
animationScheduler.addCallback(systemStatusAnimationCallback)
}
+ val left = contentInsetsProvider.getStatusBarContentInsetsForRotation(ROTATION_SEASCAPE)
+ val top = contentInsetsProvider.getStatusBarContentInsetsForRotation(ROTATION_NONE)
+ val right = contentInsetsProvider.getStatusBarContentInsetsForRotation(ROTATION_LANDSCAPE)
+ val bottom = contentInsetsProvider
+ .getStatusBarContentInsetsForRotation(ROTATION_UPSIDE_DOWN)
+
synchronized(lock) {
- nextViewState = nextViewState.copy(designatedCorner = dc, cornerIndex = index)
+ nextViewState = nextViewState.copy(
+ viewInitialized = true,
+ designatedCorner = dc,
+ cornerIndex = index,
+ seascapeRect = left,
+ portraitRect = top,
+ landscapeRect = right,
+ upsideDownRect = bottom,
+ layoutRtl = rtl
+ )
}
}
@@ -324,19 +431,6 @@
sbHeightLandscape = landscape
}
- /**
- * The dot view containers will fill the margin in order to position the dots correctly
- *
- * @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
- */
- private fun setStatusBarMargins(left: Int, right: Int) {
- dlog("setStatusBarMargins l=$left r=$right")
- synchronized(lock) {
- nextViewState = nextViewState.copy(marginLeft = left, marginRight = right)
- }
- }
-
private fun updateStatusBarState() {
synchronized(lock) {
nextViewState = nextViewState.copy(shadeExpanded = isShadeInQs())
@@ -377,6 +471,11 @@
@UiThread
private fun resolveState(state: ViewState) {
dlog("resolveState $state")
+ if (!state.viewInitialized) {
+ dlog("resolveState: view is not initialized. skipping")
+ return
+ }
+
if (state == currentViewState) {
dlog("resolveState: skipping")
return
@@ -387,23 +486,15 @@
updateRotations(state.rotation)
}
- if (state.height != currentViewState.height) {
- updateHeights(state.rotation)
- }
-
- if (state.marginLeft != currentViewState.marginLeft ||
- state.marginRight != currentViewState.marginRight) {
- updateCornerSizes(state.marginLeft, state.marginRight, state.rotation)
+ if (state.needsLayout(currentViewState)) {
+ setCornerSizes(state)
+ views.forEach { it.requestLayout() }
}
if (state.designatedCorner != currentViewState.designatedCorner) {
updateDesignatedCorner(state.designatedCorner, state.shouldShowDot())
}
- if (state.needsLayout(currentViewState)) {
- views.forEach { it.requestLayout() }
- }
-
val shouldShow = state.shouldShowDot()
if (shouldShow != currentViewState.shouldShowDot()) {
if (shouldShow && state.designatedCorner != null) {
@@ -441,6 +532,35 @@
}
return -1
}
+
+ override fun onStatusBarContentInsetsChanged() {
+ Log.d(TAG, "onStatusBarContentInsetsChanged: ")
+ setNewLayoutRects()
+ }
+
+ // Returns [left, top, right, bottom] aka [seascape, none, landscape, upside-down]
+ private fun getLayoutRects(): List<Rect> {
+ val left = contentInsetsProvider.getStatusBarContentInsetsForRotation(ROTATION_SEASCAPE)
+ val top = contentInsetsProvider.getStatusBarContentInsetsForRotation(ROTATION_NONE)
+ val right = contentInsetsProvider.getStatusBarContentInsetsForRotation(ROTATION_LANDSCAPE)
+ val bottom = contentInsetsProvider
+ .getStatusBarContentInsetsForRotation(ROTATION_UPSIDE_DOWN)
+
+ return listOf(left, top, right, bottom)
+ }
+
+ private fun setNewLayoutRects() {
+ val rects = getLayoutRects()
+
+ synchronized(lock) {
+ nextViewState = nextViewState.copy(
+ seascapeRect = rects[0],
+ portraitRect = rects[1],
+ landscapeRect = rects[2],
+ upsideDownRect = rects[3]
+ )
+ }
+ }
}
private fun dlog(s: String) {
@@ -461,7 +581,7 @@
const val BOTTOM_LEFT = 3
private const val DURATION = 160L
private const val TAG = "PrivacyDotViewController"
-private const val DEBUG = true
+private const val DEBUG = false
private const val DEBUG_VERBOSE = false
private fun Int.toGravity(): Int {
@@ -485,14 +605,20 @@
}
private data class ViewState(
+ val viewInitialized: Boolean = false,
+
val systemPrivacyEventIsActive: Boolean = false,
val shadeExpanded: Boolean = false,
val qsExpanded: Boolean = false,
+ val portraitRect: Rect? = null,
+ val landscapeRect: Rect? = null,
+ val upsideDownRect: Rect? = null,
+ val seascapeRect: Rect? = null,
+ val layoutRtl: Boolean = false,
+
val rotation: Int = 0,
val height: Int = 0,
- val marginLeft: Int = 0,
- val marginRight: Int = 0,
val cornerIndex: Int = -1,
val designatedCorner: View? = null
) {
@@ -502,7 +628,20 @@
fun needsLayout(other: ViewState): Boolean {
return rotation != other.rotation ||
- marginRight != other.marginRight ||
- height != other.height
+ layoutRtl != other.layoutRtl ||
+ portraitRect != other.portraitRect ||
+ landscapeRect != other.landscapeRect ||
+ upsideDownRect != other.upsideDownRect ||
+ seascapeRect != other.seascapeRect
+ }
+
+ fun contentRectForRotation(@Rotation rot: Int): Rect {
+ return when (rot) {
+ ROTATION_NONE -> portraitRect!!
+ ROTATION_LANDSCAPE -> landscapeRect!!
+ ROTATION_UPSIDE_DOWN -> upsideDownRect!!
+ ROTATION_SEASCAPE -> seascapeRect!!
+ else -> throw IllegalArgumentException("not a rotation ($rot)")
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java
index be1383f..6e98c27 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java
@@ -149,7 +149,7 @@
final String entryKey = entry.getKey();
if (mHeadsUpManager.isAlerting(entryKey)) {
boolean removeImmediatelyForRemoteInput =
- mRemoteInputManager.getController().isSpinning(entryKey)
+ mRemoteInputManager.isSpinning(entryKey)
&& !FORCE_REMOTE_INPUT_HISTORY;
mHeadsUpManager.removeNotification(entry.getKey(), removeImmediatelyForRemoteInput);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpController.java
index 4d56e60..b1c69e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpController.java
@@ -152,7 +152,7 @@
// Also we should not defer the removal if reordering isn't allowed since otherwise
// some notifications can't disappear before the panel is closed.
boolean ignoreEarliestRemovalTime =
- mRemoteInputManager.getController().isSpinning(key)
+ mRemoteInputManager.isSpinning(key)
&& !FORCE_REMOTE_INPUT_HISTORY
|| !mVisualStabilityManager.isReorderingAllowed();
mHeadsUpManager.removeNotification(key, ignoreEarliestRemovalTime);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 93166f3..73bb6cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -287,7 +287,7 @@
mGroupExpansionChanging = true;
final boolean wasExpanded = mGroupExpansionManager.isGroupExpanded(mEntry);
boolean nowExpanded = mGroupExpansionManager.toggleGroupExpansion(mEntry);
- mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
+ mOnExpandClickListener.onExpandClicked(mEntry, v, nowExpanded);
MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_GROUP_EXPANDER,
nowExpanded);
onExpansionChanged(true /* userAction */, wasExpanded);
@@ -310,7 +310,7 @@
setUserExpanded(nowExpanded);
}
notifyHeightChanged(true);
- mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
+ mOnExpandClickListener.onExpandClicked(mEntry, v, nowExpanded);
MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_EXPANDER,
nowExpanded);
}
@@ -3064,7 +3064,7 @@
}
public interface OnExpandClickListener {
- void onExpandClicked(NotificationEntry clickedEntry, boolean nowExpanded);
+ void onExpandClicked(NotificationEntry clickedEntry, View clickedView, boolean nowExpanded);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
index 73c4b05..1530e523 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
@@ -874,7 +874,7 @@
mRow.getImageResolver().purgeCache();
}
- private class RtlEnabledContext extends ContextWrapper {
+ private static class RtlEnabledContext extends ContextWrapper {
private RtlEnabledContext(Context packageContext) {
super(packageContext);
}
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 623e563..f43bdbf 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
@@ -82,10 +82,8 @@
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.FeatureFlags;
-import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.NotificationShelfController;
-import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.ExpandAnimationParameters;
import com.android.systemui.statusbar.notification.FakeShadowView;
@@ -442,7 +440,6 @@
private final Rect mTmpRect = new Rect();
private DismissListener mDismissListener;
private DismissAllAnimationListener mDismissAllAnimationListener;
- private NotificationRemoteInputManager mRemoteInputManager;
private ShadeController mShadeController;
private Consumer<Boolean> mOnStackYChanged;
@@ -457,6 +454,7 @@
private float mLastSentExpandedHeight;
private boolean mWillExpand;
private int mGapHeight;
+ private boolean mIsRemoteInputActive;
/**
* The extra inset during the full shade transition
@@ -528,7 +526,6 @@
private NotificationEntry mTopHeadsUpEntry;
private long mNumHeadsUp;
private NotificationStackScrollLayoutController.TouchHandler mTouchHandler;
- private final FeatureFlags mFeatureFlags;
private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
private boolean mShouldUseSplitNotificationShade;
@@ -574,12 +571,10 @@
GroupMembershipManager groupMembershipManager,
GroupExpansionManager groupExpansionManager,
AmbientState ambientState,
- FeatureFlags featureFlags,
UnlockedScreenOffAnimationController unlockedScreenOffAnimationController) {
super(context, attrs, 0, 0);
Resources res = getResources();
mSectionsManager = notificationSectionsManager;
- mFeatureFlags = featureFlags;
mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController;
updateSplitNotificationShade();
mSectionsManager.initialize(this, LayoutInflater.from(context));
@@ -681,6 +676,10 @@
mSectionsManager.reinflateViews(LayoutInflater.from(mContext));
}
+ public void setIsRemoteInputActive(boolean isActive) {
+ mIsRemoteInputActive = isActive;
+ }
+
@VisibleForTesting
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void updateFooter() {
@@ -690,11 +689,10 @@
// TODO: move this logic to controller, which will invoke updateFooterView directly
boolean showDismissView = mClearAllEnabled &&
mController.hasActiveClearableNotifications(ROWS_ALL);
- RemoteInputController remoteInputController = mRemoteInputManager.getController();
boolean showFooterView = (showDismissView || getVisibleNotificationCount() > 0)
&& mStatusBarState != StatusBarState.KEYGUARD
&& !mUnlockedScreenOffAnimationController.isScreenOffAnimationPlaying()
- && (remoteInputController == null || !remoteInputController.isRemoteInputActive());
+ && !mIsRemoteInputActive;
boolean showHistory = Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0, UserHandle.USER_CURRENT) == 1;
@@ -5369,10 +5367,6 @@
mFooterDismissListener = listener;
}
- public void setRemoteInputManager(NotificationRemoteInputManager remoteInputManager) {
- mRemoteInputManager = remoteInputManager;
- }
-
void setShadeController(ShadeController shadeController) {
mShadeController = shadeController;
}
@@ -5424,7 +5418,7 @@
}
private void updateSplitNotificationShade() {
- boolean split = shouldUseSplitNotificationShade(mFeatureFlags, getResources());
+ boolean split = shouldUseSplitNotificationShade(getResources());
if (split != mShouldUseSplitNotificationShade) {
mShouldUseSplitNotificationShade = split;
updateDismissBehavior();
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 8ee0cd1..d48109b 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
@@ -682,7 +682,13 @@
NotificationPanelEvent.fromSelection(selection)));
mView.setFooterDismissListener(() ->
mMetricsLogger.action(MetricsEvent.ACTION_DISMISS_ALL_NOTES));
- mView.setRemoteInputManager(mRemoteInputManager);
+ mView.setIsRemoteInputActive(mRemoteInputManager.isRemoteInputActive());
+ mRemoteInputManager.addControllerCallback(new RemoteInputController.Callback() {
+ @Override
+ public void onRemoteInputActive(boolean active) {
+ mView.setIsRemoteInputActive(active);
+ }
+ });
mView.setShadeController(mShadeController);
if (mFgFeatureController.isForegroundServiceDismissalEnabled()) {
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 23e3742..b36dc56 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
@@ -274,7 +274,9 @@
// expanded. Consider updating these states in updateContentView instead so that we don't
// have to recalculate in every frame.
float currentY = -ambientState.getScrollY();
- if (!ambientState.isOnKeyguard()) {
+ if (!ambientState.isOnKeyguard()
+ || (ambientState.isBypassEnabled() && ambientState.isPulseExpanding())) {
+ // add top padding at the start as long as we're not on the lock screen
currentY += mNotificationScrimPadding;
}
state.firstViewInShelf = null;
@@ -324,7 +326,8 @@
*/
private void updatePositionsForState(StackScrollAlgorithmState algorithmState,
AmbientState ambientState) {
- if (!ambientState.isOnKeyguard()) {
+ if (!ambientState.isOnKeyguard()
+ || (ambientState.isBypassEnabled() && ambientState.isPulseExpanding())) {
algorithmState.mCurrentYPosition += mNotificationScrimPadding;
algorithmState.mCurrentExpandedYPosition += mNotificationScrimPadding;
}
@@ -355,7 +358,9 @@
&& algorithmState.firstViewInShelf != null;
final float shelfHeight = showingShelf ? ambientState.getShelf().getIntrinsicHeight() : 0f;
- final float scrimPadding = ambientState.isOnKeyguard() ? 0 : mNotificationScrimPadding;
+ final float scrimPadding = ambientState.isOnKeyguard()
+ && (!ambientState.isBypassEnabled() || !ambientState.isPulseExpanding())
+ ? 0 : mNotificationScrimPadding;
final float stackHeight = ambientState.getStackHeight() - shelfHeight - scrimPadding;
final float stackEndHeight = ambientState.getStackEndHeight() - shelfHeight - scrimPadding;
@@ -394,7 +399,8 @@
ambientState.getExpansionFraction(), true /* notification */);
}
- if (view.mustStayOnScreen() && viewState.yTranslation >= 0) {
+ if (ambientState.isShadeExpanded() && view.mustStayOnScreen()
+ && viewState.yTranslation >= 0) {
// Even if we're not scrolled away we're in view and we're also not in the
// shelf. We can relax the constraints and let us scroll off the top!
float end = viewState.yTranslation + viewState.height + ambientState.getStackY();
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 a68dab9..14b39fe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
@@ -37,7 +37,6 @@
import android.view.ViewStub;
import android.widget.LinearLayout;
-import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -79,9 +78,9 @@
public static final int FADE_IN_DURATION = 320;
public static final int FADE_IN_DELAY = 50;
private PhoneStatusBarView mStatusBar;
- private StatusBarStateController mStatusBarStateController;
- private KeyguardStateController mKeyguardStateController;
- private NetworkController mNetworkController;
+ private final StatusBarStateController mStatusBarStateController;
+ private final KeyguardStateController mKeyguardStateController;
+ private final NetworkController mNetworkController;
private LinearLayout mSystemIconArea;
private View mClockView;
private View mOngoingCallChip;
@@ -92,12 +91,13 @@
private Lazy<Optional<StatusBar>> mStatusBarOptionalLazy;
private DarkIconManager mDarkIconManager;
private View mOperatorNameFrame;
- private CommandQueue mCommandQueue;
- private OngoingCallController mOngoingCallController;
+ private final CommandQueue mCommandQueue;
+ private final OngoingCallController mOngoingCallController;
private final SystemStatusAnimationScheduler mAnimationScheduler;
private final StatusBarLocationPublisher mLocationPublisher;
- private NotificationIconAreaController mNotificationIconAreaController;
private final FeatureFlags mFeatureFlags;
+ private final NotificationIconAreaController mNotificationIconAreaController;
+ private final StatusBarIconController mStatusBarIconController;
private List<String> mBlockedIcons = new ArrayList<>();
@@ -122,23 +122,24 @@
StatusBarLocationPublisher locationPublisher,
NotificationIconAreaController notificationIconAreaController,
FeatureFlags featureFlags,
- Lazy<Optional<StatusBar>> statusBarOptionalLazy
+ StatusBarIconController statusBarIconController,
+ KeyguardStateController keyguardStateController,
+ NetworkController networkController,
+ StatusBarStateController statusBarStateController,
+ Lazy<Optional<StatusBar>> statusBarOptionalLazy,
+ CommandQueue commandQueue
) {
mOngoingCallController = ongoingCallController;
mAnimationScheduler = animationScheduler;
mLocationPublisher = locationPublisher;
mNotificationIconAreaController = notificationIconAreaController;
mFeatureFlags = featureFlags;
+ mStatusBarIconController = statusBarIconController;
+ mKeyguardStateController = keyguardStateController;
+ mNetworkController = networkController;
+ mStatusBarStateController = statusBarStateController;
mStatusBarOptionalLazy = statusBarOptionalLazy;
- }
-
- @Override
- public void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- mKeyguardStateController = Dependency.get(KeyguardStateController.class);
- mNetworkController = Dependency.get(NetworkController.class);
- mStatusBarStateController = Dependency.get(StatusBarStateController.class);
- mCommandQueue = Dependency.get(CommandQueue.class);
+ mCommandQueue = commandQueue;
}
@Override
@@ -164,7 +165,7 @@
mBlockedIcons.add(getString(com.android.internal.R.string.status_bar_alarm_clock));
mBlockedIcons.add(getString(com.android.internal.R.string.status_bar_call_strength));
mDarkIconManager.setBlockList(mBlockedIcons);
- Dependency.get(StatusBarIconController.class).addIconGroup(mDarkIconManager);
+ mStatusBarIconController.addIconGroup(mDarkIconManager);
mSystemIconArea = mStatusBar.findViewById(R.id.system_icon_area);
mClockView = mStatusBar.findViewById(R.id.clock);
mOngoingCallChip = mStatusBar.findViewById(R.id.ongoing_call_chip);
@@ -203,7 +204,7 @@
@Override
public void onDestroyView() {
super.onDestroyView();
- Dependency.get(StatusBarIconController.class).removeIconGroup(mDarkIconManager);
+ mStatusBarIconController.removeIconGroup(mDarkIconManager);
if (mNetworkController.hasEmergencyCryptKeeperText()) {
mNetworkController.removeCallback(mSignalCallback);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt
index b148eeb..07618da 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt
@@ -18,6 +18,7 @@
import android.content.pm.ActivityInfo
import android.content.res.Configuration
import android.os.LocaleList
+import android.view.View.LAYOUT_DIRECTION_RTL
import com.android.systemui.statusbar.policy.ConfigurationController
import java.util.ArrayList
@@ -33,6 +34,7 @@
private var uiMode: Int = 0
private var localeList: LocaleList? = null
private val context: Context
+ private var layoutDirection: Int
init {
val currentConfig = context.resources.configuration
@@ -44,6 +46,7 @@
Configuration.UI_MODE_TYPE_CAR
uiMode = currentConfig.uiMode and Configuration.UI_MODE_NIGHT_MASK
localeList = currentConfig.locales
+ layoutDirection = currentConfig.layoutDirection
}
override fun notifyThemeChanged() {
@@ -101,6 +104,13 @@
}
}
+ if (layoutDirection != newConfig.layoutDirection) {
+ layoutDirection = newConfig.layoutDirection
+ listeners.filterForEach({ this.listeners.contains(it) }) {
+ it.onLayoutDirectionChanged(layoutDirection == LAYOUT_DIRECTION_RTL)
+ }
+ }
+
if (lastConfig.updateFrom(newConfig) and ActivityInfo.CONFIG_ASSETS_PATHS != 0) {
listeners.filterForEach({ this.listeners.contains(it) }) {
it.onOverlayChanged()
@@ -116,6 +126,10 @@
override fun removeCallback(listener: ConfigurationController.ConfigurationListener) {
listeners.remove(listener)
}
+
+ override fun isLayoutRtl(): Boolean {
+ return layoutDirection == LAYOUT_DIRECTION_RTL
+ }
}
// This could be done with a Collection.filter and Collection.forEach, but Collection.filter
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
index 1789743..f1cde8a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
@@ -62,6 +62,14 @@
}
/**
+ * Clears message queue.
+ */
+ public void clearMessages() {
+ mMessages.clear();
+ mKeyguardIndicationInfo.clear();
+ }
+
+ /**
* Changes the text with an animation and makes sure a single indication is shown long enough.
*/
public void switchIndication(int textResId) {
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 6755771..79f2dac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -18,6 +18,7 @@
import static android.view.View.GONE;
+import static androidx.constraintlayout.widget.ConstraintSet.BOTTOM;
import static androidx.constraintlayout.widget.ConstraintSet.END;
import static androidx.constraintlayout.widget.ConstraintSet.PARENT_ID;
import static androidx.constraintlayout.widget.ConstraintSet.START;
@@ -80,6 +81,7 @@
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.FrameLayout;
+import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.ConstraintSet;
import com.android.internal.annotations.VisibleForTesting;
@@ -104,6 +106,11 @@
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.classifier.Classifier;
import com.android.systemui.classifier.FalsingCollector;
+import com.android.systemui.communal.CommunalHostView;
+import com.android.systemui.communal.CommunalHostViewController;
+import com.android.systemui.communal.CommunalSource;
+import com.android.systemui.communal.CommunalSourceMonitor;
+import com.android.systemui.communal.dagger.CommunalViewComponent;
import com.android.systemui.dagger.qualifiers.DisplayId;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.doze.DozeLog;
@@ -123,7 +130,6 @@
import com.android.systemui.screenrecord.RecordingController;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.GestureRecorder;
import com.android.systemui.statusbar.KeyguardAffordanceView;
import com.android.systemui.statusbar.KeyguardIndicationController;
@@ -173,6 +179,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -314,17 +321,18 @@
private final PulseExpansionHandler mPulseExpansionHandler;
private final KeyguardBypassController mKeyguardBypassController;
private final KeyguardUpdateMonitor mUpdateMonitor;
+ private final CommunalSourceMonitor mCommunalSourceMonitor;
private final ConversationNotificationManager mConversationNotificationManager;
private final AuthController mAuthController;
private final MediaHierarchyManager mMediaHierarchyManager;
private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+ private final CommunalViewComponent.Factory mCommunalViewComponentFactory;
private final KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
private final KeyguardQsUserSwitchComponent.Factory mKeyguardQsUserSwitchComponentFactory;
private final KeyguardUserSwitcherComponent.Factory mKeyguardUserSwitcherComponentFactory;
private final KeyguardStatusBarViewComponent.Factory mKeyguardStatusBarViewComponentFactory;
private final QSDetailDisplayer mQSDetailDisplayer;
private final FragmentService mFragmentService;
- private final FeatureFlags mFeatureFlags;
private final ScrimController mScrimController;
private final PrivacyDotViewController mPrivacyDotViewController;
private final QuickAccessWalletController mQuickAccessWalletController;
@@ -352,6 +360,8 @@
private ViewGroup mBigClockContainer;
@VisibleForTesting QS mQs;
private FrameLayout mQsFrame;
+ @Nullable
+ private CommunalHostViewController mCommunalViewController;
private KeyguardStatusViewController mKeyguardStatusViewController;
private LockIconViewController mLockIconViewController;
private NotificationsQuickSettingsContainer mNotificationContainerParent;
@@ -363,6 +373,8 @@
private VelocityTracker mQsVelocityTracker;
private boolean mQsTracking;
+ private CommunalHostView mCommunalView;
+
/**
* If set, the ongoing touch gesture might both trigger the expansion in {@link PanelView} and
* the expansion for quick settings.
@@ -510,6 +522,24 @@
mPanelAlphaAnimator.getProperty(), Interpolators.ALPHA_IN);
private final NotificationEntryManager mEntryManager;
+ private final CommunalSourceMonitor.Callback mCommunalSourceMonitorCallback =
+ new CommunalSourceMonitor.Callback() {
+ @Override
+ public void onSourceAvailable(WeakReference<CommunalSource> source) {
+ setCommunalSource(source);
+ }
+ };
+
+ private WeakReference<CommunalSource> mCommunalSource;
+
+ private final CommunalSource.Callback mCommunalSourceCallback =
+ new CommunalSource.Callback() {
+ @Override
+ public void onDisconnected() {
+ setCommunalSource(null /*source*/);
+ }
+ };
+
private final CommandQueue mCommandQueue;
private final NotificationLockscreenUserManager mLockscreenUserManager;
private final UserManager mUserManager;
@@ -692,7 +722,8 @@
DozeParameters dozeParameters, CommandQueue commandQueue, VibratorHelper vibratorHelper,
LatencyTracker latencyTracker, PowerManager powerManager,
AccessibilityManager accessibilityManager, @DisplayId int displayId,
- KeyguardUpdateMonitor keyguardUpdateMonitor, MetricsLogger metricsLogger,
+ KeyguardUpdateMonitor keyguardUpdateMonitor,
+ CommunalSourceMonitor communalSourceMonitor, MetricsLogger metricsLogger,
ActivityManager activityManager,
ConfigurationController configurationController,
Provider<FlingAnimationUtils.Builder> flingAnimationUtilsBuilder,
@@ -706,6 +737,7 @@
KeyguardQsUserSwitchComponent.Factory keyguardQsUserSwitchComponentFactory,
KeyguardUserSwitcherComponent.Factory keyguardUserSwitcherComponentFactory,
KeyguardStatusBarViewComponent.Factory keyguardStatusBarViewComponentFactory,
+ CommunalViewComponent.Factory communalViewComponentFactory,
LockscreenShadeTransitionController lockscreenShadeTransitionController,
QSDetailDisplayer qsDetailDisplayer,
NotificationGroupManagerLegacy groupManager,
@@ -717,7 +749,6 @@
NotificationShadeDepthController notificationShadeDepthController,
AmbientState ambientState,
LockIconViewController lockIconViewController,
- FeatureFlags featureFlags,
KeyguardMediaController keyguardMediaController,
PrivacyDotViewController privacyDotViewController,
TapAgainViewController tapAgainViewController,
@@ -749,10 +780,10 @@
mNotificationStackScrollLayoutController = notificationStackScrollLayoutController;
mGroupManager = groupManager;
mNotificationIconAreaController = notificationIconAreaController;
+ mCommunalViewComponentFactory = communalViewComponentFactory;
mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory;
mKeyguardStatusBarViewComponentFactory = keyguardStatusBarViewComponentFactory;
mDepthController = notificationShadeDepthController;
- mFeatureFlags = featureFlags;
mContentResolver = contentResolver;
mKeyguardQsUserSwitchComponentFactory = keyguardQsUserSwitchComponentFactory;
mKeyguardUserSwitcherComponentFactory = keyguardUserSwitcherComponentFactory;
@@ -760,7 +791,7 @@
mFragmentService = fragmentService;
mSettingsChangeObserver = new SettingsChangeObserver(handler);
mShouldUseSplitNotificationShade =
- Utils.shouldUseSplitNotificationShade(mFeatureFlags, mResources);
+ Utils.shouldUseSplitNotificationShade(mResources);
mView.setWillNotDraw(!DEBUG);
mSplitShadeHeaderController = splitShadeHeaderController;
mLayoutInflater = layoutInflater;
@@ -792,6 +823,7 @@
mThemeResId = mView.getContext().getThemeResId();
mKeyguardBypassController = bypassController;
mUpdateMonitor = keyguardUpdateMonitor;
+ mCommunalSourceMonitor = communalSourceMonitor;
mFirstBypassAttempt = mKeyguardBypassController.getBypassEnabled();
KeyguardStateController.Callback
keyguardMonitorCallback =
@@ -853,6 +885,7 @@
loadDimens();
mKeyguardStatusBar = mView.findViewById(R.id.keyguard_header);
mBigClockContainer = mView.findViewById(R.id.big_clock_container);
+ mCommunalView = mView.findViewById(R.id.communal_host);
UserAvatarView userAvatarView = null;
KeyguardUserSwitcherView keyguardUserSwitcherView = null;
@@ -871,7 +904,8 @@
mView.findViewById(R.id.keyguard_status_view),
userAvatarView,
mKeyguardStatusBar,
- keyguardUserSwitcherView);
+ keyguardUserSwitcherView,
+ mCommunalView);
mNotificationContainerParent = mView.findViewById(R.id.notification_container_parent);
NotificationStackScrollLayout stackScrollLayout = mView.findViewById(
R.id.notification_stack_scroller);
@@ -951,8 +985,6 @@
R.dimen.notification_panel_min_side_margin);
mIndicationBottomPadding = mResources.getDimensionPixelSize(
R.dimen.keyguard_indication_bottom_padding);
- mQsNotificationTopPadding = mResources.getDimensionPixelSize(
- R.dimen.qs_notification_padding);
mShelfHeight = mResources.getDimensionPixelSize(R.dimen.notification_shelf_height);
mDarkIconSize = mResources.getDimensionPixelSize(R.dimen.status_bar_icon_drawing_size_dark);
int statusbarHeight = mResources.getDimensionPixelSize(
@@ -973,7 +1005,8 @@
private void updateViewControllers(KeyguardStatusView keyguardStatusView,
UserAvatarView userAvatarView,
KeyguardStatusBarView keyguardStatusBarView,
- KeyguardUserSwitcherView keyguardUserSwitcherView) {
+ KeyguardUserSwitcherView keyguardUserSwitcherView,
+ CommunalHostView communalView) {
// Re-associate the KeyguardStatusViewController
KeyguardStatusViewComponent statusViewComponent =
mKeyguardStatusViewComponentFactory.build(keyguardStatusView);
@@ -986,6 +1019,13 @@
statusBarViewComponent.getKeyguardStatusBarViewController();
mKeyguarStatusBarViewController.init();
+ if (communalView != null) {
+ CommunalViewComponent communalViewComponent =
+ mCommunalViewComponentFactory.build(communalView);
+ mCommunalViewController =
+ communalViewComponent.getCommunalHostViewController();
+ }
+
if (mKeyguardUserSwitcherController != null) {
// Try to close the switcher so that callbacks are triggered if necessary.
// Otherwise, NPV can get into a state where some of the views are still hidden
@@ -1037,7 +1077,7 @@
int qsWidth = mResources.getDimensionPixelSize(R.dimen.qs_panel_width);
int panelWidth = mResources.getDimensionPixelSize(R.dimen.notification_panel_width);
mShouldUseSplitNotificationShade =
- Utils.shouldUseSplitNotificationShade(mFeatureFlags, mResources);
+ Utils.shouldUseSplitNotificationShade(mResources);
mScrimController.setClipsQsScrim(!mShouldUseSplitNotificationShade);
if (mQs != null) {
mQs.setTranslateWhileExpanding(mShouldUseSplitNotificationShade);
@@ -1051,6 +1091,7 @@
ensureAllViewsHaveIds(mNotificationContainerParent);
ConstraintSet constraintSet = new ConstraintSet();
constraintSet.clone(mNotificationContainerParent);
+
if (mShouldUseSplitNotificationShade) {
// width = 0 to take up all available space within constraints
qsWidth = 0;
@@ -1145,7 +1186,7 @@
mBigClockContainer.removeAllViews();
updateViewControllers(mView.findViewById(R.id.keyguard_status_view), userAvatarView,
- mKeyguardStatusBar, keyguardUserSwitcherView);
+ mKeyguardStatusBar, keyguardUserSwitcherView, mCommunalView);
// Update keyguard bottom area
int index = mView.indexOfChild(mKeyguardBottomArea);
@@ -1354,6 +1395,10 @@
mKeyguardStatusViewController.updatePosition(
mClockPositionResult.clockX, mClockPositionResult.clockY,
mClockPositionResult.clockScale, animateClock);
+ // CommunalView's height is constrained to KeyguardStatusView. Match Y offset as well.
+ if (mCommunalViewController != null) {
+ mCommunalViewController.updatePositionY(mClockPositionResult.clockY, animateClock);
+ }
if (mKeyguardQsUserSwitchController != null) {
mKeyguardQsUserSwitchController.updatePosition(
mClockPositionResult.clockX,
@@ -1373,7 +1418,9 @@
private void updateKeyguardStatusViewAlignment(boolean animate) {
boolean hasVisibleNotifications = mNotificationStackScrollLayoutController
.getVisibleNotificationCount() != 0 || mMediaDataManager.hasActiveMedia();
- boolean shouldBeCentered = !mShouldUseSplitNotificationShade || !hasVisibleNotifications;
+ boolean hasCommunalSurface = mCommunalSource != null && mCommunalSource.get() != null;
+ boolean shouldBeCentered = !mShouldUseSplitNotificationShade
+ || (!hasVisibleNotifications && !hasCommunalSurface);
if (mStatusViewCentered != shouldBeCentered) {
mStatusViewCentered = shouldBeCentered;
ConstraintSet constraintSet = new ConstraintSet();
@@ -1386,6 +1433,21 @@
transition.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
TransitionManager.beginDelayedTransition(mNotificationContainerParent, transition);
}
+
+ // By default, the CommunalView is not shown. We set parameters as if it is shown, which
+ // are based on it being aligned with the start of the qs edge guide, like the
+ // notification stack scroller. These constraints cannot be expressed in the layout as
+ // they reference a peer rather than the parent.
+ constraintSet.connect(
+ R.id.communal_host, START,
+ R.id.qs_edge_guideline, START);
+ constraintSet.connect(
+ R.id.communal_host, TOP,
+ R.id.keyguard_status_view, TOP);
+ constraintSet.connect(
+ R.id.communal_host, BOTTOM,
+ R.id.keyguard_status_view, BOTTOM);
+
constraintSet.applyTo(mNotificationContainerParent);
}
}
@@ -1394,14 +1456,18 @@
* @return the padding of the stackscroller when unlocked
*/
private int getUnlockedStackScrollerPadding() {
- return (mQs != null ? mQs.getHeader().getHeight() : 0) + mQsPeekHeight
- + mQsNotificationTopPadding;
+ return (mQs != null ? mQs.getHeader().getHeight() : 0) + mQsPeekHeight;
}
/**
* @return the maximum keyguard notifications that can fit on the screen
*/
private int computeMaxKeyguardNotifications() {
+ // Do not show any notifications on the keyguard if a communal source is set.
+ if (mCommunalSource != null && mCommunalSource.get() != null) {
+ return 0;
+ }
+
float minPadding = mClockPositionAlgorithm.getMinStackScrollerPadding();
int notificationPadding = Math.max(
1, mResources.getDimensionPixelSize(R.dimen.notification_divider_height));
@@ -1615,7 +1681,7 @@
private boolean isQsExpansionEnabled() {
return mQsExpansionEnabledPolicy && mQsExpansionEnabledAmbient
- && !mRemoteInputManager.getController().isRemoteInputActive();
+ && !mRemoteInputManager.isRemoteInputActive();
}
public void expandWithQs() {
@@ -2513,7 +2579,7 @@
// panel. We need to take the maximum and linearly interpolate with the panel expansion
// for a nice motion.
int maxNotificationPadding = getKeyguardNotificationStaticPadding();
- int maxQsPadding = mQsMaxExpansionHeight + mQsNotificationTopPadding;
+ int maxQsPadding = mQsMaxExpansionHeight;
int max = mBarState == KEYGUARD ? Math.max(
maxNotificationPadding, maxQsPadding) : maxQsPadding;
return (int) MathUtils.lerp((float) mQsMinExpansionHeight, (float) max,
@@ -2526,10 +2592,10 @@
// We can only do the smoother transition on Keyguard when we also are not collapsing
// from a scrolled quick settings.
return MathUtils.lerp((float) getKeyguardNotificationStaticPadding(),
- (float) (mQsMaxExpansionHeight + mQsNotificationTopPadding),
+ (float) (mQsMaxExpansionHeight),
computeQsExpansionFraction());
} else {
- return mQsExpansionHeight + mQsNotificationTopPadding;
+ return mQsExpansionHeight;
}
}
@@ -2915,10 +2981,6 @@
}
int maxQsHeight = mQsMaxExpansionHeight;
- if (mKeyguardShowing) {
- maxQsHeight += mQsNotificationTopPadding;
- }
-
// If an animation is changing the size of the QS panel, take the animated value.
if (mQsSizeChangeAnimator != null) {
maxQsHeight = (int) mQsSizeChangeAnimator.getAnimatedValue();
@@ -3695,8 +3757,6 @@
public void setAmbientIndicationBottomPadding(int ambientIndicationBottomPadding) {
if (mAmbientIndicationBottomPadding != ambientIndicationBottomPadding) {
mAmbientIndicationBottomPadding = ambientIndicationBottomPadding;
- mLockIconViewController.setAmbientIndicationBottomPadding(
- mAmbientIndicationBottomPadding);
updateMaxDisplayedNotifications(true);
}
}
@@ -4361,8 +4421,7 @@
if (mAccessibilityManager.isEnabled()) {
mView.setAccessibilityPaneTitle(determineAccessibilityPaneTitle());
}
- mNotificationStackScrollLayoutController.setMaxTopPadding(
- mQsMaxExpansionHeight + mQsNotificationTopPadding);
+ mNotificationStackScrollLayoutController.setMaxTopPadding(mQsMaxExpansionHeight);
}
}
@@ -4513,6 +4572,27 @@
setExpandedFraction(1f);
}
+ private void setCommunalSource(WeakReference<CommunalSource> source) {
+ CommunalSource existingSource = mCommunalSource != null ? mCommunalSource.get() : null;
+
+ if (existingSource != null) {
+ existingSource.removeCallback(mCommunalSourceCallback);
+ mCommunalViewController.show(null /*source*/);
+ }
+
+ mCommunalSource = source;
+
+ CommunalSource currentSource = mCommunalSource != null ? mCommunalSource.get() : null;
+ // Set source and register callback
+ if (currentSource != null && mCommunalViewController != null) {
+ currentSource.addCallback(mCommunalSourceCallback);
+ mCommunalViewController.show(source);
+ }
+
+ updateKeyguardStatusViewAlignment(true /*animate*/);
+ updateMaxDisplayedNotifications(true /*recompute*/);
+ }
+
/**
* Sets the overstretch amount in raw pixels when dragging down.
*/
@@ -4529,6 +4609,7 @@
mStatusBarStateController.addCallback(mStatusBarStateListener);
mConfigurationController.addCallback(mConfigurationListener);
mUpdateMonitor.registerCallback(mKeyguardUpdateCallback);
+ mCommunalSourceMonitor.addCallback(mCommunalSourceMonitorCallback);
// Theme might have changed between inflating this view and attaching it to the
// window, so
// force a call to onThemeChanged
@@ -4546,6 +4627,9 @@
mStatusBarStateController.removeCallback(mStatusBarStateListener);
mConfigurationController.removeCallback(mConfigurationListener);
mUpdateMonitor.removeCallback(mKeyguardUpdateCallback);
+ mCommunalSourceMonitor.removeCallback(mCommunalSourceMonitorCallback);
+ // Clear source when detached.
+ setCommunalSource(null /*source*/);
mFalsingManager.removeTapListener(mFalsingTapListener);
}
}
@@ -4571,8 +4655,7 @@
if (mQs != null) {
updateQSMinHeight();
mQsMaxExpansionHeight = mQs.getDesiredHeight();
- mNotificationStackScrollLayoutController.setMaxTopPadding(
- mQsMaxExpansionHeight + mQsNotificationTopPadding);
+ mNotificationStackScrollLayoutController.setMaxTopPadding(mQsMaxExpansionHeight);
}
positionClockAndNotifications();
if (mQsExpanded && mQsFullyExpanded) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 31a432e..c300b11 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -23,6 +23,7 @@
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Configuration;
+import android.graphics.Point;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.EventLog;
@@ -52,6 +53,7 @@
private static final boolean DEBUG = StatusBar.DEBUG;
private static final boolean DEBUG_GESTURES = false;
private final CommandQueue mCommandQueue;
+ private final StatusBarContentInsetsProvider mContentInsetsProvider;
StatusBar mBar;
@@ -85,11 +87,10 @@
private int mCutoutSideNudge = 0;
private boolean mHeadsUpVisible;
- private int mRoundedCornerPadding = 0;
-
public PhoneStatusBarView(Context context, AttributeSet attrs) {
super(context, attrs);
mCommandQueue = Dependency.get(CommandQueue.class);
+ mContentInsetsProvider = Dependency.get(StatusBarContentInsetsProvider.class);
}
public void setBar(StatusBar bar) {
@@ -305,8 +306,6 @@
public void updateResources() {
mCutoutSideNudge = getResources().getDimensionPixelSize(
R.dimen.display_cutout_margin_consumption);
- mRoundedCornerPadding = getResources().getDimensionPixelSize(
- R.dimen.rounded_corner_content_padding);
updateStatusBarHeight();
}
@@ -341,8 +340,7 @@
private void updateLayoutForCutout() {
updateStatusBarHeight();
updateCutoutLocation(StatusBarWindowView.cornerCutoutMargins(mDisplayCutout, getDisplay()));
- updateSafeInsets(StatusBarWindowView.statusBarCornerCutoutMargins(mDisplayCutout,
- getDisplay(), mRotationOrientation, mStatusBarHeight));
+ updateSafeInsets();
}
private void updateCutoutLocation(Pair<Integer, Integer> cornerCutoutMargins) {
@@ -370,15 +368,18 @@
lp.height = bounds.height();
}
- private void updateSafeInsets(Pair<Integer, Integer> cornerCutoutMargins) {
- // Depending on our rotation, we may have to work around a cutout in the middle of the view,
- // or letterboxing from the right or left sides.
+ private void updateSafeInsets() {
+ Rect contentRect = mContentInsetsProvider
+ .getStatusBarContentInsetsForRotation(RotationUtils.getExactRotation(getContext()));
- Pair<Integer, Integer> padding =
- StatusBarWindowView.paddingNeededForCutoutAndRoundedCorner(
- mDisplayCutout, cornerCutoutMargins, mRoundedCornerPadding);
+ Point size = new Point();
+ getDisplay().getRealSize(size);
- setPadding(padding.first, getPaddingTop(), padding.second, getPaddingBottom());
+ setPadding(
+ contentRect.left,
+ getPaddingTop(),
+ size.x - contentRect.right,
+ getPaddingBottom());
}
public void setHeadsUpVisible(boolean headsUpVisible) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt
index d29107d..70f3436 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt
@@ -34,6 +34,7 @@
featureFlags: FeatureFlags
) {
+ // TODO(b/194178072) Handle RSSI hiding when multi carrier
private val iconManager: StatusBarIconController.IconManager
private val qsCarrierGroupController: QSCarrierGroupController
private var visible = false
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 bc3a770..9bdb3cf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -187,6 +187,7 @@
import com.android.systemui.scrim.ScrimView;
import com.android.systemui.settings.brightness.BrightnessSlider;
import com.android.systemui.shared.plugins.PluginManager;
+import com.android.unfold.config.UnfoldTransitionConfig;
import com.android.systemui.statusbar.AutoHideUiElement;
import com.android.systemui.statusbar.BackDropView;
import com.android.systemui.statusbar.CircleReveal;
@@ -245,6 +246,7 @@
import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation;
import com.android.systemui.volume.VolumeComponent;
import com.android.systemui.wmshell.BubblesManager;
import com.android.wm.shell.bubbles.Bubbles;
@@ -442,6 +444,7 @@
private final OngoingCallController mOngoingCallController;
private final SystemStatusAnimationScheduler mAnimationScheduler;
private final StatusBarLocationPublisher mStatusBarLocationPublisher;
+ private final StatusBarIconController mStatusBarIconController;
// expanded notifications
// the sliding/resizing panel within the notification window
@@ -467,6 +470,8 @@
protected final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
private final BrightnessSlider.Factory mBrightnessSliderFactory;
private final FeatureFlags mFeatureFlags;
+ private final UnfoldTransitionConfig mUnfoldTransitionConfig;
+ private final Lazy<UnfoldLightRevealOverlayAnimation> mUnfoldLightRevealOverlayAnimation;
private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
@@ -801,9 +806,12 @@
NotificationIconAreaController notificationIconAreaController,
BrightnessSlider.Factory brightnessSliderFactory,
WiredChargingRippleController chargingRippleAnimationController,
+ UnfoldTransitionConfig unfoldTransitionConfig,
+ Lazy<UnfoldLightRevealOverlayAnimation> unfoldLightRevealOverlayAnimation,
OngoingCallController ongoingCallController,
SystemStatusAnimationScheduler animationScheduler,
StatusBarLocationPublisher locationPublisher,
+ StatusBarIconController statusBarIconController,
LockscreenShadeTransitionController lockscreenShadeTransitionController,
FeatureFlags featureFlags,
KeyguardUnlockAnimationController keyguardUnlockAnimationController,
@@ -887,9 +895,12 @@
mNotificationIconAreaController = notificationIconAreaController;
mBrightnessSliderFactory = brightnessSliderFactory;
mChargingRippleAnimationController = chargingRippleAnimationController;
+ mUnfoldTransitionConfig = unfoldTransitionConfig;
+ mUnfoldLightRevealOverlayAnimation = unfoldLightRevealOverlayAnimation;
mOngoingCallController = ongoingCallController;
mAnimationScheduler = animationScheduler;
mStatusBarLocationPublisher = locationPublisher;
+ mStatusBarIconController = statusBarIconController;
mFeatureFlags = featureFlags;
mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController;
@@ -1058,6 +1069,10 @@
mFalsingManager.addFalsingBeliefListener(mFalsingBeliefListener);
+ if (mUnfoldTransitionConfig.isEnabled()) {
+ mUnfoldLightRevealOverlayAnimation.get().init();
+ }
+
mPluginManager.addPluginListener(
new PluginListener<OverlayPlugin>() {
private ArraySet<OverlayPlugin> mOverlays = new ArraySet<>();
@@ -1193,7 +1208,13 @@
mStatusBarLocationPublisher,
mNotificationIconAreaController,
mFeatureFlags,
- () -> Optional.of(this)),
+ mStatusBarIconController,
+ mKeyguardStateController,
+ mNetworkController,
+ mStatusBarStateController,
+ () -> Optional.of(this),
+ mCommandQueue
+ ),
CollapsedStatusBarFragment.TAG)
.commit();
@@ -1224,7 +1245,7 @@
@Override
public boolean shouldHideOnTouch() {
- return !mRemoteInputManager.getController().isRemoteInputActive();
+ return !mRemoteInputManager.isRemoteInputActive();
}
@Override
@@ -1444,7 +1465,7 @@
mNotificationInterruptStateProvider);
mNotificationShelfController.setOnActivatedListener(mPresenter);
- mRemoteInputManager.getController().addCallback(mNotificationShadeWindowController);
+ mRemoteInputManager.addControllerCallback(mNotificationShadeWindowController);
mNotificationActivityStarter =
mStatusBarNotificationActivityStarterBuilder
@@ -1619,7 +1640,7 @@
mKeyguardIndicationController
.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
mBiometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager);
- mRemoteInputManager.getController().addCallback(mStatusBarKeyguardViewManager);
+ mRemoteInputManager.addControllerCallback(mStatusBarKeyguardViewManager);
mDynamicPrivacyController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
mLightBarController.setBiometricUnlockController(mBiometricUnlockController);
@@ -2741,6 +2762,11 @@
mScrimController.dump(fd, pw, args);
}
+ if (mLightRevealScrim != null) {
+ pw.println(
+ "mLightRevealScrim.getRevealAmount(): " + mLightRevealScrim.getRevealAmount());
+ }
+
if (mStatusBarKeyguardViewManager != null) {
mStatusBarKeyguardViewManager.dump(pw);
}
@@ -3037,9 +3063,7 @@
String action = intent.getAction();
if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
KeyboardShortcuts.dismiss();
- if (mRemoteInputManager.getController() != null) {
- mRemoteInputManager.getController().closeRemoteInputs();
- }
+ mRemoteInputManager.closeRemoteInputs();
if (mBubblesOptional.isPresent() && mBubblesOptional.get().isStackExpanded()) {
mBubblesOptional.get().collapseStack();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt
index edcf261..1dd22b4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt
@@ -155,13 +155,30 @@
val dc = context.display.cutout
val currentRotation = RotationUtils.getExactRotation(context)
+ val isRtl = rotatedResources.configuration.layoutDirection == LAYOUT_DIRECTION_RTL
+ val roundedCornerPadding = rotatedResources
+ .getDimensionPixelSize(R.dimen.rounded_corner_content_padding)
+ val minDotWidth = rotatedResources
+ .getDimensionPixelSize(R.dimen.ongoing_appops_dot_min_padding)
+
+ val minLeft: Int
+ val minRight: Int
+ if (isRtl) {
+ minLeft = max(minDotWidth, roundedCornerPadding)
+ minRight = roundedCornerPadding
+ } else {
+ minLeft = roundedCornerPadding
+ minRight = max(minDotWidth, roundedCornerPadding)
+ }
+
return calculateInsetsForRotationWithRotatedResources(
currentRotation,
targetRotation,
dc,
windowManager.maximumWindowMetrics,
rotatedResources.getDimensionPixelSize(R.dimen.status_bar_height),
- rotatedResources.getDimensionPixelSize(R.dimen.rounded_corner_content_padding))
+ minLeft,
+ minRight)
}
override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
@@ -212,9 +229,12 @@
* Calculates the exact left and right positions for the status bar contents for the given
* rotation
*
- * @param rot rotation for which to query the margins
- * @param context systemui context
- * @param rotatedResources resources constructed with the proper orientation set
+ * @param currentRotation current device rotation
+ * @param targetRotation rotation for which to calculate the status bar content rect
+ * @param displayCutout [DisplayCutout] for the curren display. possibly null
+ * @param windowMetrics [WindowMetrics] for the current window
+ * @param statusBarHeight height of the status bar for the target rotation
+ * @param roundedCornerPadding from rounded_corner_content_padding
*
* @see [RotationUtils#getResourcesForRotation]
*/
@@ -224,7 +244,8 @@
displayCutout: DisplayCutout?,
windowMetrics: WindowMetrics,
statusBarHeight: Int,
- roundedCornerPadding: Int
+ minLeft: Int,
+ minRight: Int
): Rect {
/*
TODO: Check if this is ever used for devices with no rounded corners
@@ -242,7 +263,8 @@
rotZeroBounds.bottom,
currentBounds.width(),
currentBounds.height(),
- roundedCornerPadding,
+ minLeft,
+ minRight,
targetRotation,
currentRotation)
@@ -256,7 +278,10 @@
* @param sbHeight appropriate status bar height for this rotation
* @param width display width calculated for ROTATION_NONE
* @param height display height calculated for ROTATION_NONE
- * @param roundedCornerPadding rounded_corner_content_padding dimension
+ * @param cWidth display width in our current rotation
+ * @param cHeight display height in our current rotation
+ * @param minLeft the minimum padding to enforce on the left
+ * @param minRight the minimum padding to enforce on the right
* @param targetRotation the rotation for which to calculate margins
* @param currentRotation the rotation from which the display cutout was generated
*
@@ -270,7 +295,8 @@
height: Int,
cWidth: Int,
cHeight: Int,
- roundedCornerPadding: Int,
+ minLeft: Int,
+ minRight: Int,
@Rotation targetRotation: Int,
@Rotation currentRotation: Int
): Rect {
@@ -279,9 +305,9 @@
val cutoutRects = dc?.boundingRects
if (cutoutRects == null || cutoutRects.isEmpty()) {
- return Rect(roundedCornerPadding,
+ return Rect(minLeft,
0,
- logicalDisplayWidth - roundedCornerPadding,
+ logicalDisplayWidth - minRight,
sbHeight)
}
@@ -294,8 +320,8 @@
// Size of the status bar window for the given rotation relative to our exact rotation
val sbRect = sbRect(relativeRotation, sbHeight, Pair(cWidth, cHeight))
- var leftMargin = roundedCornerPadding
- var rightMargin = roundedCornerPadding
+ var leftMargin = minLeft
+ var rightMargin = minRight
for (cutoutRect in cutoutRects) {
// There is at most one non-functional area per short edge of the device. So if the status
// bar doesn't share a short edge with the cutout, we can ignore its insets because there
@@ -306,11 +332,11 @@
if (cutoutRect.touchesLeftEdge(relativeRotation, cWidth, cHeight)) {
- val l = max(roundedCornerPadding, cutoutRect.logicalWidth(relativeRotation))
+ val l = max(minLeft, cutoutRect.logicalWidth(relativeRotation))
leftMargin = max(l, leftMargin)
} else if (cutoutRect.touchesRightEdge(relativeRotation, cWidth, cHeight)) {
val logicalWidth = cutoutRect.logicalWidth(relativeRotation)
- rightMargin = max(roundedCornerPadding, logicalWidth)
+ rightMargin = max(minRight, logicalWidth)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index 9a6dd38..1717b82 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -60,7 +60,6 @@
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
-import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -230,12 +229,11 @@
mLogger.logStartingActivityFromClick(sbn.getKey());
final NotificationEntry entry = row.getEntry();
- RemoteInputController controller = mRemoteInputManager.getController();
- if (controller.isRemoteInputActive(entry)
+ if (mRemoteInputManager.isRemoteInputActive(entry)
&& !TextUtils.isEmpty(row.getActiveRemoteInputText())) {
// We have an active remote input typed and the user clicked on the notification.
// this was probably unintentional, so we're closing the edit text instead.
- controller.closeRemoteInputs();
+ mRemoteInputManager.closeRemoteInputs();
return;
}
Notification notification = sbn.getNotification();
@@ -265,8 +263,7 @@
@Override
public boolean onDismiss() {
return handleNotificationClickAfterKeyguardDismissed(
- entry, row, controller, intent,
- isActivityIntent, animate, showOverLockscreen);
+ entry, row, intent, isActivityIntent, animate, showOverLockscreen);
}
@Override
@@ -286,7 +283,6 @@
private boolean handleNotificationClickAfterKeyguardDismissed(
NotificationEntry entry,
ExpandableNotificationRow row,
- RemoteInputController controller,
PendingIntent intent,
boolean isActivityIntent,
boolean animate,
@@ -294,8 +290,7 @@
mLogger.logHandleClickAfterKeyguardDismissed(entry.getKey());
final Runnable runnable = () -> handleNotificationClickAfterPanelCollapsed(
- entry, row, controller, intent,
- isActivityIntent, animate);
+ entry, row, intent, isActivityIntent, animate);
if (showOverLockscreen) {
mShadeController.addPostCollapseAction(runnable);
@@ -315,7 +310,6 @@
private void handleNotificationClickAfterPanelCollapsed(
NotificationEntry entry,
ExpandableNotificationRow row,
- RemoteInputController controller,
PendingIntent intent,
boolean isActivityIntent,
boolean animate) {
@@ -354,7 +348,8 @@
if (!TextUtils.isEmpty(entry.remoteInputText)) {
remoteInputText = entry.remoteInputText;
}
- if (!TextUtils.isEmpty(remoteInputText) && !controller.isSpinning(notificationKey)) {
+ if (!TextUtils.isEmpty(remoteInputText)
+ && !mRemoteInputManager.isSpinning(notificationKey)) {
fillInIntent = new Intent().putExtra(Notification.EXTRA_REMOTE_INPUT_DRAFT,
remoteInputText.toString());
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index aa58527..cb844d8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -24,12 +24,14 @@
import android.content.Context;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SystemClock;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.service.vr.IVrManager;
import android.service.vr.IVrStateCallbacks;
import android.util.Log;
import android.util.Slog;
+import android.view.View;
import android.view.accessibility.AccessibilityManager;
import android.widget.TextView;
@@ -179,8 +181,6 @@
remoteInputManager.setUpWithCallback(
Dependency.get(NotificationRemoteInputManager.Callback.class),
mNotificationPanel.createRemoteInputDelegate());
- remoteInputManager.getController().addCallback(
- Dependency.get(NotificationShadeWindowController.class));
initController.addPostInitTask(() -> {
NotificationEntryListener notificationEntryListener = new NotificationEntryListener() {
@@ -394,8 +394,10 @@
}
@Override
- public void onExpandClicked(NotificationEntry clickedEntry, boolean nowExpanded) {
+ public void onExpandClicked(NotificationEntry clickedEntry, View clickedView,
+ boolean nowExpanded) {
mHeadsUpManager.setExpanded(clickedEntry, nowExpanded);
+ mStatusBar.wakeUpIfDozing(SystemClock.uptimeMillis(), clickedView, "NOTIFICATION_CLICK");
if (nowExpanded) {
if (mStatusBarStateController.getState() == StatusBarState.KEYGUARD) {
mShadeTransitionController.goToLockedShade(clickedEntry.getRow());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
index 64a497d..3292934 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
@@ -245,8 +245,19 @@
* @param slotName name of the icon slot to remove from the ignored list
*/
public void removeIgnoredSlot(String slotName) {
- if (mIgnoredSlots.contains(slotName)) {
- mIgnoredSlots.remove(slotName);
+ mIgnoredSlots.remove(slotName);
+
+ requestLayout();
+ }
+
+ /**
+ * Remove a list of slots from the list of ignored icon slots.
+ * It will then be shown when set to visible by the {@link StatusBarIconController}.
+ * @param slots name of the icon slots to remove from the ignored list
+ */
+ public void removeIgnoredSlots(List<String> slots) {
+ for (String slot : slots) {
+ mIgnoredSlots.remove(slot);
}
requestLayout();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
index 4167287..a5b868b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
@@ -199,10 +199,9 @@
// We currently draw both the light reveal scrim, and the AOD UI, in the shade. If it's
// already expanded and showing notifications/QS, the animation looks really messy. For now,
- // disable it if the notification panel is expanded.
+ // disable it if the notification panel is not fully collapsed.
if (!this::statusBar.isInitialized ||
- statusBar.notificationPanelViewController.isFullyExpanded ||
- statusBar.notificationPanelViewController.isExpanding) {
+ !statusBar.notificationPanelViewController.isFullyCollapsed) {
return false
}
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 716d1db..5e8eecb 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
@@ -48,6 +48,7 @@
import com.android.systemui.recents.ScreenPinningRequest;
import com.android.systemui.settings.brightness.BrightnessSlider;
import com.android.systemui.shared.plugins.PluginManager;
+import com.android.unfold.config.UnfoldTransitionConfig;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.KeyguardIndicationController;
@@ -89,6 +90,7 @@
import com.android.systemui.statusbar.phone.ScrimController;
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;
@@ -105,6 +107,7 @@
import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation;
import com.android.systemui.volume.VolumeComponent;
import com.android.systemui.wmshell.BubblesManager;
import com.android.wm.shell.bubbles.Bubbles;
@@ -213,9 +216,12 @@
NotificationIconAreaController notificationIconAreaController,
BrightnessSlider.Factory brightnessSliderFactory,
WiredChargingRippleController chargingRippleAnimationController,
+ UnfoldTransitionConfig unfoldTransitionConfig,
+ Lazy<UnfoldLightRevealOverlayAnimation> unfoldLightRevealOverlayAnimation,
OngoingCallController ongoingCallController,
SystemStatusAnimationScheduler animationScheduler,
StatusBarLocationPublisher locationPublisher,
+ StatusBarIconController statusBarIconController,
LockscreenShadeTransitionController transitionController,
FeatureFlags featureFlags,
KeyguardUnlockAnimationController keyguardUnlockAnimationController,
@@ -302,9 +308,12 @@
notificationIconAreaController,
brightnessSliderFactory,
chargingRippleAnimationController,
+ unfoldTransitionConfig,
+ unfoldLightRevealOverlayAnimation,
ongoingCallController,
animationScheduler,
locationPublisher,
+ statusBarIconController,
transitionController,
featureFlags,
keyguardUnlockAnimationController,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java
index 5a3d725..4ca1f60 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java
@@ -119,6 +119,11 @@
new UserHandle(mCurrentUser));
}
+ public boolean canConfigMobileData() {
+ return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS,
+ UserHandle.of(mCurrentUser));
+ }
+
public void onUserSwitched(int newUserId) {
mCurrentUser = newUserId;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java
index c2bd87c..3a05ec7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java
@@ -30,6 +30,9 @@
/** Alert controller of a change in between light and dark themes. */
void notifyThemeChanged();
+ /** Query the current configuration's layout direction */
+ boolean isLayoutRtl();
+
interface ConfigurationListener {
default void onConfigChanged(Configuration newConfig) {}
default void onDensityOrFontScaleChanged() {}
@@ -38,5 +41,6 @@
default void onUiModeChanged() {}
default void onThemeChanged() {}
default void onLocaleListChanged() {}
+ default void onLayoutDirectionChanged(boolean isLayoutRtl) {}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index 6b71f46..eeea699 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -228,6 +228,7 @@
int getIcon(WifiEntry ap);
boolean connect(WifiEntry ap);
boolean canConfigWifi();
+ boolean canConfigMobileData();
public interface AccessPointCallback {
void onAccessPointsChanged(List<WifiEntry> accessPoints);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index acbbde5..52c37a9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -793,7 +793,8 @@
mReceiverHandler.post(this::handleConfigurationChanged);
break;
case Settings.Panel.ACTION_INTERNET_CONNECTIVITY:
- mMainHandler.post(() -> mInternetDialogFactory.create(true));
+ boolean canConfigMobileData = mAccessPoints.canConfigMobileData();
+ mMainHandler.post(() -> mInternetDialogFactory.create(true, canConfigMobileData));
break;
default:
int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 107fb94..6af632d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -562,6 +562,13 @@
mSecondaryUser = userInfo.id;
}
unpauseRefreshUsers = true;
+ if (mGuestUserAutoCreated) {
+ // Guest user must be scheduled for creation AFTER switching to the target user.
+ // This avoids lock contention which will produce UX bugs on the keyguard
+ // (b/193933686).
+ // TODO(b/191067027): Move guest user recreation to system_server
+ guaranteeGuestPresent();
+ }
} else if (Intent.ACTION_USER_INFO_CHANGED.equals(intent.getAction())) {
forcePictureLoadForId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
UserHandle.USER_NULL);
@@ -678,10 +685,6 @@
switchToUserId(newGuestId);
mUserManager.removeUser(currentUser.id);
} else {
- if (mGuestUserAutoCreated) {
- // TODO(b/191067027): Move guest recreation to system_server
- scheduleGuestCreation();
- }
switchToUserId(targetUserId);
mUserManager.removeUser(currentUser.id);
}
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java
index 843630b..c3b4fbe 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java
@@ -197,8 +197,10 @@
.collect(Collectors.toList());
OverlayManagerTransaction.Builder transaction = getTransactionBuilder();
+ HashSet<OverlayIdentifier> identifiersPending = new HashSet<>();
if (pendingCreation != null) {
for (FabricatedOverlay overlay : pendingCreation) {
+ identifiersPending.add(overlay.getIdentifier());
transaction.registerFabricatedOverlay(overlay);
}
}
@@ -206,14 +208,14 @@
for (Pair<String, String> packageToDisable : overlaysToDisable) {
OverlayIdentifier overlayInfo = new OverlayIdentifier(packageToDisable.second);
setEnabled(transaction, overlayInfo, packageToDisable.first, currentUser,
- managedProfiles, false);
+ managedProfiles, false, identifiersPending.contains(overlayInfo));
}
for (String category : THEME_CATEGORIES) {
if (categoryToPackage.containsKey(category)) {
OverlayIdentifier overlayInfo = categoryToPackage.get(category);
setEnabled(transaction, overlayInfo, category, currentUser, managedProfiles,
- true);
+ true, identifiersPending.contains(overlayInfo));
}
}
@@ -233,7 +235,7 @@
@AnyThread
private void setEnabled(OverlayManagerTransaction.Builder transaction,
OverlayIdentifier identifier, String category, int currentUser,
- Set<UserHandle> managedProfiles, boolean enabled) {
+ Set<UserHandle> managedProfiles, boolean enabled, boolean pendingCreation) {
if (DEBUG) {
Log.d(TAG, "setEnabled: " + identifier.getPackageName() + " category: "
+ category + ": " + enabled);
@@ -241,7 +243,7 @@
OverlayInfo overlayInfo = mOverlayManager.getOverlayInfo(identifier,
UserHandle.of(currentUser));
- if (overlayInfo == null) {
+ if (overlayInfo == null && !pendingCreation) {
Log.i(TAG, "Won't enable " + identifier + ", it doesn't exist for user"
+ currentUser);
return;
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
new file mode 100644
index 0000000..8e7c49a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
@@ -0,0 +1,127 @@
+/*
+ * 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.unfold
+
+import android.content.Context
+import android.graphics.PixelFormat
+import android.hardware.devicestate.DeviceStateManager
+import android.hardware.devicestate.DeviceStateManager.FoldStateListener
+import android.view.Surface
+import android.view.WindowManager
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.unfold.UnfoldTransitionProgressProvider
+import com.android.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
+import com.android.systemui.statusbar.LightRevealScrim
+import com.android.systemui.statusbar.LinearLightRevealEffect
+import java.util.concurrent.Executor
+import java.util.function.Consumer
+import javax.inject.Inject
+
+@SysUISingleton
+class UnfoldLightRevealOverlayAnimation @Inject constructor(
+ private val context: Context,
+ private val deviceStateManager: DeviceStateManager,
+ private val unfoldTransitionProgressProvider: UnfoldTransitionProgressProvider,
+ @Main private val executor: Executor,
+ private val windowManager: WindowManager
+) {
+
+ private val transitionListener = TransitionListener()
+ private var scrimView: LightRevealScrim? = null
+
+ fun init() {
+ deviceStateManager.registerCallback(executor, FoldListener())
+ unfoldTransitionProgressProvider.addCallback(transitionListener)
+ }
+
+ private inner class TransitionListener : TransitionProgressListener {
+
+ override fun onTransitionProgress(progress: Float) {
+ scrimView?.revealAmount = progress
+ }
+
+ override fun onTransitionFinished() {
+ removeOverlayView()
+ }
+
+ override fun onTransitionStarted() {
+ }
+ }
+
+ private inner class FoldListener : FoldStateListener(context, Consumer { isFolded ->
+ if (isFolded) {
+ removeOverlayView()
+ } else {
+ // Add overlay view before starting the transition as soon as we unfolded the device
+ addOverlayView()
+ }
+ })
+
+ private fun addOverlayView() {
+ val params: WindowManager.LayoutParams = WindowManager.LayoutParams()
+ params.height = WindowManager.LayoutParams.MATCH_PARENT
+ params.width = WindowManager.LayoutParams.MATCH_PARENT
+ params.format = PixelFormat.TRANSLUCENT
+
+ // TODO(b/193801466): create a separate type for this overlay
+ params.type = WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY
+ params.title = "Unfold Light Reveal Animation"
+ params.layoutInDisplayCutoutMode =
+ WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
+ params.fitInsetsTypes = 0
+ params.flags = (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ or WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
+ params.setTrustedOverlay()
+
+ val rotation = windowManager.defaultDisplay.rotation
+ val isVerticalFold = rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180
+
+ val newScrimView = LightRevealScrim(context, null)
+ .apply {
+ revealEffect = LinearLightRevealEffect(isVerticalFold)
+ revealAmountListener = Consumer {}
+ revealAmount = 0f
+ }
+
+ val packageName: String = newScrimView.context.opPackageName
+ params.packageName = packageName
+ params.hideTimeoutMilliseconds = OVERLAY_HIDE_TIMEOUT_MILLIS
+
+ if (scrimView?.parent != null) {
+ windowManager.removeView(scrimView)
+ }
+
+ this.scrimView = newScrimView
+
+ try {
+ windowManager.addView(scrimView, params)
+ } catch (e: WindowManager.BadTokenException) {
+ e.printStackTrace()
+ }
+ }
+
+ private fun removeOverlayView() {
+ scrimView?.let {
+ if (it.parent != null) {
+ windowManager.removeViewImmediate(it)
+ }
+ scrimView = null
+ }
+ }
+}
+
+private const val OVERLAY_HIDE_TIMEOUT_MILLIS = 10_000L
diff --git a/packages/SystemUI/src/com/android/systemui/util/Utils.java b/packages/SystemUI/src/com/android/systemui/util/Utils.java
index bf00667..a1cdfd8 100644
--- a/packages/SystemUI/src/com/android/systemui/util/Utils.java
+++ b/packages/SystemUI/src/com/android/systemui/util/Utils.java
@@ -29,7 +29,6 @@
import com.android.systemui.R;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FeatureFlags;
import java.util.List;
import java.util.function.Consumer;
@@ -161,13 +160,11 @@
}
/**
- * Returns true if the device should use the split notification shade, based on feature flags,
- * orientation and screen width.
+ * Returns true if the device should use the split notification shade, based on orientation and
+ * screen width.
*/
- public static boolean shouldUseSplitNotificationShade(FeatureFlags featureFlags,
- Resources resources) {
- return featureFlags.isTwoColumnNotificationShadeEnabled()
- && resources.getBoolean(R.bool.config_use_split_notification_shade);
+ public static boolean shouldUseSplitNotificationShade(Resources resources) {
+ return resources.getBoolean(R.bool.config_use_split_notification_shade);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java b/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java
index 0ecc4e2..4a4f2e9 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java
@@ -31,8 +31,10 @@
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.util.settings.SecureSettings;
+import com.android.systemui.util.time.SystemClock;
import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
@@ -52,9 +54,11 @@
}
private static final String TAG = "QAWController";
+ private static final long RECREATION_TIME_WINDOW = TimeUnit.MINUTES.toMillis(10L);
private final Context mContext;
private final Executor mExecutor;
private final SecureSettings mSecureSettings;
+ private final SystemClock mClock;
private QuickAccessWalletClient mQuickAccessWalletClient;
private ContentObserver mWalletPreferenceObserver;
@@ -62,17 +66,21 @@
private int mWalletPreferenceChangeEvents = 0;
private int mDefaultPaymentAppChangeEvents = 0;
private boolean mWalletEnabled = false;
+ private long mQawClientCreatedTimeMillis;
@Inject
public QuickAccessWalletController(
Context context,
@Main Executor executor,
SecureSettings secureSettings,
- QuickAccessWalletClient quickAccessWalletClient) {
+ QuickAccessWalletClient quickAccessWalletClient,
+ SystemClock clock) {
mContext = context;
mExecutor = executor;
mSecureSettings = secureSettings;
mQuickAccessWalletClient = quickAccessWalletClient;
+ mClock = clock;
+ mQawClientCreatedTimeMillis = mClock.elapsedRealtime();
}
/**
@@ -143,6 +151,11 @@
*/
public void queryWalletCards(
QuickAccessWalletClient.OnWalletCardsRetrievedCallback cardsRetriever) {
+ if (mClock.elapsedRealtime() - mQawClientCreatedTimeMillis
+ > RECREATION_TIME_WINDOW) {
+ Log.i(TAG, "Re-creating the QAW client to avoid stale.");
+ reCreateWalletClient();
+ }
if (!mQuickAccessWalletClient.isWalletFeatureAvailable()) {
Log.d(TAG, "QuickAccessWallet feature is not available.");
return;
@@ -162,6 +175,7 @@
*/
public void reCreateWalletClient() {
mQuickAccessWalletClient = QuickAccessWalletClient.create(mContext);
+ mQawClientCreatedTimeMillis = mClock.elapsedRealtime();
}
private void setupDefaultPaymentAppObserver(
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index fc0214a..e9061af 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -754,6 +754,28 @@
}
@Test
+ public void testActiveSubscriptionBecomesInactive() {
+ List<SubscriptionInfo> list = new ArrayList<>();
+ list.add(TEST_SUBSCRIPTION);
+ when(mSubscriptionManager.getCompleteActiveSubscriptionInfoList()).thenReturn(list);
+ mKeyguardUpdateMonitor.mPhoneStateListener.onActiveDataSubscriptionIdChanged(
+ TEST_SUBSCRIPTION.getSubscriptionId());
+ mTestableLooper.processAllMessages();
+ assertThat(mKeyguardUpdateMonitor.mSimDatas.get(TEST_SUBSCRIPTION.getSubscriptionId()))
+ .isNotNull();
+
+ when(mSubscriptionManager.getCompleteActiveSubscriptionInfoList()).thenReturn(null);
+ mKeyguardUpdateMonitor.mPhoneStateListener.onActiveDataSubscriptionIdChanged(
+ SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+ mTestableLooper.processAllMessages();
+
+ assertThat(mKeyguardUpdateMonitor.mSimDatas.get(TEST_SUBSCRIPTION.getSubscriptionId()))
+ .isNull();
+ assertThat(mKeyguardUpdateMonitor.mSimDatas.get(
+ SubscriptionManager.INVALID_SUBSCRIPTION_ID)).isNull();
+ }
+
+ @Test
public void testIsUserUnlocked() {
// mUserManager will report the user as unlocked on @Before
assertThat(mKeyguardUpdateMonitor.isUserUnlocked(KeyguardUpdateMonitor.getCurrentUser()))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
index e94f836..39d5314 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -20,9 +20,7 @@
import static android.hardware.biometrics.BiometricManager.BIOMETRIC_MULTI_SENSOR_FACE_THEN_FINGERPRINT;
import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNull;
-import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -50,12 +48,14 @@
import android.hardware.biometrics.IBiometricSysuiReceiver;
import android.hardware.biometrics.PromptInfo;
import android.hardware.biometrics.SensorProperties;
+import android.hardware.display.DisplayManager;
import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorProperties;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
import android.os.Bundle;
+import android.os.Handler;
import android.os.RemoteException;
import android.testing.AndroidTestingRunner;
import android.testing.TestableContext;
@@ -110,6 +110,10 @@
private UdfpsController mUdfpsController;
@Mock
private SidefpsController mSidefpsController;
+ @Mock
+ private DisplayManager mDisplayManager;
+ @Mock
+ private Handler mHandler;
@Captor
ArgumentCaptor<IFingerprintAuthenticatorsRegisteredCallback> mAuthenticatorsRegisteredCaptor;
@@ -544,13 +548,12 @@
@Test
public void testSubscribesToOrientationChangesWhenShowingDialog() {
- assertFalse(mAuthController.mOrientationListener.getEnabled());
-
showDialog(new int[]{1} /* sensorIds */, false /* credentialAllowed */);
- assertTrue(mAuthController.mOrientationListener.getEnabled());
+
+ verify(mDisplayManager).registerDisplayListener(any(), eq(mHandler));
mAuthController.hideAuthenticationDialog();
- assertFalse(mAuthController.mOrientationListener.getEnabled());
+ verify(mDisplayManager).unregisterDisplayListener(any());
}
// Helpers
@@ -603,7 +606,7 @@
Provider<SidefpsController> sidefpsControllerFactory) {
super(context, commandQueue, activityTaskManager, windowManager,
fingerprintManager, faceManager, udfpsControllerFactory,
- sidefpsControllerFactory);
+ sidefpsControllerFactory, mDisplayManager, mHandler);
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SidefpsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SidefpsControllerTest.kt
index 7019a4b..977b05c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SidefpsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SidefpsControllerTest.kt
@@ -17,11 +17,13 @@
package com.android.systemui.biometrics
import android.hardware.biometrics.SensorProperties
+import android.hardware.display.DisplayManager
import android.hardware.display.DisplayManagerGlobal
import android.hardware.fingerprint.FingerprintManager
import android.hardware.fingerprint.FingerprintSensorProperties
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
import android.hardware.fingerprint.ISidefpsController
+import android.os.Handler
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.Display
@@ -34,14 +36,15 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
-import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock
import org.mockito.Mockito.`when`
+import org.mockito.Mockito.any
import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
@@ -64,6 +67,10 @@
lateinit var windowManager: WindowManager
@Mock
lateinit var sidefpsView: SidefpsView
+ @Mock
+ lateinit var displayManager: DisplayManager
+ @Mock
+ lateinit var handler: Handler
private val executor = FakeExecutor(FakeSystemClock())
private lateinit var overlayController: ISidefpsController
@@ -94,7 +101,8 @@
)
sideFpsController = SidefpsController(
- mContext, layoutInflater, fingerprintManager, windowManager, executor
+ mContext, layoutInflater, fingerprintManager, windowManager, executor,
+ displayManager, handler
)
overlayController = ArgumentCaptor.forClass(ISidefpsController::class.java).apply {
@@ -104,14 +112,13 @@
@Test
fun testSubscribesToOrientationChangesWhenShowingOverlay() {
- assertThat(sideFpsController.mOrientationListener.enabled).isFalse()
-
overlayController.show()
executor.runAllReady()
- assertThat(sideFpsController.mOrientationListener.enabled).isTrue()
+
+ verify(displayManager).registerDisplayListener(any(), eq(handler))
overlayController.hide()
executor.runAllReady()
- assertThat(sideFpsController.mOrientationListener.enabled).isFalse()
+ verify(displayManager).unregisterDisplayListener(any())
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 8d6e1d8..f53dddb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -17,8 +17,6 @@
package com.android.systemui.biometrics;
import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -33,11 +31,13 @@
import android.content.res.TypedArray;
import android.hardware.biometrics.ComponentInfoInternal;
import android.hardware.biometrics.SensorProperties;
+import android.hardware.display.DisplayManager;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorProperties;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.hardware.fingerprint.IUdfpsOverlayControllerCallback;
+import android.os.Handler;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.Vibrator;
@@ -139,6 +139,10 @@
private KeyguardStateController mKeyguardStateController;
@Mock
private KeyguardBypassController mKeyguardBypassController;
+ @Mock
+ private DisplayManager mDisplayManager;
+ @Mock
+ private Handler mHandler;
private FakeExecutor mFgExecutor;
@@ -208,7 +212,9 @@
mUdfpsHapticsSimulator,
Optional.of(mHbmProvider),
mKeyguardStateController,
- mKeyguardBypassController);
+ mKeyguardBypassController,
+ mDisplayManager,
+ mHandler);
verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture());
mOverlayController = mOverlayCaptor.getValue();
verify(mScreenLifecycle).addObserver(mScreenObserverCaptor.capture());
@@ -324,18 +330,16 @@
@Test
public void testSubscribesToOrientationChangesWhenShowingOverlay() throws Exception {
- assertFalse(mUdfpsController.mOrientationListener.getEnabled());
-
mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
- assertTrue(mUdfpsController.mOrientationListener.getEnabled());
+ verify(mDisplayManager).registerDisplayListener(any(), eq(mHandler));
mOverlayController.hideUdfpsOverlay(TEST_UDFPS_SENSOR_ID);
mFgExecutor.runAllReady();
- assertFalse(mUdfpsController.mOrientationListener.getEnabled());
+ verify(mDisplayManager).unregisterDisplayListener(any());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalHostViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalHostViewControllerTest.java
new file mode 100644
index 0000000..e98cf1f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalHostViewControllerTest.java
@@ -0,0 +1,95 @@
+/*
+ * 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.communal;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.testing.AndroidTestingRunner;
+import android.view.View;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.lang.ref.WeakReference;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class CommunalHostViewControllerTest extends SysuiTestCase {
+ @Mock
+ private Context mContext;
+
+ @Mock
+ private KeyguardStateController mKeyguardStateController;
+
+ @Mock
+ private StatusBarStateController mStatusBarStateController;
+
+ @Mock
+ private CommunalHostView mCommunalView;
+
+ private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
+
+ private CommunalHostViewController mController;
+
+ @Mock
+ private CommunalSource mCommunalSource;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+
+ when(mKeyguardStateController.isShowing()).thenReturn(true);
+
+ mController = new CommunalHostViewController(mFakeExecutor, mKeyguardStateController,
+ mStatusBarStateController, mCommunalView);
+ }
+
+ @Test
+ public void testShow() {
+ ArgumentCaptor<KeyguardStateController.Callback> callbackCapture =
+ ArgumentCaptor.forClass(KeyguardStateController.Callback.class);
+
+ // Capture callback value for later use.
+ verify(mKeyguardStateController).addCallback(callbackCapture.capture());
+
+ // Verify the communal view is shown when the controller is initialized with keyguard
+ // showing (see setup).
+ mController.show(new WeakReference<>(mCommunalSource));
+ mFakeExecutor.runAllReady();
+ verify(mCommunalView).setVisibility(View.VISIBLE);
+
+ // Trigger keyguard off to ensure visibility of communal view is changed accordingly.
+ when(mKeyguardStateController.isShowing()).thenReturn(false);
+ callbackCapture.getValue().onKeyguardShowingChanged();
+ mFakeExecutor.runAllReady();
+ verify(mCommunalView).setVisibility(View.INVISIBLE);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt
index 25ae67b..79b0dd0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt
@@ -16,13 +16,12 @@
package com.android.systemui.media
+import android.test.suitebuilder.annotation.SmallTest
import android.testing.AndroidTestingRunner
import android.view.View.GONE
import android.view.View.VISIBLE
import android.widget.FrameLayout
-import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.statusbar.FeatureFlags
import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.SysuiStatusBarStateController
@@ -52,8 +51,7 @@
private lateinit var statusBarStateController: SysuiStatusBarStateController
@Mock
private lateinit var configurationController: ConfigurationController
- @Mock
- private lateinit var featureFlags: FeatureFlags
+
@Mock
private lateinit var notificationLockscreenUserManager: NotificationLockscreenUserManager
@JvmField @Rule
@@ -77,7 +75,6 @@
bypassController,
statusBarStateController,
notificationLockscreenUserManager,
- featureFlags,
context,
configurationController
)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarButtonTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarButtonTest.java
index d25b3e3..92652a7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarButtonTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarButtonTest.java
@@ -16,12 +16,12 @@
package com.android.systemui.navigationbar;
-import static com.android.systemui.Dependency.EDGE_BACK_GESTURE_HANDLER_PROVIDER;
-
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+import android.content.Context;
import android.graphics.PixelFormat;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
@@ -38,7 +38,6 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.SysuiTestableContext;
import com.android.systemui.assist.AssistManager;
-import com.android.systemui.navigationbar.NavigationBarView;
import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler;
import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -47,6 +46,8 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import java.util.function.Predicate;
@@ -56,6 +57,10 @@
@SmallTest
public class NavigationBarButtonTest extends SysuiTestCase {
+ @Mock
+ EdgeBackGestureHandler.Factory mEdgeBackGestureHandlerFactory;
+ @Mock
+ EdgeBackGestureHandler mEdgeBackGestureHandler;
private static final String TAG = "NavigationBarButtonTest";
private ImageReader mReader;
private NavigationBarView mNavBar;
@@ -63,16 +68,20 @@
@Before
public void setup() {
+ MockitoAnnotations.initMocks(this);
final Display display = createVirtualDisplay();
final SysuiTestableContext context =
(SysuiTestableContext) mContext.createDisplayContext(display);
+ when(mEdgeBackGestureHandlerFactory.create(any(Context.class)))
+ .thenReturn(mEdgeBackGestureHandler);
+
mDependency.injectMockDependency(AssistManager.class);
mDependency.injectMockDependency(OverviewProxyService.class);
mDependency.injectMockDependency(KeyguardStateController.class);
mDependency.injectMockDependency(NavigationBarController.class);
- mDependency.injectTestDependency(EDGE_BACK_GESTURE_HANDLER_PROVIDER,
- () -> mock(EdgeBackGestureHandler.class));
+ mDependency.injectTestDependency(EdgeBackGestureHandler.Factory.class,
+ mEdgeBackGestureHandlerFactory);
mNavBar = new NavigationBarView(context, null);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
index df502f9..ed3c473 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
@@ -24,7 +24,6 @@
import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.HOME_BUTTON_LONG_PRESS_DURATION_MS;
-import static com.android.systemui.Dependency.EDGE_BACK_GESTURE_HANDLER_PROVIDER;
import static com.android.systemui.navigationbar.NavigationBar.NavBarActionEvent.NAVBAR_ASSIST_LONGPRESS;
import static org.junit.Assert.assertEquals;
@@ -119,6 +118,10 @@
private BroadcastDispatcher mBroadcastDispatcher;
@Mock
private UiEventLogger mUiEventLogger;
+ @Mock
+ EdgeBackGestureHandler.Factory mEdgeBackGestureHandlerFactory;
+ @Mock
+ EdgeBackGestureHandler mEdgeBackGestureHandler;
@Rule
public final LeakCheckedTest.SysuiLeakCheck mLeakCheck = new LeakCheckedTest.SysuiLeakCheck();
@@ -129,6 +132,8 @@
public void setup() throws Exception {
MockitoAnnotations.initMocks(this);
+ when(mEdgeBackGestureHandlerFactory.create(any(Context.class)))
+ .thenReturn(mEdgeBackGestureHandler);
mCommandQueue = new CommandQueue(mContext);
setupSysuiDependency();
mDependency.injectMockDependency(AssistManager.class);
@@ -136,8 +141,8 @@
mDependency.injectMockDependency(StatusBarStateController.class);
mDependency.injectMockDependency(NavigationBarController.class);
mOverviewProxyService = mDependency.injectMockDependency(OverviewProxyService.class);
- mDependency.injectTestDependency(EDGE_BACK_GESTURE_HANDLER_PROVIDER,
- () -> mock(EdgeBackGestureHandler.class));
+ mDependency.injectTestDependency(EdgeBackGestureHandler.Factory.class,
+ mEdgeBackGestureHandlerFactory);
TestableLooper.get(this).runWithLooper(() -> {
mNavigationBar = createNavBar(mContext);
mExternalDisplayNavigationBar = createNavBar(mSysuiTestableContextExternal);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTransitionsTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTransitionsTest.java
index 62871dc..6a2a78b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTransitionsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTransitionsTest.java
@@ -16,16 +16,16 @@
package com.android.systemui.navigationbar;
-import static com.android.systemui.Dependency.EDGE_BACK_GESTURE_HANDLER_PROVIDER;
-
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
+import android.content.Context;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
import android.view.IWindowManager;
@@ -44,24 +44,34 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
@SmallTest
public class NavigationBarTransitionsTest extends SysuiTestCase {
+ @Mock
+ EdgeBackGestureHandler.Factory mEdgeBackGestureHandlerFactory;
+ @Mock
+ EdgeBackGestureHandler mEdgeBackGestureHandler;
private NavigationBarTransitions mTransitions;
@Before
public void setup() {
+ MockitoAnnotations.initMocks(this);
+
+ when(mEdgeBackGestureHandlerFactory.create(any(Context.class)))
+ .thenReturn(mEdgeBackGestureHandler);
mDependency.injectMockDependency(IWindowManager.class);
mDependency.injectMockDependency(AssistManager.class);
mDependency.injectMockDependency(OverviewProxyService.class);
mDependency.injectMockDependency(StatusBarStateController.class);
mDependency.injectMockDependency(KeyguardStateController.class);
mDependency.injectMockDependency(NavigationBarController.class);
- mDependency.injectTestDependency(EDGE_BACK_GESTURE_HANDLER_PROVIDER,
- () -> mock(EdgeBackGestureHandler.class));
+ mDependency.injectTestDependency(EdgeBackGestureHandler.Factory.class,
+ mEdgeBackGestureHandlerFactory);
doReturn(mContext)
.when(mDependency.injectMockDependency(NavigationModeController.class))
.getCurrentUserContext();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/NavigationBarContextTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/NavigationBarContextTest.java
index 671b1be..7eb7c8e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/NavigationBarContextTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/NavigationBarContextTest.java
@@ -16,19 +16,20 @@
package com.android.systemui.navigationbar.buttons;
-import static com.android.systemui.Dependency.EDGE_BACK_GESTURE_HANDLER_PROVIDER;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.View;
@@ -37,15 +38,14 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.assist.AssistManager;
-import com.android.systemui.navigationbar.buttons.ContextualButton;
-import com.android.systemui.navigationbar.buttons.ContextualButtonGroup;
-import com.android.systemui.navigationbar.buttons.KeyButtonDrawable;
import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
/** atest NavigationBarContextTest */
@SmallTest
@@ -60,6 +60,11 @@
private static final float DARK_INTENSITY_ERR = 0.0002f;
private static final int ICON_RES_ID = 1;
+ @Mock
+ EdgeBackGestureHandler.Factory mEdgeBackGestureHandlerFactory;
+ @Mock
+ EdgeBackGestureHandler mEdgeBackGestureHandler;
+
private ContextualButtonGroup mGroup;
private ContextualButton mBtn0;
private ContextualButton mBtn1;
@@ -67,9 +72,14 @@
@Before
public void setup() {
+ MockitoAnnotations.initMocks(this);
+
+ when(mEdgeBackGestureHandlerFactory.create(any(Context.class)))
+ .thenReturn(mEdgeBackGestureHandler);
+
mDependency.injectMockDependency(AssistManager.class);
- mDependency.injectTestDependency(EDGE_BACK_GESTURE_HANDLER_PROVIDER,
- () -> mock(EdgeBackGestureHandler.class));
+ mDependency.injectTestDependency(EdgeBackGestureHandler.Factory.class,
+ mEdgeBackGestureHandlerFactory);
mGroup = new ContextualButtonGroup(GROUP_ID);
mBtn0 = new ContextualButton(BUTTON_0_ID, mContext, ICON_RES_ID);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/NearestTouchFrameTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/NearestTouchFrameTest.java
index 2ab2c94..038b42b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/NearestTouchFrameTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/NearestTouchFrameTest.java
@@ -16,18 +16,16 @@
package com.android.systemui.navigationbar.buttons;
-import static com.android.systemui.Dependency.EDGE_BACK_GESTURE_HANDLER_PROVIDER;
-
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.testing.AndroidTestingRunner;
@@ -38,12 +36,13 @@
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.navigationbar.buttons.NearestTouchFrame;
import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import java.util.Map;
@@ -52,12 +51,21 @@
@SmallTest
public class NearestTouchFrameTest extends SysuiTestCase {
+ @Mock
+ EdgeBackGestureHandler.Factory mEdgeBackGestureHandlerFactory;
+ @Mock
+ EdgeBackGestureHandler mEdgeBackGestureHandler;
private NearestTouchFrame mNearestTouchFrame;
@Before
public void setup() {
- mDependency.injectTestDependency(EDGE_BACK_GESTURE_HANDLER_PROVIDER,
- () -> mock(EdgeBackGestureHandler.class));
+ MockitoAnnotations.initMocks(this);
+
+ when(mEdgeBackGestureHandlerFactory.create(any(Context.class)))
+ .thenReturn(mEdgeBackGestureHandler);
+
+ mDependency.injectTestDependency(EdgeBackGestureHandler.Factory.class,
+ mEdgeBackGestureHandlerFactory);
Configuration c = new Configuration(mContext.getResources().getConfiguration());
c.smallestScreenWidthDp = 500;
mNearestTouchFrame = new NearestTouchFrame(mContext, null, c);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index c40977b..8c53091 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -53,7 +53,6 @@
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.phone.AutoTileManager;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarIconController;
@@ -92,8 +91,6 @@
@Mock
private MediaHost mQQSMediaHost;
@Mock
- private FeatureFlags mFeatureFlags;
- @Mock
private FalsingManager mFalsingManager;
public QSFragmentTest() {
@@ -185,7 +182,6 @@
mQSMediaHost,
mQQSMediaHost,
mQsComponentFactory,
- mFeatureFlags,
mFalsingManager);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
index 65e5f97..6ff5aa0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
@@ -49,7 +49,6 @@
import com.android.systemui.qs.customize.QSCustomizerController;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.util.animation.DisappearParameters;
import org.junit.Before;
@@ -93,8 +92,6 @@
@Mock
PagedTileLayout mPagedTileLayout;
@Mock
- FeatureFlags mFeatureFlags;
- @Mock
Resources mResources;
@Mock
Configuration mConfiguration;
@@ -108,9 +105,9 @@
protected TestableQSPanelControllerBase(QSPanel view, QSTileHost host,
QSCustomizerController qsCustomizerController, MediaHost mediaHost,
MetricsLogger metricsLogger, UiEventLogger uiEventLogger, QSLogger qsLogger,
- DumpManager dumpManager, FeatureFlags featureFlags) {
+ DumpManager dumpManager) {
super(view, host, qsCustomizerController, true, mediaHost, metricsLogger, uiEventLogger,
- qsLogger, dumpManager, featureFlags);
+ qsLogger, dumpManager);
}
@Override
@@ -140,7 +137,7 @@
mController = new TestableQSPanelControllerBase(mQSPanel, mQSTileHost,
mQSCustomizerController, mMediaHost,
- mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager, mFeatureFlags);
+ mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager);
mController.init();
reset(mQSTileRevealController);
@@ -152,7 +149,7 @@
QSPanelControllerBase<QSPanel> controller = new TestableQSPanelControllerBase(mQSPanel,
mQSTileHost, mQSCustomizerController, mMediaHost,
- mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager, mFeatureFlags) {
+ mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager) {
@Override
protected QSTileRevealController createTileRevealController() {
return mQSTileRevealController;
@@ -241,18 +238,17 @@
mConfiguration.orientation = Configuration.ORIENTATION_LANDSCAPE;
when(mMediaHost.getVisible()).thenReturn(true);
- when(mFeatureFlags.isTwoColumnNotificationShadeEnabled()).thenReturn(false);
+ when(mResources.getBoolean(R.bool.config_use_split_notification_shade)).thenReturn(false);
mController = new TestableQSPanelControllerBase(mQSPanel, mQSTileHost,
mQSCustomizerController, mMediaHost,
- mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager, mFeatureFlags);
+ mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager);
assertThat(mController.shouldUseHorizontalLayout()).isTrue();
- when(mFeatureFlags.isTwoColumnNotificationShadeEnabled()).thenReturn(true);
when(mResources.getBoolean(R.bool.config_use_split_notification_shade)).thenReturn(true);
mController = new TestableQSPanelControllerBase(mQSPanel, mQSTileHost,
mQSCustomizerController, mMediaHost,
- mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager, mFeatureFlags);
+ mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager);
assertThat(mController.shouldUseHorizontalLayout()).isFalse();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java
index bf6c981..1a87975 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java
@@ -42,7 +42,6 @@
import com.android.systemui.settings.brightness.BrightnessController;
import com.android.systemui.settings.brightness.BrightnessSlider;
import com.android.systemui.settings.brightness.ToggleSlider;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.util.animation.DisappearParameters;
@@ -96,8 +95,6 @@
@Mock
PagedTileLayout mPagedTileLayout;
FalsingManagerFake mFalsingManager = new FalsingManagerFake();
- @Mock
- FeatureFlags mFeatureFlags;
private QSPanelController mController;
@@ -109,6 +106,7 @@
when(mQSPanel.getDumpableTag()).thenReturn("QSPanel");
when(mQSPanel.getOrCreateTileLayout()).thenReturn(mPagedTileLayout);
when(mQSPanel.getTileLayout()).thenReturn(mPagedTileLayout);
+ when(mQSPanel.getResources()).thenReturn(mContext.getResources());
when(mQSTileHost.getTiles()).thenReturn(Collections.singleton(mQSTile));
when(mQSTileHost.createTileView(any(), eq(mQSTile), anyBoolean())).thenReturn(mQSTileView);
when(mToggleSliderViewControllerFactory.create(any(), any()))
@@ -123,7 +121,7 @@
mQSTileHost, mQSCustomizerController, true, mMediaHost,
mQSTileRevealControllerFactory, mDumpManager, mMetricsLogger, mUiEventLogger,
mQSLogger, mBrightnessControllerFactory, mToggleSliderViewControllerFactory,
- mFalsingManager, mFeatureFlags
+ mFalsingManager
);
mController.init();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
index 6e1519a..62ac72e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
@@ -16,8 +16,8 @@
package com.android.systemui.qs
+import android.test.suitebuilder.annotation.SmallTest
import android.testing.AndroidTestingRunner
-import androidx.test.filters.SmallTest
import com.android.internal.logging.MetricsLogger
import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.systemui.SysuiTestCase
@@ -77,6 +77,7 @@
`when`(quickQSPanel.tileLayout).thenReturn(tileLayout)
`when`(quickQSPanel.dumpableTag).thenReturn("")
+ `when`(quickQSPanel.resources).thenReturn(mContext.resources)
`when`(qsTileHost.createTileView(any(), any(), anyBoolean())).thenReturn(tileView)
controller = QuickQSPanelController(
@@ -89,7 +90,6 @@
uiEventLogger,
qsLogger,
dumpManager,
- featureFlags,
quickQsBrightnessController
)
@@ -120,4 +120,4 @@
verify(quickQSPanel, times(limit)).addTile(any())
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
index c259072..8b7e20e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
@@ -50,6 +50,7 @@
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
import org.mockito.Mockito.`when`
+import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@@ -106,6 +107,10 @@
private lateinit var controller: QuickStatusBarHeaderController
+ private lateinit var cameraSlotName: String
+ private lateinit var microphoneSlotName: String
+ private lateinit var locationSlotName: String
+
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
@@ -118,6 +123,13 @@
`when`(view.isAttachedToWindow).thenReturn(true)
`when`(view.context).thenReturn(context)
+ cameraSlotName = mContext.resources.getString(
+ com.android.internal.R.string.status_bar_camera)
+ microphoneSlotName = mContext.resources.getString(
+ com.android.internal.R.string.status_bar_microphone)
+ locationSlotName = mContext.resources.getString(
+ com.android.internal.R.string.status_bar_location)
+
controller = QuickStatusBarHeaderController(
view,
privacyItemController,
@@ -152,10 +164,9 @@
controller.init()
- val captor = argumentCaptor<List<String>>()
- verify(iconContainer).setIgnoredSlots(capture(captor))
-
- assertThat(captor.value).isEmpty()
+ verify(iconContainer).removeIgnoredSlot(cameraSlotName)
+ verify(iconContainer).removeIgnoredSlot(microphoneSlotName)
+ verify(iconContainer).removeIgnoredSlot(locationSlotName)
}
@Test
@@ -164,15 +175,9 @@
controller.init()
- val captor = argumentCaptor<List<String>>()
- verify(iconContainer).setIgnoredSlots(capture(captor))
-
- val cameraString = mContext.resources.getString(
- com.android.internal.R.string.status_bar_camera)
- val micString = mContext.resources.getString(
- com.android.internal.R.string.status_bar_microphone)
-
- assertThat(captor.value).containsExactly(cameraString, micString)
+ verify(iconContainer).addIgnoredSlot(cameraSlotName)
+ verify(iconContainer).addIgnoredSlot(microphoneSlotName)
+ verify(iconContainer).removeIgnoredSlot(locationSlotName)
}
@Test
@@ -181,13 +186,9 @@
controller.init()
- val captor = argumentCaptor<List<String>>()
- verify(iconContainer).setIgnoredSlots(capture(captor))
-
- val locationString = mContext.resources.getString(
- com.android.internal.R.string.status_bar_location)
-
- assertThat(captor.value).containsExactly(locationString)
+ verify(iconContainer).removeIgnoredSlot(cameraSlotName)
+ verify(iconContainer).removeIgnoredSlot(microphoneSlotName)
+ verify(iconContainer).addIgnoredSlot(locationSlotName)
}
@Test
@@ -196,17 +197,9 @@
controller.init()
- val captor = argumentCaptor<List<String>>()
- verify(iconContainer).setIgnoredSlots(capture(captor))
-
- val cameraString = mContext.resources.getString(
- com.android.internal.R.string.status_bar_camera)
- val micString = mContext.resources.getString(
- com.android.internal.R.string.status_bar_microphone)
- val locationString = mContext.resources.getString(
- com.android.internal.R.string.status_bar_location)
-
- assertThat(captor.value).containsExactly(cameraString, micString, locationString)
+ verify(iconContainer).addIgnoredSlot(cameraSlotName)
+ verify(iconContainer).addIgnoredSlot(microphoneSlotName)
+ verify(iconContainer).addIgnoredSlot(locationSlotName)
}
@Test
@@ -221,6 +214,71 @@
verify(privacyDialogController).showDialog(any(Context::class.java))
}
+ @Test
+ fun testSingleCarrierListenerAttachedOnInit() {
+ controller.init()
+
+ verify(qsCarrierGroupController).setOnSingleCarrierChangedListener(any())
+ }
+
+ @Test
+ fun testSingleCarrierSetOnViewOnInit_false() {
+ `when`(qsCarrierGroupController.isSingleCarrier).thenReturn(false)
+ controller.init()
+
+ verify(view).setIsSingleCarrier(false)
+ }
+
+ @Test
+ fun testSingleCarrierSetOnViewOnInit_true() {
+ `when`(qsCarrierGroupController.isSingleCarrier).thenReturn(true)
+ controller.init()
+
+ verify(view).setIsSingleCarrier(true)
+ }
+
+ @Test
+ fun testRSSISlot_notCombined() {
+ `when`(featureFlags.isCombinedStatusBarSignalIconsEnabled).thenReturn(false)
+ controller.init()
+
+ val captor = argumentCaptor<List<String>>()
+ verify(view).onAttach(any(), any(), capture(captor))
+
+ assertThat(captor.value).containsExactly(
+ mContext.getString(com.android.internal.R.string.status_bar_mobile)
+ )
+ }
+
+ @Test
+ fun testRSSISlot_combined() {
+ `when`(featureFlags.isCombinedStatusBarSignalIconsEnabled).thenReturn(true)
+ controller.init()
+
+ val captor = argumentCaptor<List<String>>()
+ verify(view).onAttach(any(), any(), capture(captor))
+
+ assertThat(captor.value).containsExactly(
+ mContext.getString(com.android.internal.R.string.status_bar_no_calling),
+ mContext.getString(com.android.internal.R.string.status_bar_call_strength)
+ )
+ }
+
+ @Test
+ fun testSingleCarrierCallback() {
+ controller.init()
+ reset(view)
+
+ val captor = argumentCaptor<QSCarrierGroupController.OnSingleCarrierChangedListener>()
+ verify(qsCarrierGroupController).setOnSingleCarrierChangedListener(capture(captor))
+
+ captor.value.onSingleCarrierChanged(true)
+ verify(view).setIsSingleCarrier(true)
+
+ captor.value.onSingleCarrierChanged(false)
+ verify(view).setIsSingleCarrier(false)
+ }
+
private fun stubViews() {
`when`(view.findViewById<View>(anyInt())).thenReturn(mockView)
`when`(view.findViewById<QSCarrierGroup>(R.id.carrier_group)).thenReturn(qsCarrierGroup)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java
index 9ae6069..72c7ddd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java
@@ -17,15 +17,18 @@
package com.android.systemui.qs.carrier;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.os.Handler;
-import android.telephony.SubscriptionManager;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.View;
@@ -46,9 +49,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
-import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
-import org.mockito.stubbing.Answer;
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@@ -70,8 +71,18 @@
private CarrierTextManager mCarrierTextManager;
@Mock
private CarrierConfigTracker mCarrierConfigTracker;
+ @Mock
+ private QSCarrier mQSCarrier1;
+ @Mock
+ private QSCarrier mQSCarrier2;
+ @Mock
+ private QSCarrier mQSCarrier3;
private TestableLooper mTestableLooper;
@Mock private FeatureFlags mFeatureFlags;
+ @Mock
+ private QSCarrierGroupController.OnSingleCarrierChangedListener mOnSingleCarrierChangedListener;
+
+ private FakeSlotIndexResolver mSlotIndexResolver;
@Before
public void setup() throws Exception {
@@ -96,29 +107,31 @@
.setListening(any(CarrierTextManager.CarrierTextCallback.class));
when(mQSCarrierGroup.getNoSimTextView()).thenReturn(new TextView(mContext));
- when(mQSCarrierGroup.getCarrier1View()).thenReturn(mock(QSCarrier.class));
- when(mQSCarrierGroup.getCarrier2View()).thenReturn(mock(QSCarrier.class));
- when(mQSCarrierGroup.getCarrier3View()).thenReturn(mock(QSCarrier.class));
+ when(mQSCarrierGroup.getCarrier1View()).thenReturn(mQSCarrier1);
+ when(mQSCarrierGroup.getCarrier2View()).thenReturn(mQSCarrier2);
+ when(mQSCarrierGroup.getCarrier3View()).thenReturn(mQSCarrier3);
when(mQSCarrierGroup.getCarrierDivider1()).thenReturn(new View(mContext));
when(mQSCarrierGroup.getCarrierDivider2()).thenReturn(new View(mContext));
+ mSlotIndexResolver = new FakeSlotIndexResolver();
+
mQSCarrierGroupController = new QSCarrierGroupController.Builder(
mActivityStarter, handler, TestableLooper.get(this).getLooper(),
mNetworkController, mCarrierTextControllerBuilder, mContext, mCarrierConfigTracker,
- mFeatureFlags)
+ mFeatureFlags, mSlotIndexResolver)
.setQSCarrierGroup(mQSCarrierGroup)
.build();
mQSCarrierGroupController.setListening(true);
}
+ @Test
+ public void testInitiallyMultiCarrier() {
+ assertFalse(mQSCarrierGroupController.isSingleCarrier());
+ }
+
@Test // throws no Exception
public void testUpdateCarrierText_sameLengths() {
- QSCarrierGroupController spiedCarrierGroupController =
- Mockito.spy(mQSCarrierGroupController);
- when(spiedCarrierGroupController.getSlotIndex(anyInt())).thenAnswer(
- (Answer<Integer>) invocationOnMock -> invocationOnMock.getArgument(0));
-
// listOfCarriers length 1, subscriptionIds length 1, anySims false
CarrierTextManager.CarrierTextCallbackInfo
c1 = new CarrierTextManager.CarrierTextCallbackInfo(
@@ -160,11 +173,6 @@
@Test // throws no Exception
public void testUpdateCarrierText_differentLength() {
- QSCarrierGroupController spiedCarrierGroupController =
- Mockito.spy(mQSCarrierGroupController);
- when(spiedCarrierGroupController.getSlotIndex(anyInt())).thenAnswer(
- (Answer<Integer>) invocationOnMock -> invocationOnMock.getArgument(0));
-
// listOfCarriers length 2, subscriptionIds length 1, anySims false
CarrierTextManager.CarrierTextCallbackInfo
c1 = new CarrierTextManager.CarrierTextCallbackInfo(
@@ -205,10 +213,7 @@
@Test // throws no Exception
public void testUpdateCarrierText_invalidSim() {
- QSCarrierGroupController spiedCarrierGroupController =
- Mockito.spy(mQSCarrierGroupController);
- when(spiedCarrierGroupController.getSlotIndex(anyInt())).thenReturn(
- SubscriptionManager.INVALID_SIM_SLOT_INDEX);
+ mSlotIndexResolver.overrideInvalid = true;
CarrierTextManager.CarrierTextCallbackInfo
c4 = new CarrierTextManager.CarrierTextCallbackInfo(
@@ -222,6 +227,8 @@
@Test // throws no Exception
public void testSetMobileDataIndicators_invalidSim() {
+ mSlotIndexResolver.overrideInvalid = true;
+
MobileDataIndicators indicators = new MobileDataIndicators(
mock(NetworkController.IconState.class),
mock(NetworkController.IconState.class),
@@ -242,4 +249,137 @@
mTestableLooper.processAllMessages();
assertEquals(View.GONE, mQSCarrierGroup.getNoSimTextView().getVisibility());
}
+
+ @Test
+ public void testListenerNotCalledOnRegistreation() {
+ mQSCarrierGroupController
+ .setOnSingleCarrierChangedListener(mOnSingleCarrierChangedListener);
+
+ verify(mOnSingleCarrierChangedListener, never()).onSingleCarrierChanged(anyBoolean());
+ }
+
+ @Test
+ public void testSingleCarrier() {
+ // Only one element in the info
+ CarrierTextManager.CarrierTextCallbackInfo
+ info = new CarrierTextManager.CarrierTextCallbackInfo(
+ "",
+ new CharSequence[]{""},
+ true,
+ new int[]{0},
+ false /* airplaneMode */);
+
+ mCallback.updateCarrierInfo(info);
+ mTestableLooper.processAllMessages();
+
+ verify(mQSCarrier1).updateState(any(), eq(true));
+ verify(mQSCarrier2).updateState(any(), eq(true));
+ verify(mQSCarrier3).updateState(any(), eq(true));
+ }
+
+ @Test
+ public void testMultiCarrier() {
+ // More than one element in the info
+ CarrierTextManager.CarrierTextCallbackInfo
+ info = new CarrierTextManager.CarrierTextCallbackInfo(
+ "",
+ new CharSequence[]{"", ""},
+ true,
+ new int[]{0, 1},
+ false /* airplaneMode */);
+
+ mCallback.updateCarrierInfo(info);
+ mTestableLooper.processAllMessages();
+
+ verify(mQSCarrier1).updateState(any(), eq(false));
+ verify(mQSCarrier2).updateState(any(), eq(false));
+ verify(mQSCarrier3).updateState(any(), eq(false));
+ }
+
+ @Test
+ public void testSingleMultiCarrierSwitch() {
+ CarrierTextManager.CarrierTextCallbackInfo
+ singleCarrierInfo = new CarrierTextManager.CarrierTextCallbackInfo(
+ "",
+ new CharSequence[]{""},
+ true,
+ new int[]{0},
+ false /* airplaneMode */);
+
+ CarrierTextManager.CarrierTextCallbackInfo
+ multiCarrierInfo = new CarrierTextManager.CarrierTextCallbackInfo(
+ "",
+ new CharSequence[]{"", ""},
+ true,
+ new int[]{0, 1},
+ false /* airplaneMode */);
+
+ mCallback.updateCarrierInfo(singleCarrierInfo);
+ mTestableLooper.processAllMessages();
+
+ mQSCarrierGroupController
+ .setOnSingleCarrierChangedListener(mOnSingleCarrierChangedListener);
+ reset(mOnSingleCarrierChangedListener);
+
+ mCallback.updateCarrierInfo(multiCarrierInfo);
+ mTestableLooper.processAllMessages();
+ verify(mOnSingleCarrierChangedListener).onSingleCarrierChanged(false);
+
+ mCallback.updateCarrierInfo(singleCarrierInfo);
+ mTestableLooper.processAllMessages();
+ verify(mOnSingleCarrierChangedListener).onSingleCarrierChanged(true);
+ }
+
+ @Test
+ public void testNoCallbackIfSingleCarrierDoesntChange() {
+ CarrierTextManager.CarrierTextCallbackInfo
+ singleCarrierInfo = new CarrierTextManager.CarrierTextCallbackInfo(
+ "",
+ new CharSequence[]{""},
+ true,
+ new int[]{0},
+ false /* airplaneMode */);
+
+ mCallback.updateCarrierInfo(singleCarrierInfo);
+ mTestableLooper.processAllMessages();
+
+ mQSCarrierGroupController
+ .setOnSingleCarrierChangedListener(mOnSingleCarrierChangedListener);
+
+ mCallback.updateCarrierInfo(singleCarrierInfo);
+ mTestableLooper.processAllMessages();
+
+ verify(mOnSingleCarrierChangedListener, never()).onSingleCarrierChanged(anyBoolean());
+ }
+
+ @Test
+ public void testNoCallbackIfMultiCarrierDoesntChange() {
+ CarrierTextManager.CarrierTextCallbackInfo
+ multiCarrierInfo = new CarrierTextManager.CarrierTextCallbackInfo(
+ "",
+ new CharSequence[]{"", ""},
+ true,
+ new int[]{0, 1},
+ false /* airplaneMode */);
+
+ mCallback.updateCarrierInfo(multiCarrierInfo);
+ mTestableLooper.processAllMessages();
+
+ mQSCarrierGroupController
+ .setOnSingleCarrierChangedListener(mOnSingleCarrierChangedListener);
+
+ mCallback.updateCarrierInfo(multiCarrierInfo);
+ mTestableLooper.processAllMessages();
+
+ verify(mOnSingleCarrierChangedListener, never()).onSingleCarrierChanged(anyBoolean());
+ }
+
+ private class FakeSlotIndexResolver implements QSCarrierGroupController.SlotIndexResolver {
+ public boolean overrideInvalid;
+
+ @Override
+ public int getSlotIndex(int subscriptionId) {
+ return overrideInvalid ? -1 : subscriptionId;
+ }
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierTest.java
index 9bee47d..93c75ad8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierTest.java
@@ -16,6 +16,7 @@
package com.android.systemui.qs.carrier;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -23,6 +24,7 @@
import android.testing.TestableLooper;
import android.util.FeatureFlagUtils;
import android.view.LayoutInflater;
+import android.view.View;
import androidx.test.filters.SmallTest;
@@ -64,25 +66,64 @@
public void testUpdateState_first() {
CellSignalState c = new CellSignalState(true, mSignalIconId, "", "", false, false);
- assertTrue(mQSCarrier.updateState(c));
+ assertTrue(mQSCarrier.updateState(c, false));
}
@Test
public void testUpdateState_same() {
CellSignalState c = new CellSignalState(true, mSignalIconId, "", "", false, false);
- assertTrue(mQSCarrier.updateState(c));
- assertFalse(mQSCarrier.updateState(c));
+ assertTrue(mQSCarrier.updateState(c, false));
+ assertFalse(mQSCarrier.updateState(c, false));
}
@Test
public void testUpdateState_changed() {
CellSignalState c = new CellSignalState(true, mSignalIconId, "", "", false, false);
- assertTrue(mQSCarrier.updateState(c));
+ assertTrue(mQSCarrier.updateState(c, false));
CellSignalState other = c.changeVisibility(false);
- assertTrue(mQSCarrier.updateState(other));
+ assertTrue(mQSCarrier.updateState(other, false));
+ }
+
+ @Test
+ public void testUpdateState_singleCarrier_first() {
+ CellSignalState c = new CellSignalState(true, mSignalIconId, "", "", false, false);
+
+ assertTrue(mQSCarrier.updateState(c, true));
+ }
+
+ @Test
+ public void testUpdateState_singleCarrier_noShowIcon() {
+ CellSignalState c = new CellSignalState(true, mSignalIconId, "", "", false, false);
+
+ mQSCarrier.updateState(c, true);
+
+ assertEquals(View.GONE, mQSCarrier.getRSSIView().getVisibility());
+ }
+
+ @Test
+ public void testUpdateState_multiCarrier_showIcon() {
+ CellSignalState c = new CellSignalState(true, mSignalIconId, "", "", false, false);
+
+ mQSCarrier.updateState(c, false);
+
+ assertEquals(View.VISIBLE, mQSCarrier.getRSSIView().getVisibility());
+ }
+
+ @Test
+ public void testUpdateState_changeSingleMultiSingle() {
+ CellSignalState c = new CellSignalState(true, mSignalIconId, "", "", false, false);
+
+ mQSCarrier.updateState(c, true);
+ assertEquals(View.GONE, mQSCarrier.getRSSIView().getVisibility());
+
+ mQSCarrier.updateState(c, false);
+ assertEquals(View.VISIBLE, mQSCarrier.getRSSIView().getVisibility());
+
+ mQSCarrier.updateState(c, true);
+ assertEquals(View.GONE, mQSCarrier.getRSSIView().getVisibility());
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java
index 17797b7..a70c2be 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java
@@ -30,7 +30,6 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
@@ -257,19 +256,6 @@
}
@Test
- public void testGetServiceLabelUnsafe_recreateWalletClient() {
- doAnswer(invocation -> {
- throw new Exception("Bad service label.");
- }).when(mQuickAccessWalletClient).getServiceLabel();
-
- QSTile.State state = new QSTile.State();
-
- mTile.handleUpdateState(state, null);
-
- verify(mController).reCreateWalletClient();
- }
-
- @Test
public void testHandleUpdateState_updateLabelAndIcon() {
QSTile.State state = new QSTile.State();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
index d394b0c..94bd959 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
@@ -73,7 +73,7 @@
public void setUp() {
MockitoAnnotations.initMocks(this);
mInternetDialog = new MockInternetDialog(mContext, mInternetDialogFactory,
- mInternetDialogController, true, mUiEventLogger, mHandler);
+ mInternetDialogController, true, true, mUiEventLogger, mHandler);
mInternetDialog.show();
doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(SUB_ID);
when(mMockWifiManager.isWifiEnabled()).thenReturn(true);
@@ -178,10 +178,10 @@
private String mConnectedWifiSummary;
MockInternetDialog(Context context, InternetDialogFactory internetDialogFactory,
- InternetDialogController internetDialogController, boolean aboveStatusBar,
- UiEventLogger uiEventLogger, @Main Handler handler) {
- super(context, internetDialogFactory, internetDialogController, aboveStatusBar,
- uiEventLogger, handler);
+ InternetDialogController internetDialogController, boolean canConfigMobileData,
+ boolean aboveStatusBar, UiEventLogger uiEventLogger, @Main Handler handler) {
+ super(context, internetDialogFactory, internetDialogController, canConfigMobileData,
+ aboveStatusBar, uiEventLogger, handler);
mAdapter = mInternetAdapter;
mWifiManager = mMockWifiManager;
}
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 1ba3831..298bd9a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -154,6 +154,9 @@
private ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverCaptor;
@Captor
private ArgumentCaptor<KeyguardIndication> mKeyguardIndicationCaptor;
+ @Captor
+ private ArgumentCaptor<KeyguardStateController.Callback> mKeyguardStateControllerCallbackCaptor;
+ private KeyguardStateController.Callback mKeyguardStateControllerCallback;
private StatusBarStateController.StateListener mStatusBarStateListener;
private BroadcastReceiver mBroadcastReceiver;
private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
@@ -223,6 +226,10 @@
mController.mRotateTextViewController = mRotateTextViewController;
mController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
clearInvocations(mIBatteryStats);
+
+ verify(mKeyguardStateController).addCallback(
+ mKeyguardStateControllerCallbackCaptor.capture());
+ mKeyguardStateControllerCallback = mKeyguardStateControllerCallbackCaptor.getValue();
}
@Test
@@ -529,7 +536,7 @@
reset(mKeyguardUpdateMonitor);
when(mKeyguardUpdateMonitor.isUserUnlocked(anyInt())).thenReturn(true);
when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(false);
- mController.onUnlockedChanged();
+ mKeyguardStateControllerCallback.onUnlockedChanged();
verifyIndicationMessage(INDICATION_TYPE_RESTING, restingIndication);
}
@@ -572,7 +579,7 @@
@Test
public void updateMonitor_listener() {
createController();
- verify(mKeyguardStateController).addCallback(eq(mController));
+ verify(mKeyguardStateController).addCallback(any());
verify(mKeyguardUpdateMonitor, times(2)).registerCallback(any());
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
index 18cf1c8..c50296b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
@@ -1,10 +1,10 @@
package com.android.systemui.statusbar
+import android.test.suitebuilder.annotation.SmallTest
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.testing.TestableLooper.RunWithLooper
import android.util.DisplayMetrics
-import androidx.test.filters.SmallTest
import com.android.systemui.ExpandHelper
import com.android.systemui.SysuiTestCase
import com.android.systemui.classifier.FalsingCollector
@@ -67,7 +67,6 @@
@Mock lateinit var falsingManager: FalsingManager
@Mock lateinit var notificationPanelController: NotificationPanelViewController
@Mock lateinit var nsslController: NotificationStackScrollLayoutController
- @Mock lateinit var featureFlags: FeatureFlags
@Mock lateinit var depthController: NotificationShadeDepthController
@Mock lateinit var stackscroller: NotificationStackScrollLayout
@Mock lateinit var expandHelperCallback: ExpandHelper.Callback
@@ -92,11 +91,10 @@
displayMetrics = displayMetrics,
mediaHierarchyManager = mediaHierarchyManager,
scrimController = scrimController,
- featureFlags = featureFlags,
+ depthController = depthController,
context = context,
configurationController = configurationController,
- falsingManager = falsingManager,
- depthController = depthController
+ falsingManager = falsingManager
)
whenever(nsslController.view).thenReturn(stackscroller)
whenever(nsslController.expandHelperCallback).thenReturn(expandHelperCallback)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
index d6c2797..d23a9ce 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
@@ -196,6 +196,13 @@
}
@Test
+ fun onDozeAmountChanged_appliesBlur() {
+ statusBarStateListener.onDozeAmountChanged(1f, 1f)
+ notificationShadeDepthController.updateBlurCallback.doFrame(0)
+ verify(blurUtils).applyBlur(any(), eq(maxBlur), eq(false))
+ }
+
+ @Test
fun setFullShadeTransition_appliesBlur_onlyIfSupported() {
reset(blurUtils)
`when`(blurUtils.blurRadiusOfRatio(anyFloat())).then { answer ->
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java
index 7e771ce..a3569e4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java
@@ -31,7 +31,6 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
-import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
@@ -72,7 +71,6 @@
@Mock private HeadsUpViewBinder mHeadsUpViewBinder;
@Mock private NotificationInterruptStateProvider mNotificationInterruptStateProvider;
@Mock private NotificationRemoteInputManager mRemoteInputManager;
- @Mock private RemoteInputController mRemoteInputController;
@Mock private NotifLifetimeExtender.OnEndLifetimeExtensionCallback mEndLifetimeExtension;
@Mock private NodeController mHeaderController;
@@ -81,7 +79,6 @@
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController);
mCoordinator = new HeadsUpCoordinator(
mHeadsUpManager,
@@ -215,7 +212,7 @@
// WHEN mEntry is removed from the notification collection
mCollectionListener.onEntryRemoved(mEntry, /* cancellation reason */ 0);
- when(mRemoteInputController.isSpinning(any())).thenReturn(false);
+ when(mRemoteInputManager.isSpinning(any())).thenReturn(false);
// THEN heads up manager should remove the entry
verify(mHeadsUpManager).removeNotification(mEntry.getKey(), false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
index 6ee2f20..c56d085 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
@@ -24,6 +24,7 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
@@ -128,7 +129,6 @@
@Mock private ForegroundServiceDungeonView mForegroundServiceDungeonView;
@Mock private LayoutInflater mLayoutInflater;
@Mock private NotificationRemoteInputManager mRemoteInputManager;
- @Mock private RemoteInputController mRemoteInputController;
@Mock private VisualStabilityManager mVisualStabilityManager;
@Mock private ShadeController mShadeController;
@@ -145,7 +145,6 @@
when(mFeatureFlags.isNewNotifPipelineRenderingEnabled()).thenReturn(false);
when(mFgServicesSectionController.createView(mLayoutInflater))
.thenReturn(mForegroundServiceDungeonView);
- when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController);
mController = new NotificationStackScrollLayoutController(
true,
@@ -402,6 +401,19 @@
any(ForegroundServiceDungeonView.class));
}
+ @Test
+ public void testUpdateFooter_remoteInput() {
+ ArgumentCaptor<RemoteInputController.Callback> callbackCaptor =
+ ArgumentCaptor.forClass(RemoteInputController.Callback.class);
+ doNothing().when(mRemoteInputManager).addControllerCallback(callbackCaptor.capture());
+ when(mRemoteInputManager.isRemoteInputActive()).thenReturn(false);
+ mController.attach(mNotificationStackScrollLayout);
+ verify(mNotificationStackScrollLayout).setIsRemoteInputActive(false);
+ RemoteInputController.Callback callback = callbackCaptor.getValue();
+ callback.onRemoteInputActive(true);
+ verify(mNotificationStackScrollLayout).setIsRemoteInputActive(true);
+ }
+
private LogMaker logMatcher(int category, int type) {
return argThat(new LogMatcher(category, type));
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 3f35063..d02d77e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -53,10 +53,8 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.FeatureFlags;
-import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.NotificationShelfController;
-import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -97,16 +95,12 @@
@Mock private NotificationGroupManagerLegacy mGroupExpansionManager;
@Mock private ExpandHelper mExpandHelper;
@Mock private EmptyShadeView mEmptyShadeView;
- @Mock private NotificationRemoteInputManager mRemoteInputManager;
- @Mock private RemoteInputController mRemoteInputController;
@Mock private NotificationRoundnessManager mNotificationRoundnessManager;
@Mock private KeyguardBypassController mBypassController;
@Mock private NotificationSectionsManager mNotificationSectionsManager;
@Mock private NotificationSection mNotificationSection;
- @Mock private SysuiStatusBarStateController mStatusBarStateController;
@Mock private NotificationSwipeHelper mNotificationSwipeHelper;
@Mock private NotificationStackScrollLayoutController mStackScrollLayoutController;
- @Mock private FeatureFlags mFeatureFlags;
@Mock private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
@Before
@@ -129,7 +123,6 @@
new NotificationSection[]{
mNotificationSection
});
- when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController);
// Interact with real instance of AmbientState.
mAmbientState = new AmbientState(mContext, mNotificationSectionsManager, mBypassController);
@@ -146,7 +139,6 @@
mGroupMembershipManger,
mGroupExpansionManager,
mAmbientState,
- mFeatureFlags,
mUnlockedScreenOffAnimationController);
mStackScrollerInternal.initView(getContext(), mNotificationSwipeHelper);
mStackScroller = spy(mStackScrollerInternal);
@@ -156,7 +148,6 @@
when(mStackScrollLayoutController.getNoticationRoundessManager())
.thenReturn(mNotificationRoundnessManager);
mStackScroller.setController(mStackScrollLayoutController);
- mStackScroller.setRemoteInputManager(mRemoteInputManager);
// Stub out functionality that isn't necessary to test.
doNothing().when(mBar)
@@ -230,21 +221,24 @@
@Test
@UiThreadTest
public void testSetExpandedHeight_withSplitShade_doesntInterpolateStackHeight() {
- when(mFeatureFlags.isTwoColumnNotificationShadeEnabled()).thenReturn(true);
+ mContext.getOrCreateTestableResources()
+ .addOverride(R.bool.config_use_split_notification_shade, /* value= */ true);
final int[] expectedStackHeight = {0};
mStackScroller.addOnExpandedHeightChangedListener((expandedHeight, appear) -> {
assertWithMessage("Given shade enabled: %s",
- mFeatureFlags.isTwoColumnNotificationShadeEnabled())
+ true)
.that(mStackScroller.getHeight())
.isEqualTo(expectedStackHeight[0]);
});
- when(mFeatureFlags.isTwoColumnNotificationShadeEnabled()).thenReturn(false);
+ mContext.getOrCreateTestableResources()
+ .addOverride(R.bool.config_use_split_notification_shade, /* value= */ false);
expectedStackHeight[0] = 0;
mStackScroller.setExpandedHeight(100f);
- when(mFeatureFlags.isTwoColumnNotificationShadeEnabled()).thenReturn(true);
+ mContext.getOrCreateTestableResources()
+ .addOverride(R.bool.config_use_split_notification_shade, /* value= */ true);
expectedStackHeight[0] = 100;
mStackScroller.setExpandedHeight(100f);
}
@@ -301,7 +295,7 @@
when(row.canViewBeDismissed()).thenReturn(true);
when(mStackScroller.getChildCount()).thenReturn(1);
when(mStackScroller.getChildAt(anyInt())).thenReturn(row);
- when(mRemoteInputController.isRemoteInputActive()).thenReturn(true);
+ mStackScroller.setIsRemoteInputActive(true);
when(mStackScrollLayoutController.hasActiveClearableNotifications(ROWS_ALL))
.thenReturn(true);
when(mStackScrollLayoutController.hasActiveNotifications()).thenReturn(true);
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 32b08be..f10565c 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,11 +38,15 @@
import com.android.systemui.R;
import com.android.systemui.SysuiBaseFragmentTest;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.statusbar.policy.NetworkController;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
@@ -54,21 +58,28 @@
@SmallTest
public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
- private StatusBar mStatusBar;
private NotificationIconAreaController mMockNotificationAreaController;
private View mNotificationAreaInner;
- private StatusBarStateController mStatusBarStateController;
private OngoingCallController mOngoingCallController;
private SystemStatusAnimationScheduler mAnimationScheduler;
private StatusBarLocationPublisher mLocationPublisher;
+ // Set in instantiate()
+ private StatusBarIconController mStatusBarIconController;
+ private NetworkController mNetworkController;
+ private StatusBarStateController mStatusBarStateController;
+ private KeyguardStateController mKeyguardStateController;
+
+ private final StatusBar mStatusBar = mock(StatusBar.class);
+ private final CommandQueue mCommandQueue = mock(CommandQueue.class);
+
+
public CollapsedStatusBarFragmentTest() {
super(CollapsedStatusBarFragment.class);
}
@Before
public void setup() {
- mStatusBar = mock(StatusBar.class);
mStatusBarStateController = mDependency
.injectMockDependency(StatusBarStateController.class);
injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
@@ -204,6 +215,7 @@
mFragment.getView().findViewById(R.id.ongoing_call_chip).getVisibility());
}
+ @Ignore("b/192618546")
@Test
public void testOnDozingChanged() throws Exception {
mFragments.dispatchResume();
@@ -227,6 +239,10 @@
mOngoingCallController = mock(OngoingCallController.class);
mAnimationScheduler = mock(SystemStatusAnimationScheduler.class);
mLocationPublisher = mock(StatusBarLocationPublisher.class);
+ mStatusBarIconController = mock(StatusBarIconController.class);
+ mNetworkController = mock(NetworkController.class);
+ mStatusBarStateController = mock(StatusBarStateController.class);
+ mKeyguardStateController = mock(KeyguardStateController.class);
setUpNotificationIconAreaController();
return new CollapsedStatusBarFragment(
mOngoingCallController,
@@ -234,9 +250,15 @@
mLocationPublisher,
mMockNotificationAreaController,
mock(FeatureFlags.class),
- () -> Optional.of(mStatusBar));
+ mStatusBarIconController,
+ mKeyguardStateController,
+ mNetworkController,
+ mStatusBarStateController,
+ () -> Optional.of(mStatusBar),
+ mCommandQueue);
}
+
private void setUpNotificationIconAreaController() {
mMockNotificationAreaController = mock(NotificationIconAreaController.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index 16d2179..5ea55e5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -88,6 +88,11 @@
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.classifier.FalsingManagerFake;
+import com.android.systemui.communal.CommunalHostView;
+import com.android.systemui.communal.CommunalHostViewController;
+import com.android.systemui.communal.CommunalSource;
+import com.android.systemui.communal.CommunalSourceMonitor;
+import com.android.systemui.communal.dagger.CommunalViewComponent;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.fragments.FragmentService;
@@ -99,7 +104,6 @@
import com.android.systemui.qs.QSDetailDisplayer;
import com.android.systemui.screenrecord.RecordingController;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.KeyguardAffordanceView;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
@@ -108,7 +112,6 @@
import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationShelfController;
import com.android.systemui.statusbar.PulseExpansionHandler;
-import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.StatusBarStateControllerImpl;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.VibratorHelper;
@@ -138,6 +141,7 @@
import org.mockito.MockitoAnnotations;
import org.mockito.stubbing.Answer;
+import java.lang.ref.WeakReference;
import java.util.List;
@SmallTest
@@ -248,6 +252,18 @@
@Mock
private KeyguardStatusBarViewComponent mKeyguardStatusBarViewComponent;
@Mock
+ private CommunalViewComponent.Factory mCommunalViewComponentFactory;
+ @Mock
+ private CommunalViewComponent mCommunalViewComponent;
+ @Mock
+ private CommunalHostViewController mCommunalHostViewController;
+ @Mock
+ private CommunalSourceMonitor mCommunalSourceMonitor;
+ @Mock
+ private CommunalSource mCommunalSource;
+ @Mock
+ private CommunalHostView mCommunalHostView;
+ @Mock
private KeyguardClockSwitchController mKeyguardClockSwitchController;
@Mock
private KeyguardStatusViewController mKeyguardStatusViewController;
@@ -266,8 +282,6 @@
@Mock
private MediaDataManager mMediaDataManager;
@Mock
- private FeatureFlags mFeatureFlags;
- @Mock
private AmbientState mAmbientState;
@Mock
private UserManager mUserManager;
@@ -300,8 +314,6 @@
@Mock
private NotificationRemoteInputManager mNotificationRemoteInputManager;
@Mock
- private RemoteInputController mRemoteInputController;
- @Mock
private RecordingController mRecordingController;
private SysuiStatusBarStateController mStatusBarStateController;
@@ -339,6 +351,7 @@
when(mView.findViewById(R.id.keyguard_clock_container)).thenReturn(mKeyguardClockSwitch);
when(mView.findViewById(R.id.notification_stack_scroller))
.thenReturn(mNotificationStackScrollLayout);
+ when(mView.findViewById(R.id.communal_host)).thenReturn(mCommunalHostView);
when(mNotificationStackScrollLayout.getController())
.thenReturn(mNotificationStackScrollLayoutController);
when(mNotificationStackScrollLayoutController.getHeight()).thenReturn(1000);
@@ -395,12 +408,15 @@
.thenReturn(mKeyguardStatusBarViewComponent);
when(mKeyguardStatusBarViewComponent.getKeyguardStatusBarViewController())
.thenReturn(mKeyguardStatusBarViewController);
+ when(mCommunalViewComponentFactory.build(any()))
+ .thenReturn(mCommunalViewComponent);
+ when(mCommunalViewComponent.getCommunalHostViewController())
+ .thenReturn(mCommunalHostViewController);
when(mLayoutInflater.inflate(eq(R.layout.keyguard_status_view), any(), anyBoolean()))
.thenReturn(mKeyguardStatusView);
when(mLayoutInflater.inflate(eq(R.layout.keyguard_bottom_area), any(), anyBoolean()))
.thenReturn(mKeyguardBottomArea);
- when(mNotificationRemoteInputManager.getController()).thenReturn(mRemoteInputController);
- when(mRemoteInputController.isRemoteInputActive()).thenReturn(false);
+ when(mNotificationRemoteInputManager.isRemoteInputActive()).thenReturn(false);
reset(mView);
@@ -414,7 +430,7 @@
mKeyguardStateController, mStatusBarStateController, mDozeLog,
mDozeParameters, mCommandQueue, mVibratorHelper,
mLatencyTracker, mPowerManager, mAccessibilityManager, 0, mUpdateMonitor,
- mMetricsLogger, mActivityManager, mConfigurationController,
+ mCommunalSourceMonitor, mMetricsLogger, mActivityManager, mConfigurationController,
() -> flingAnimationUtilsBuilder, mStatusBarTouchableRegionManager,
mConversationNotificationManager, mMediaHiearchyManager,
mBiometricUnlockController, mStatusBarKeyguardViewManager,
@@ -423,6 +439,7 @@
mKeyguardQsUserSwitchComponentFactory,
mKeyguardUserSwitcherComponentFactory,
mKeyguardStatusBarViewComponentFactory,
+ mCommunalViewComponentFactory,
mLockscreenShadeTransitionController,
mQSDetailDisplayer,
mGroupManager,
@@ -434,7 +451,6 @@
mNotificationShadeDepthController,
mAmbientState,
mLockIconViewController,
- mFeatureFlags,
mKeyguardMediaController,
mPrivacyDotViewController,
mTapAgainViewController,
@@ -560,7 +576,7 @@
@Test
public void testAllChildrenOfNotificationContainer_haveIds() {
- enableSplitShade();
+ enableSplitShade(/* enabled= */ true);
mNotificationContainerParent.removeAllViews();
mNotificationContainerParent.addView(newViewWithId(1));
mNotificationContainerParent.addView(newViewWithId(View.NO_ID));
@@ -573,7 +589,7 @@
@Test
public void testSinglePaneShadeLayout_isAlignedToParent() {
- when(mFeatureFlags.isTwoColumnNotificationShadeEnabled()).thenReturn(false);
+ enableSplitShade(/* enabled= */ false);
mNotificationPanelViewController.updateResources();
@@ -586,7 +602,7 @@
@Test
public void testKeyguardStatusViewInSplitShade_changesConstraintsDependingOnNotifications() {
mStatusBarStateController.setState(KEYGUARD);
- enableSplitShade();
+ enableSplitShade(/* enabled= */ true);
when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(2);
mNotificationPanelViewController.updateResources();
@@ -633,7 +649,7 @@
@Test
public void testSplitShadeLayout_isAlignedToGuideline() {
- enableSplitShade();
+ enableSplitShade(/* enabled= */ true);
mNotificationPanelViewController.updateResources();
@@ -645,7 +661,7 @@
@Test
public void testSinglePaneShadeLayout_childrenHaveConstantWidth() {
- when(mFeatureFlags.isTwoColumnNotificationShadeEnabled()).thenReturn(false);
+ enableSplitShade(/* enabled= */ false);
mNotificationPanelViewController.updateResources();
@@ -657,7 +673,7 @@
@Test
public void testSplitShadeLayout_childrenHaveZeroWidth() {
- enableSplitShade();
+ enableSplitShade(/* enabled= */ true);
mNotificationPanelViewController.updateResources();
@@ -669,7 +685,7 @@
public void testOnDragDownEvent_horizontalTranslationIsZeroForSplitShade() {
when(mNotificationStackScrollLayoutController.getWidth()).thenReturn(350f);
when(mView.getWidth()).thenReturn(800);
- enableSplitShade();
+ enableSplitShade(/* enabled= */ true);
onTouchEvent(MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN,
200f /* x position */, 0f, 0));
@@ -703,7 +719,7 @@
@Test
public void testCanCollapsePanelOnTouch_falseInDualPaneShade() {
mStatusBarStateController.setState(SHADE);
- enableSplitShade();
+ enableSplitShade(/* enabled= */ true);
mNotificationPanelViewController.setQsExpanded(true);
assertThat(mNotificationPanelViewController.canCollapsePanelOnTouch()).isFalse();
@@ -773,7 +789,7 @@
@Test
public void testSwitchesToCorrectClockInSplitShade() {
mStatusBarStateController.setState(KEYGUARD);
- enableSplitShade();
+ enableSplitShade(/* enabled= */ true);
when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(0);
triggerPositionClockAndNotifications();
@@ -788,7 +804,7 @@
@Test
public void testDisplaysSmallClockOnLockscreenInSplitShadeWhenMediaIsPlaying() {
mStatusBarStateController.setState(KEYGUARD);
- enableSplitShade();
+ enableSplitShade(/* enabled= */ true);
when(mMediaDataManager.hasActiveMedia()).thenReturn(true);
// one notification + media player visible
@@ -803,6 +819,28 @@
verify(mKeyguardStatusViewController, never()).displayClock(LARGE);
}
+ @Test
+ public void testCommunalSourceListening() {
+ final ArgumentCaptor<CommunalSourceMonitor.Callback> monitorCallback =
+ ArgumentCaptor.forClass(CommunalSourceMonitor.Callback.class);
+
+ givenViewAttached();
+ verify(mCommunalSourceMonitor).addCallback(monitorCallback.capture());
+
+ final ArgumentCaptor<WeakReference<CommunalSource>> sourceCapture =
+ ArgumentCaptor.forClass(WeakReference.class);
+
+ monitorCallback.getValue().onSourceAvailable(new WeakReference<>(mCommunalSource));
+ verify(mCommunalHostViewController).show(sourceCapture.capture());
+ assertThat(sourceCapture.getValue().get()).isEqualTo(mCommunalSource);
+
+ clearInvocations(mCommunalHostViewController);
+ givenViewDetached();
+ verify(mCommunalSourceMonitor).removeCallback(any());
+ verify(mCommunalHostViewController).show(sourceCapture.capture());
+ assertThat(sourceCapture.getValue()).isEqualTo(null);
+ }
+
private void triggerPositionClockAndNotifications() {
mNotificationPanelViewController.closeQs();
}
@@ -821,6 +859,13 @@
}
}
+ private void givenViewDetached() {
+ for (View.OnAttachStateChangeListener listener : mOnAttachStateChangeListeners) {
+ listener.onViewDetachedFromWindow(mView);
+ }
+ }
+
+
private View newViewWithId(int id) {
View view = new View(mContext);
view.setId(id);
@@ -837,9 +882,8 @@
return constraintSet.getConstraint(id).layout;
}
- private void enableSplitShade() {
- when(mResources.getBoolean(R.bool.config_use_split_notification_shade)).thenReturn(true);
- when(mFeatureFlags.isTwoColumnNotificationShadeEnabled()).thenReturn(true);
+ private void enableSplitShade(boolean enabled) {
+ when(mResources.getBoolean(R.bool.config_use_split_notification_shade)).thenReturn(enabled);
mNotificationPanelViewController.updateResources();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt
index 4796cd7..10eb71f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt
@@ -47,7 +47,8 @@
@Test
fun testGetBoundingRectForPrivacyChipForRotation_noCutout() {
val screenBounds = Rect(0, 0, 1080, 2160)
- val roundedCornerPadding = 20
+ val minLeftPadding = 20
+ val minRightPadding = 20
val sbHeightPortrait = 100
val sbHeightLandscape = 60
val currentRotation = ROTATION_NONE
@@ -64,7 +65,8 @@
null,
windowMetrics,
sbHeightPortrait,
- roundedCornerPadding)
+ minLeftPadding,
+ minRightPadding)
var chipBounds = getPrivacyChipBoundingRectForInsets(bounds, dotWidth, chipWidth, isRtl)
/* 1080 - 20 (rounded corner) - 30 (chip),
@@ -92,7 +94,8 @@
dc,
windowMetrics,
sbHeightLandscape,
- roundedCornerPadding)
+ minLeftPadding,
+ minRightPadding)
chipBounds = getPrivacyChipBoundingRectForInsets(bounds, dotWidth, chipWidth, isRtl)
/* 2160 - 20 (rounded corner) - 30 (chip),
@@ -118,7 +121,8 @@
// GIVEN a device in portrait mode with width < height and a display cutout in the top-left
val screenBounds = Rect(0, 0, 1080, 2160)
val dcBounds = Rect(0, 0, 100, 100)
- val roundedCornerPadding = 20
+ val minLeftPadding = 20
+ val minRightPadding = 20
val sbHeightPortrait = 100
val sbHeightLandscape = 60
val currentRotation = ROTATION_NONE
@@ -131,7 +135,7 @@
var targetRotation = ROTATION_NONE
var expectedBounds = Rect(dcBounds.right,
0,
- screenBounds.right - roundedCornerPadding,
+ screenBounds.right - minRightPadding,
sbHeightPortrait)
var bounds = calculateInsetsForRotationWithRotatedResources(
@@ -140,14 +144,15 @@
dc,
windowMetrics,
sbHeightPortrait,
- roundedCornerPadding)
+ minLeftPadding,
+ minRightPadding)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
targetRotation = ROTATION_LANDSCAPE
expectedBounds = Rect(dcBounds.height(),
0,
- screenBounds.height() - roundedCornerPadding,
+ screenBounds.height() - minRightPadding,
sbHeightLandscape)
bounds = calculateInsetsForRotationWithRotatedResources(
@@ -156,16 +161,17 @@
dc,
windowMetrics,
sbHeightLandscape,
- roundedCornerPadding)
+ minLeftPadding,
+ minRightPadding)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
// THEN the side that does NOT share a short side with the display cutout ignores the
// display cutout bounds
targetRotation = ROTATION_UPSIDE_DOWN
- expectedBounds = Rect(roundedCornerPadding,
+ expectedBounds = Rect(minLeftPadding,
0,
- screenBounds.width() - roundedCornerPadding,
+ screenBounds.width() - minRightPadding,
sbHeightPortrait)
bounds = calculateInsetsForRotationWithRotatedResources(
@@ -174,13 +180,14 @@
dc,
windowMetrics,
sbHeightPortrait,
- roundedCornerPadding)
+ minLeftPadding,
+ minRightPadding)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
// Phone in portrait, seascape (rot_270) bounds
targetRotation = ROTATION_SEASCAPE
- expectedBounds = Rect(roundedCornerPadding,
+ expectedBounds = Rect(minLeftPadding,
0,
screenBounds.height() - dcBounds.height(),
sbHeightLandscape)
@@ -191,7 +198,8 @@
dc,
windowMetrics,
sbHeightLandscape,
- roundedCornerPadding)
+ minLeftPadding,
+ minRightPadding)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
}
@@ -205,7 +213,8 @@
val screenBounds = Rect(0, 0, 1080, 2160)
// cutout centered at the top
val dcBounds = Rect(490, 0, 590, 100)
- val roundedCornerPadding = 20
+ val minLeftPadding = 20
+ val minRightPadding = 20
val sbHeightPortrait = 100
val sbHeightLandscape = 60
val currentRotation = ROTATION_NONE
@@ -216,9 +225,9 @@
// THEN only the landscape/seascape rotations should avoid the cutout area because of the
// potential letterboxing
var targetRotation = ROTATION_NONE
- var expectedBounds = Rect(roundedCornerPadding,
+ var expectedBounds = Rect(minLeftPadding,
0,
- screenBounds.right - roundedCornerPadding,
+ screenBounds.right - minRightPadding,
sbHeightPortrait)
var bounds = calculateInsetsForRotationWithRotatedResources(
@@ -227,14 +236,15 @@
dc,
windowMetrics,
sbHeightPortrait,
- roundedCornerPadding)
+ minLeftPadding,
+ minRightPadding)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
targetRotation = ROTATION_LANDSCAPE
expectedBounds = Rect(dcBounds.height(),
0,
- screenBounds.height() - roundedCornerPadding,
+ screenBounds.height() - minRightPadding,
sbHeightLandscape)
bounds = calculateInsetsForRotationWithRotatedResources(
@@ -243,14 +253,15 @@
dc,
windowMetrics,
sbHeightLandscape,
- roundedCornerPadding)
+ minLeftPadding,
+ minRightPadding)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
targetRotation = ROTATION_UPSIDE_DOWN
- expectedBounds = Rect(roundedCornerPadding,
+ expectedBounds = Rect(minLeftPadding,
0,
- screenBounds.right - roundedCornerPadding,
+ screenBounds.right - minRightPadding,
sbHeightPortrait)
bounds = calculateInsetsForRotationWithRotatedResources(
@@ -259,12 +270,13 @@
dc,
windowMetrics,
sbHeightPortrait,
- roundedCornerPadding)
+ minLeftPadding,
+ minRightPadding)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
targetRotation = ROTATION_SEASCAPE
- expectedBounds = Rect(roundedCornerPadding,
+ expectedBounds = Rect(minLeftPadding,
0,
screenBounds.height() - dcBounds.height(),
sbHeightLandscape)
@@ -275,7 +287,8 @@
dc,
windowMetrics,
sbHeightLandscape,
- roundedCornerPadding)
+ minLeftPadding,
+ minRightPadding)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
}
@@ -285,7 +298,8 @@
// GIVEN device in portrait mode, where width < height and no cutout
val currentRotation = ROTATION_NONE
val screenBounds = Rect(0, 0, 1080, 2160)
- val roundedCornerPadding = 20
+ val minLeftPadding = 20
+ val minRightPadding = 20
val sbHeightPortrait = 100
val sbHeightLandscape = 60
@@ -293,9 +307,9 @@
// THEN content insets should only use rounded corner padding
var targetRotation = ROTATION_NONE
- var expectedBounds = Rect(roundedCornerPadding,
+ var expectedBounds = Rect(minLeftPadding,
0,
- screenBounds.right - roundedCornerPadding,
+ screenBounds.right - minRightPadding,
sbHeightPortrait)
var bounds = calculateInsetsForRotationWithRotatedResources(
@@ -304,13 +318,14 @@
null, /* no cutout */
windowMetrics,
sbHeightPortrait,
- roundedCornerPadding)
+ minLeftPadding,
+ minRightPadding)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
targetRotation = ROTATION_LANDSCAPE
- expectedBounds = Rect(roundedCornerPadding,
+ expectedBounds = Rect(minLeftPadding,
0,
- screenBounds.height() - roundedCornerPadding,
+ screenBounds.height() - minRightPadding,
sbHeightLandscape)
bounds = calculateInsetsForRotationWithRotatedResources(
@@ -319,13 +334,14 @@
null, /* no cutout */
windowMetrics,
sbHeightLandscape,
- roundedCornerPadding)
+ minLeftPadding,
+ minRightPadding)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
targetRotation = ROTATION_UPSIDE_DOWN
- expectedBounds = Rect(roundedCornerPadding,
+ expectedBounds = Rect(minLeftPadding,
0,
- screenBounds.width() - roundedCornerPadding,
+ screenBounds.width() - minRightPadding,
sbHeightPortrait)
bounds = calculateInsetsForRotationWithRotatedResources(
@@ -334,13 +350,14 @@
null, /* no cutout */
windowMetrics,
sbHeightPortrait,
- roundedCornerPadding)
+ minLeftPadding,
+ minRightPadding)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
targetRotation = ROTATION_LANDSCAPE
- expectedBounds = Rect(roundedCornerPadding,
+ expectedBounds = Rect(minLeftPadding,
0,
- screenBounds.height() - roundedCornerPadding,
+ screenBounds.height() - minRightPadding,
sbHeightLandscape)
bounds = calculateInsetsForRotationWithRotatedResources(
@@ -349,7 +366,41 @@
null, /* no cutout */
windowMetrics,
sbHeightLandscape,
- roundedCornerPadding)
+ minLeftPadding,
+ minRightPadding)
+ assertRects(expectedBounds, bounds, currentRotation, targetRotation)
+ }
+
+ @Test
+ fun testMinLeftRight_accountsForDisplayCutout() {
+ // GIVEN a device in portrait mode with width < height and a display cutout in the top-left
+ val screenBounds = Rect(0, 0, 1080, 2160)
+ val dcBounds = Rect(0, 0, 100, 100)
+ val minLeftPadding = 80
+ val minRightPadding = 150
+ val sbHeightPortrait = 100
+ val sbHeightLandscape = 60
+ val currentRotation = ROTATION_NONE
+
+ `when`(windowMetrics.bounds).thenReturn(screenBounds)
+ `when`(dc.boundingRects).thenReturn(listOf(dcBounds))
+
+ // THEN left should be set to the display cutout width, and right should use the minRight
+ var targetRotation = ROTATION_NONE
+ var expectedBounds = Rect(dcBounds.right,
+ 0,
+ screenBounds.right - minRightPadding,
+ sbHeightPortrait)
+
+ var bounds = calculateInsetsForRotationWithRotatedResources(
+ currentRotation,
+ targetRotation,
+ dc,
+ windowMetrics,
+ sbHeightPortrait,
+ minLeftPadding,
+ minRightPadding)
+
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index 37a6d21..83bf96b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -61,7 +61,6 @@
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
-import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -111,8 +110,6 @@
@Mock
private NotificationRemoteInputManager mRemoteInputManager;
@Mock
- private RemoteInputController mRemoteInputController;
- @Mock
private StatusBar mStatusBar;
@Mock
private KeyguardStateController mKeyguardStateController;
@@ -153,8 +150,6 @@
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController);
-
when(mContentIntent.isActivity()).thenReturn(true);
when(mContentIntent.getCreatorUserHandle()).thenReturn(UserHandle.of(1));
when(mContentIntent.getIntent()).thenReturn(mContentIntentInner);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
index ce45f26..fd85c44 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
@@ -46,7 +46,6 @@
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.NotificationViewHierarchyManager;
-import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -89,8 +88,6 @@
public void setup() {
NotificationRemoteInputManager notificationRemoteInputManager =
mock(NotificationRemoteInputManager.class);
- when(notificationRemoteInputManager.getController())
- .thenReturn(mock(RemoteInputController.class));
mMetricsLogger = new FakeMetricsLogger();
mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger);
mCommandQueue = new CommandQueue(mContext);
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 c504fd8..2a58f7c 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
@@ -98,6 +98,7 @@
import com.android.systemui.recents.ScreenPinningRequest;
import com.android.systemui.settings.brightness.BrightnessSlider;
import com.android.systemui.shared.plugins.PluginManager;
+import com.android.unfold.config.UnfoldTransitionConfig;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.KeyguardIndicationController;
@@ -110,7 +111,6 @@
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.NotificationViewHierarchyManager;
import com.android.systemui.statusbar.PulseExpansionHandler;
-import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.StatusBarStateControllerImpl;
import com.android.systemui.statusbar.SuperStatusBarViewFactory;
@@ -146,6 +146,7 @@
import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
import com.android.systemui.volume.VolumeComponent;
@@ -201,7 +202,6 @@
@Mock private KeyguardViewMediator mKeyguardViewMediator;
@Mock private NotificationLockscreenUserManager mLockscreenUserManager;
@Mock private NotificationRemoteInputManager mRemoteInputManager;
- @Mock private RemoteInputController mRemoteInputController;
@Mock private StatusBarStateControllerImpl mStatusBarStateController;
@Mock private BatteryController mBatteryController;
@Mock private DeviceProvisionedController mDeviceProvisionedController;
@@ -266,9 +266,12 @@
@Mock private Lazy<NotificationShadeDepthController> mNotificationShadeDepthControllerLazy;
@Mock private BrightnessSlider.Factory mBrightnessSliderFactory;
@Mock private WiredChargingRippleController mWiredChargingRippleController;
+ @Mock private UnfoldTransitionConfig mUnfoldTransitionConfig;
+ @Mock private Lazy<UnfoldLightRevealOverlayAnimation> mUnfoldLightRevealOverlayAnimationLazy;
@Mock private OngoingCallController mOngoingCallController;
@Mock private SystemStatusAnimationScheduler mAnimationScheduler;
@Mock private StatusBarLocationPublisher mLocationPublisher;
+ @Mock private StatusBarIconController mIconController;
@Mock private LockscreenShadeTransitionController mLockscreenTransitionController;
@Mock private FeatureFlags mFeatureFlags;
@Mock private IWallpaperManager mWallpaperManager;
@@ -331,8 +334,6 @@
return null;
}).when(mStatusBarKeyguardViewManager).addAfterKeyguardGoneRunnable(any());
- when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController);
-
WakefulnessLifecycle wakefulnessLifecycle =
new WakefulnessLifecycle(mContext, mWallpaperManager);
wakefulnessLifecycle.dispatchStartedWakingUp(PowerManager.WAKE_REASON_UNKNOWN);
@@ -439,9 +440,12 @@
mNotificationIconAreaController,
mBrightnessSliderFactory,
mWiredChargingRippleController,
+ mUnfoldTransitionConfig,
+ mUnfoldLightRevealOverlayAnimationLazy,
mOngoingCallController,
mAnimationScheduler,
mLocationPublisher,
+ mIconController,
mLockscreenTransitionController,
mFeatureFlags,
mKeyguardUnlockAnimationController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeConfigurationController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeConfigurationController.java
index f5ccac3..516eb6e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeConfigurationController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeConfigurationController.java
@@ -33,4 +33,9 @@
@Override
public void notifyThemeChanged() {
}
+
+ @Override
+ public boolean isLayoutRtl() {
+ return false;
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/QuickAccessWalletControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/QuickAccessWalletControllerTest.java
index ce0098e..72a329a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/QuickAccessWalletControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/QuickAccessWalletControllerTest.java
@@ -37,6 +37,7 @@
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.util.settings.SecureSettings;
+import com.android.systemui.util.time.FakeSystemClock;
import com.google.common.util.concurrent.MoreExecutors;
@@ -62,6 +63,7 @@
@Captor
private ArgumentCaptor<GetWalletCardsRequest> mRequestCaptor;
+ private FakeSystemClock mClock = new FakeSystemClock();
private QuickAccessWalletController mController;
@Before
@@ -70,12 +72,14 @@
when(mQuickAccessWalletClient.isWalletServiceAvailable()).thenReturn(true);
when(mQuickAccessWalletClient.isWalletFeatureAvailable()).thenReturn(true);
when(mQuickAccessWalletClient.isWalletFeatureAvailableWhenDeviceLocked()).thenReturn(true);
+ mClock.setElapsedRealtime(100L);
mController = new QuickAccessWalletController(
mContext,
MoreExecutors.directExecutor(),
mSecureSettings,
- mQuickAccessWalletClient);
+ mQuickAccessWalletClient,
+ mClock);
}
@Test
@@ -125,6 +129,23 @@
}
@Test
+ public void queryWalletCards_avoidStale_recreateClient() {
+ // advance current time by 100 seconds, should not recreate the client.
+ mClock.setElapsedRealtime(100100L);
+
+ mController.queryWalletCards(mCardsRetriever);
+
+ assertSame(mQuickAccessWalletClient, mController.getWalletClient());
+
+ // advance current time by another 501 seconds, should recreate the client.
+ mClock.setElapsedRealtime(601100L);
+
+ mController.queryWalletCards(mCardsRetriever);
+
+ assertNotSame(mQuickAccessWalletClient, mController.getWalletClient());
+ }
+
+ @Test
public void queryWalletCards_walletEnabled_queryCards() {
mController.queryWalletCards(mCardsRetriever);
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java b/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java
index a7f0f1c..0ab0c89 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java
@@ -444,8 +444,10 @@
private boolean isValidPackageForUid(String packageName, int uid) {
final long token = Binder.clearCallingIdentity();
try {
+ // Since we treat calls from a profile as if made by its parent, using
+ // MATCH_ANY_USER to query the uid of the given package name.
return uid == mPackageManager.getPackageUidAsUser(
- packageName, UserHandle.getUserId(uid));
+ packageName, PackageManager.MATCH_ANY_USER, UserHandle.getUserId(uid));
} catch (PackageManager.NameNotFoundException e) {
return false;
} finally {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
index 244f357..0a68d71 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
@@ -143,12 +143,8 @@
/**
* Starts tracking windows changes from window manager by registering callback.
- *
- * @return true if callback registers successful.
*/
- boolean startTrackingWindowsLocked() {
- boolean result = true;
-
+ void startTrackingWindowsLocked() {
if (!mTrackingWindows) {
// Turns on the flag before setup the callback.
// In some cases, onWindowsForAccessibilityChanged will be called immediately in
@@ -158,15 +154,9 @@
logTraceWM("setWindowsForAccessibilityCallback",
"displayId=" + mDisplayId + ";callback=" + this);
}
- result = mWindowManagerInternal.setWindowsForAccessibilityCallback(
+ mWindowManagerInternal.setWindowsForAccessibilityCallback(
mDisplayId, this);
- if (!result) {
- mTrackingWindows = false;
- Slog.w(LOG_TAG, "set windowsObserver callbacks fail, displayId:"
- + mDisplayId);
- }
}
- return result;
}
/**
@@ -384,20 +374,6 @@
}
}
- /**
- * Called when the display is reparented and becomes an embedded
- * display.
- *
- * @param embeddedDisplayId The embedded display Id.
- */
- @Override
- public void onDisplayReparented(int embeddedDisplayId) {
- // Removes the un-used window observer for the embedded display.
- synchronized (mLock) {
- mDisplayWindowsObservers.remove(embeddedDisplayId);
- }
- }
-
private boolean shouldUpdateWindowsLocked(boolean forceSend,
@NonNull List<WindowInfo> windows) {
if (forceSend) {
@@ -904,9 +880,8 @@
if (observer.isTrackingWindowsLocked()) {
return;
}
- if (observer.startTrackingWindowsLocked()) {
- mDisplayWindowsObservers.put(displayId, observer);
- }
+ observer.startTrackingWindowsLocked();
+ mDisplayWindowsObservers.put(displayId, observer);
}
}
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 7d80bb5..bafa9913 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -39,6 +39,7 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.PersistableBundle;
+import android.os.Process;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.SparseArray;
@@ -719,6 +720,20 @@
*/
public abstract boolean filterAppAccess(int uid, int callingUid);
+ /**
+ * Fetches all app Ids that a given application is currently visible to the provided user.
+ *
+ * <p>
+ * <strong>Note: </strong>This only includes UIDs >= {@link Process#FIRST_APPLICATION_UID}
+ * as all other UIDs can already see all applications.
+ * </p>
+ *
+ * If the app is visible to all UIDs, null is returned. If the app is not visible to any
+ * applications, the int array will be empty.
+ */
+ @Nullable
+ public abstract int[] getVisibilityAllowList(@NonNull String packageName, int userId);
+
/** Returns whether the given package was signed by the platform */
public abstract boolean isPlatformSigned(String pkg);
@@ -830,7 +845,7 @@
/**
* Perform the given action for each installed package for a user.
- * Note that packages lock will be held while performin the actions.
+ * Note that packages lock will be held while performing the actions.
*/
public abstract void forEachInstalledPackage(
@NonNull Consumer<AndroidPackage> actionLocked, @UserIdInt int userId);
diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java
index f440ee8..c9608a5 100644
--- a/services/core/java/com/android/server/NsdService.java
+++ b/services/core/java/com/android/server/NsdService.java
@@ -82,6 +82,8 @@
private static final int INVALID_ID = 0;
private int mUniqueId = 1;
+ // The count of the connected legacy clients.
+ private int mLegacyClientCount = 0;
private class NsdStateMachine extends StateMachine {
@@ -107,7 +109,9 @@
sendMessageDelayed(NsdManager.DAEMON_CLEANUP, mCleanupDelayMs);
}
private void maybeScheduleStop() {
- if (!isAnyRequestActive()) {
+ // The native daemon should stay alive and can't be cleanup
+ // if any legacy client connected.
+ if (!isAnyRequestActive() && mLegacyClientCount == 0) {
scheduleStop();
}
}
@@ -175,11 +179,11 @@
if (cInfo != null) {
cInfo.expungeAllRequests();
mClients.remove(msg.replyTo);
+ if (cInfo.isLegacy()) {
+ mLegacyClientCount -= 1;
+ }
}
- //Last client
- if (mClients.size() == 0) {
- scheduleStop();
- }
+ maybeScheduleStop();
break;
case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION:
AsyncChannel ac = new AsyncChannel();
@@ -208,6 +212,17 @@
case NsdManager.DAEMON_CLEANUP:
mDaemon.maybeStop();
break;
+ // This event should be only sent by the legacy (target SDK < S) clients.
+ // Mark the sending client as legacy.
+ case NsdManager.DAEMON_STARTUP:
+ cInfo = mClients.get(msg.replyTo);
+ if (cInfo != null) {
+ cancelStop();
+ cInfo.setLegacy();
+ mLegacyClientCount += 1;
+ maybeStartDaemon();
+ }
+ break;
case NsdManager.NATIVE_DAEMON_EVENT:
default:
Slog.e(TAG, "Unhandled " + msg);
@@ -863,6 +878,9 @@
/* A map from client id to the type of the request we had received */
private final SparseIntArray mClientRequests = new SparseIntArray();
+ // The target SDK of this client < Build.VERSION_CODES.S
+ private boolean mIsLegacy = false;
+
private ClientInfo(AsyncChannel c, Messenger m) {
mChannel = c;
mMessenger = m;
@@ -875,6 +893,7 @@
sb.append("mChannel ").append(mChannel).append("\n");
sb.append("mMessenger ").append(mMessenger).append("\n");
sb.append("mResolvedService ").append(mResolvedService).append("\n");
+ sb.append("mIsLegacy ").append(mIsLegacy).append("\n");
for(int i = 0; i< mClientIds.size(); i++) {
int clientID = mClientIds.keyAt(i);
sb.append("clientId ").append(clientID).
@@ -884,6 +903,14 @@
return sb.toString();
}
+ private boolean isLegacy() {
+ return mIsLegacy;
+ }
+
+ private void setLegacy() {
+ mIsLegacy = true;
+ }
+
// Remove any pending requests from the global map when we get rid of a client,
// and send cancellations to the daemon.
private void expungeAllRequests() {
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 795d3d6..07847f1 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1934,6 +1934,28 @@
if (smap != null) {
decActiveForegroundAppLocked(smap, r);
}
+
+ // Adjust notification handling before setting isForeground to false, because
+ // that state is relevant to the notification policy side.
+ // Leave the time-to-display as already set: re-entering foreground mode will
+ // only resume the previous quiet timeout, or will display immediately if the
+ // deferral period had already passed.
+ if ((flags & Service.STOP_FOREGROUND_REMOVE) != 0) {
+ cancelForegroundNotificationLocked(r);
+ r.foregroundId = 0;
+ r.foregroundNoti = null;
+ } else if (r.appInfo.targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) {
+ // if it's been deferred, force to visibility
+ if (!r.mFgsNotificationShown) {
+ r.postNotification();
+ }
+ dropFgsNotificationStateLocked(r);
+ if ((flags & Service.STOP_FOREGROUND_DETACH) != 0) {
+ r.foregroundId = 0;
+ r.foregroundNoti = null;
+ }
+ }
+
r.isForeground = false;
r.mFgsExitTime = SystemClock.uptimeMillis();
ServiceState stracker = r.getTracker();
@@ -1957,20 +1979,6 @@
updateServiceForegroundLocked(r.app.mServices, true);
}
}
- // Leave the time-to-display as already set: re-entering foreground mode will
- // only resume the previous quiet timeout, or will display immediately if the
- // deferral period had already passed.
- if ((flags & Service.STOP_FOREGROUND_REMOVE) != 0) {
- cancelForegroundNotificationLocked(r);
- r.foregroundId = 0;
- r.foregroundNoti = null;
- } else if (r.appInfo.targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) {
- dropFgsNotificationStateLocked(r);
- if ((flags & Service.STOP_FOREGROUND_DETACH) != 0) {
- r.foregroundId = 0;
- r.foregroundNoti = null;
- }
- }
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 5a663a9..6129100 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3536,15 +3536,17 @@
intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
intent.putExtra(Intent.EXTRA_UID, (appInfo != null) ? appInfo.uid : -1);
intent.putExtra(Intent.EXTRA_USER_HANDLE, resolvedUserId);
+ final int[] visibilityAllowList =
+ mPackageManagerInt.getVisibilityAllowList(packageName, resolvedUserId);
if (isInstantApp) {
intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
broadcastIntentInPackage("android", null, SYSTEM_UID, uid, pid, intent,
null, null, 0, null, null, permission.ACCESS_INSTANT_APPS, null,
- false, false, resolvedUserId, false, null);
+ false, false, resolvedUserId, false, null, visibilityAllowList);
} else {
broadcastIntentInPackage("android", null, SYSTEM_UID, uid, pid, intent,
null, null, 0, null, null, null, null, false, false, resolvedUserId,
- false, null);
+ false, null, visibilityAllowList);
}
if (observer != null) {
@@ -4125,11 +4127,8 @@
return;
}
if (appId < 0) {
- try {
- appId = UserHandle.getAppId(AppGlobals.getPackageManager()
- .getPackageUid(packageName, MATCH_DEBUG_TRIAGED_MISSING, 0));
- } catch (RemoteException e) {
- }
+ appId = UserHandle.getAppId(getPackageManagerInternal().getPackageUid(packageName,
+ MATCH_DEBUG_TRIAGED_MISSING | MATCH_ANY_USER, UserHandle.USER_SYSTEM));
}
mProcessList.killAppZygotesLocked(packageName, appId, userId, true /* force */);
@@ -4146,11 +4145,8 @@
}
if (appId < 0 && packageName != null) {
- try {
- appId = UserHandle.getAppId(AppGlobals.getPackageManager()
- .getPackageUid(packageName, MATCH_DEBUG_TRIAGED_MISSING, 0));
- } catch (RemoteException e) {
- }
+ appId = UserHandle.getAppId(getPackageManagerInternal().getPackageUid(packageName,
+ MATCH_DEBUG_TRIAGED_MISSING | MATCH_ANY_USER, UserHandle.USER_SYSTEM));
}
boolean didSomething;
@@ -13653,7 +13649,8 @@
IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras,
String requiredPermission, Bundle bOptions, boolean serialized, boolean sticky,
int userId, boolean allowBackgroundActivityStarts,
- @Nullable IBinder backgroundActivityStartsToken) {
+ @Nullable IBinder backgroundActivityStartsToken,
+ @Nullable int[] broadcastAllowList) {
synchronized(this) {
intent = verifyBroadcastLocked(intent);
@@ -13665,8 +13662,7 @@
resultTo, resultCode, resultData, resultExtras, requiredPermissions, null,
OP_NONE, bOptions, serialized, sticky, -1, uid, realCallingUid,
realCallingPid, userId, allowBackgroundActivityStarts,
- backgroundActivityStartsToken,
- null /* broadcastAllowList */);
+ backgroundActivityStartsToken, broadcastAllowList);
} finally {
Binder.restoreCallingIdentity(origId);
}
@@ -15851,13 +15847,14 @@
IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras,
String requiredPermission, Bundle bOptions, boolean serialized, boolean sticky,
int userId, boolean allowBackgroundActivityStarts,
- @Nullable IBinder backgroundActivityStartsToken) {
+ @Nullable IBinder backgroundActivityStartsToken,
+ @Nullable int[] broadcastAllowList) {
synchronized (ActivityManagerService.this) {
return ActivityManagerService.this.broadcastIntentInPackage(packageName, featureId,
uid, realCallingUid, realCallingPid, intent, resolvedType, resultTo,
resultCode, resultData, resultExtras, requiredPermission, bOptions,
serialized, sticky, userId, allowBackgroundActivityStarts,
- backgroundActivityStartsToken);
+ backgroundActivityStartsToken, broadcastAllowList);
}
}
diff --git a/services/core/java/com/android/server/am/AppExitInfoTracker.java b/services/core/java/com/android/server/am/AppExitInfoTracker.java
index abb8243..979a9ee 100644
--- a/services/core/java/com/android/server/am/AppExitInfoTracker.java
+++ b/services/core/java/com/android/server/am/AppExitInfoTracker.java
@@ -430,7 +430,13 @@
final ApplicationExitInfo info = new ApplicationExitInfo(raw);
final String[] packages = raw.getPackageList();
- final int uid = raw.getPackageUid();
+ int uid = raw.getRealUid();
+ if (UserHandle.isIsolated(uid)) {
+ Integer k = mIsolatedUidRecords.getUidByIsolatedUid(uid);
+ if (k != null) {
+ uid = k;
+ }
+ }
for (int i = 0; i < packages.length; i++) {
addExitInfoInnerLocked(packages[i], uid, info);
}
@@ -833,14 +839,14 @@
pw.println(prefix + "package: " + packageName);
int size = array.size();
for (int i = 0; i < size; i++) {
- pw.println(prefix + " Historical Process Exit for userId=" + array.keyAt(i));
+ pw.println(prefix + " Historical Process Exit for uid=" + array.keyAt(i));
array.valueAt(i).dumpLocked(pw, prefix + " ", sdf);
}
}
@GuardedBy("mLock")
- private void addExitInfoInnerLocked(String packageName, int userId, ApplicationExitInfo info) {
- AppExitInfoContainer container = mData.get(packageName, userId);
+ private void addExitInfoInnerLocked(String packageName, int uid, ApplicationExitInfo info) {
+ AppExitInfoContainer container = mData.get(packageName, uid);
if (container == null) {
container = new AppExitInfoContainer(mAppExitInfoHistoryListSize);
if (UserHandle.isIsolated(info.getRealUid())) {
@@ -851,7 +857,7 @@
} else {
container.mUid = info.getRealUid();
}
- mData.put(packageName, userId, container);
+ mData.put(packageName, uid, container);
}
container.addExitInfoLocked(info);
}
@@ -997,7 +1003,7 @@
info.setPackageList(app.getPackageList());
info.setReason(ApplicationExitInfo.REASON_UNKNOWN);
info.setStatus(0);
- info.setImportance(procStateToImportance(app.mState.getSetProcState()));
+ info.setImportance(procStateToImportance(app.mState.getReportedProcState()));
info.setPss(app.mProfile.getLastPss());
info.setRss(app.mProfile.getLastRss());
info.setTimestamp(timestamp);
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index 0c633ca..449f02e 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -79,6 +79,9 @@
// There is some accuracy error in wifi reports so allow some slop in the results.
private static final long MAX_WIFI_STATS_SAMPLE_ERROR_MILLIS = 750;
+ // Delay for clearing out battery stats for UIDs corresponding to a removed user
+ public static final int UID_REMOVAL_AFTER_USER_REMOVAL_DELAY_MILLIS = 10_000;
+
private final ScheduledExecutorService mExecutorService =
Executors.newSingleThreadScheduledExecutor(
(ThreadFactory) r -> {
@@ -346,6 +349,17 @@
}
}
+ @Override
+ public Future<?> scheduleCleanupDueToRemovedUser(int userId) {
+ synchronized (BatteryExternalStatsWorker.this) {
+ return mExecutorService.schedule(() -> {
+ synchronized (mStats) {
+ mStats.clearRemovedUserUidsLocked(userId);
+ }
+ }, UID_REMOVAL_AFTER_USER_REMOVAL_DELAY_MILLIS, TimeUnit.MILLISECONDS);
+ }
+ }
+
/**
* Schedule a sync {@param syncRunnable} with a delay. If there's already a scheduled sync, a
* new sync won't be scheduled unless it is being scheduled to run immediately (delayMillis=0).
@@ -481,7 +495,7 @@
mStats.removeIsolatedUidLocked(uid, SystemClock.elapsedRealtime(),
SystemClock.uptimeMillis());
}
- mStats.clearPendingRemovedUids();
+ mStats.clearPendingRemovedUidsLocked();
}
} catch (Exception e) {
Slog.wtf(TAG, "Error updating external stats: ", e);
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index f7c777e..175da9c 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -24,6 +24,7 @@
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityOptions;
+import android.app.BroadcastOptions;
import android.app.PendingIntent;
import android.content.IIntentReceiver;
import android.content.IIntentSender;
@@ -408,6 +409,18 @@
}
controller.mAmInternal.tempAllowlistForPendingIntent(callingPid, callingUid,
uid, duration.duration, duration.type, duration.reasonCode, tag.toString());
+ } else if (key.type == ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE
+ && options != null) {
+ // If this is a getForegroundService() type pending intent, use its BroadcastOptions
+ // temp allowlist duration as its pending intent temp allowlist duration.
+ BroadcastOptions brOptions = new BroadcastOptions(options);
+ if (brOptions.getTemporaryAppAllowlistDuration() > 0) {
+ controller.mAmInternal.tempAllowlistForPendingIntent(callingPid, callingUid,
+ uid, brOptions.getTemporaryAppAllowlistDuration(),
+ brOptions.getTemporaryAppAllowlistType(),
+ brOptions.getTemporaryAppAllowlistReasonCode(),
+ brOptions.getTemporaryAppAllowlistReason());
+ }
}
boolean sendFinish = finishedReceiver != null;
@@ -468,7 +481,8 @@
key.featureId, uid, callingUid, callingPid, finalIntent,
resolvedType, finishedReceiver, code, null, null,
requiredPermission, options, (finishedReceiver != null), false,
- userId, allowedByToken || allowTrampoline, bgStartsToken);
+ userId, allowedByToken || allowTrampoline, bgStartsToken,
+ null /* broadcastAllowList */);
if (sent == ActivityManager.BROADCAST_SUCCESS) {
sendFinish = false;
}
diff --git a/services/core/java/com/android/server/am/PhantomProcessList.java b/services/core/java/com/android/server/am/PhantomProcessList.java
index 4f3438fe..ca31681 100644
--- a/services/core/java/com/android/server/am/PhantomProcessList.java
+++ b/services/core/java/com/android/server/am/PhantomProcessList.java
@@ -305,7 +305,7 @@
}
// Somehow our record doesn't match, remove it anyway
Slog.w(TAG, "Stale " + proc + ", removing");
- mPhantomProcesses.removeAt(index);
+ onPhantomProcessKilledLocked(proc);
} else {
// Is this one of the zombie processes we've known?
final int idx = mZombiePhantomProcesses.indexOfKey(pid);
diff --git a/services/core/java/com/android/server/am/ProcessStateRecord.java b/services/core/java/com/android/server/am/ProcessStateRecord.java
index 7520d88..dc6bcd8 100644
--- a/services/core/java/com/android/server/am/ProcessStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessStateRecord.java
@@ -1086,7 +1086,7 @@
mCurRawAdj = mSetRawAdj = mCurAdj = mSetAdj = mVerifiedAdj = ProcessList.INVALID_ADJ;
mCurCapability = mSetCapability = PROCESS_CAPABILITY_NONE;
mCurSchedGroup = mSetSchedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
- mCurProcState = mRepProcState = mCurRawProcState = mSetProcState = mAllowStartFgsState =
+ mCurProcState = mCurRawProcState = mSetProcState = mAllowStartFgsState =
PROCESS_STATE_NONEXISTENT;
}
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 24edc01..ca844f5 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -1821,13 +1821,13 @@
for (int attributionNum = 0; attributionNum < numAttributions;
attributionNum++) {
ParsedAttribution attribution = pkg.getAttributions().get(attributionNum);
- attributionTags.add(attribution.tag);
+ attributionTags.add(attribution.getTag());
- int numInheritFrom = attribution.inheritFrom.size();
+ int numInheritFrom = attribution.getInheritFrom().size();
for (int inheritFromNum = 0; inheritFromNum < numInheritFrom;
inheritFromNum++) {
- dstAttributionTags.put(attribution.inheritFrom.get(inheritFromNum),
- attribution.tag);
+ dstAttributionTags.put(attribution.getInheritFrom().get(inheritFromNum),
+ attribution.getTag());
}
}
}
@@ -4621,7 +4621,7 @@
if (pkg.getAttributions() != null) {
int numAttributions = pkg.getAttributions().size();
for (int i = 0; i < numAttributions; i++) {
- if (pkg.getAttributions().get(i).tag.equals(attributionTag)) {
+ if (pkg.getAttributions().get(i).getTag().equals(attributionTag)) {
return true;
}
}
@@ -7297,6 +7297,30 @@
}
}
}
+
+ @Override
+ public int getOpRestrictionCount(int code, UserHandle user, String pkg,
+ String attributionTag) {
+ int number = 0;
+ synchronized (AppOpsService.this) {
+ int numRestrictions = mOpUserRestrictions.size();
+ for (int i = 0; i < numRestrictions; i++) {
+ if (mOpUserRestrictions.valueAt(i)
+ .hasRestriction(code, pkg, attributionTag, user.getIdentifier())) {
+ number++;
+ }
+ }
+
+ numRestrictions = mOpGlobalRestrictions.size();
+ for (int i = 0; i < numRestrictions; i++) {
+ if (mOpGlobalRestrictions.valueAt(i).hasRestriction(code)) {
+ number++;
+ }
+ }
+ }
+
+ return number;
+ }
}
/**
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index fed320d..6b7787a 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -73,6 +73,7 @@
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.DumpUtils;
import com.android.server.SystemService;
+import com.android.server.biometrics.sensors.CoexCoordinator;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -1100,6 +1101,12 @@
}
return new ArrayList<>();
}
+
+ public boolean isAdvancedCoexLogicEnabled(Context context) {
+ return (Build.IS_USERDEBUG || Build.IS_ENG)
+ && Settings.Secure.getInt(context.getContentResolver(),
+ CoexCoordinator.SETTING_ENABLE_NAME, 0) != 0;
+ }
}
/**
@@ -1126,6 +1133,12 @@
mSettingObserver = mInjector.getSettingObserver(context, mHandler,
mEnabledOnKeyguardCallbacks);
+ // TODO(b/193089985) This logic lives here (outside of CoexCoordinator) so that it doesn't
+ // need to depend on context. We can remove this code once the advanced logic is enabled
+ // by default.
+ CoexCoordinator coexCoordinator = CoexCoordinator.getInstance();
+ coexCoordinator.setAdvancedLogicEnabled(injector.isAdvancedCoexLogicEnabled(context));
+
try {
injector.getActivityManagerService().registerUserSwitchObserver(
new UserSwitchObserver() {
@@ -1437,5 +1450,7 @@
pw.println();
pw.println("CurrentSession: " + mCurrentAuthSession);
pw.println();
+ pw.println("CoexCoordinator: " + CoexCoordinator.getInstance().toString());
+ pw.println();
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
index 28c949d..6463e04 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
@@ -16,6 +16,7 @@
package com.android.server.biometrics.sensors;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
@@ -30,6 +31,7 @@
import android.hardware.biometrics.BiometricsProtoEnums;
import android.os.IBinder;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.security.KeyStore;
import android.util.EventLog;
import android.util.Slog;
@@ -48,6 +50,18 @@
private static final String TAG = "Biometrics/AuthenticationClient";
+ // New, has not started yet
+ public static final int STATE_NEW = 0;
+ // Framework/HAL have started this operation
+ public static final int STATE_STARTED = 1;
+ // Operation is started, but requires some user action (such as finger lift & re-touch)
+ public static final int STATE_STARTED_PAUSED = 2;
+ // Done, errored, canceled, etc. HAL/framework are not running this sensor anymore.
+ public static final int STATE_STOPPED = 3;
+
+ @IntDef({STATE_NEW, STATE_STARTED, STATE_STARTED_PAUSED, STATE_STOPPED})
+ @interface State {}
+
private final boolean mIsStrongBiometric;
private final boolean mRequireConfirmation;
private final ActivityTaskManager mActivityTaskManager;
@@ -63,6 +77,20 @@
protected boolean mAuthAttempted;
+ // TODO: This is currently hard to maintain, as each AuthenticationClient subclass must update
+ // the state. We should think of a way to improve this in the future.
+ protected @State int mState = STATE_NEW;
+
+ /**
+ * Handles lifecycle, e.g. {@link BiometricScheduler},
+ * {@link com.android.server.biometrics.sensors.BaseClientMonitor.Callback} after authentication
+ * results are known. Note that this happens asynchronously from (but shortly after)
+ * {@link #onAuthenticated(BiometricAuthenticator.Identifier, boolean, ArrayList)} and allows
+ * {@link CoexCoordinator} a chance to invoke/delay this event.
+ * @param authenticated
+ */
+ protected abstract void handleLifecycleAfterAuth(boolean authenticated);
+
public AuthenticationClient(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon,
@NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener,
int targetUserId, long operationId, boolean restricted, @NonNull String owner,
@@ -221,7 +249,8 @@
}
final CoexCoordinator coordinator = CoexCoordinator.getInstance();
- coordinator.onAuthenticationSucceeded(this, new CoexCoordinator.Callback() {
+ coordinator.onAuthenticationSucceeded(SystemClock.uptimeMillis(), this,
+ new CoexCoordinator.Callback() {
@Override
public void sendAuthenticationResult(boolean addAuthTokenIfStrong) {
if (addAuthTokenIfStrong && mIsStrongBiometric) {
@@ -262,6 +291,11 @@
vibrateSuccess();
}
}
+
+ @Override
+ public void handleLifecycleAfterAuth() {
+ AuthenticationClient.this.handleLifecycleAfterAuth(true /* authenticated */);
+ }
});
} else {
// Allow system-defined limit of number of attempts before giving up
@@ -272,7 +306,7 @@
}
final CoexCoordinator coordinator = CoexCoordinator.getInstance();
- coordinator.onAuthenticationRejected(this, lockoutMode,
+ coordinator.onAuthenticationRejected(SystemClock.uptimeMillis(), this, lockoutMode,
new CoexCoordinator.Callback() {
@Override
public void sendAuthenticationResult(boolean addAuthTokenIfStrong) {
@@ -291,6 +325,11 @@
vibrateError();
}
}
+
+ @Override
+ public void handleLifecycleAfterAuth() {
+ AuthenticationClient.this.handleLifecycleAfterAuth(false /* authenticated */);
+ }
});
}
}
@@ -307,6 +346,12 @@
}
}
+ @Override
+ public void onError(int errorCode, int vendorCode) {
+ super.onError(errorCode, vendorCode);
+ mState = STATE_STOPPED;
+ }
+
/**
* Start authentication
*/
@@ -345,6 +390,10 @@
}
}
+ public @State int getState() {
+ return mState;
+ }
+
@Override
public int getProtoEnum() {
return BiometricsProto.CM_AUTHENTICATE;
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
index 6126607..b20316e 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
@@ -356,10 +356,12 @@
/**
* Creates a new scheduler.
* @param tag for the specific instance of the scheduler. Should be unique.
+ * @param sensorType the sensorType that this scheduler is handling.
* @param gestureAvailabilityDispatcher may be null if the sensor does not support gestures
* (such as fingerprint swipe).
*/
- public BiometricScheduler(@NonNull String tag, @SensorType int sensorType,
+ public BiometricScheduler(@NonNull String tag,
+ @SensorType int sensorType,
@Nullable GestureAvailabilityDispatcher gestureAvailabilityDispatcher) {
this(tag, sensorType, gestureAvailabilityDispatcher, IBiometricService.Stub.asInterface(
ServiceManager.getService(Context.BIOMETRIC_SERVICE)), LOG_NUM_RECENT_OPERATIONS,
diff --git a/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java b/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java
index 08bf2e0..f732a14 100644
--- a/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java
@@ -16,12 +16,23 @@
package com.android.server.biometrics.sensors;
+import static com.android.server.biometrics.sensors.BiometricScheduler.SENSOR_TYPE_FACE;
+import static com.android.server.biometrics.sensors.BiometricScheduler.SENSOR_TYPE_UDFPS;
import static com.android.server.biometrics.sensors.BiometricScheduler.sensorTypeToString;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Handler;
+import android.os.Looper;
import android.util.Slog;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.biometrics.sensors.BiometricScheduler.SensorType;
+import com.android.server.biometrics.sensors.fingerprint.Udfps;
+
import java.util.HashMap;
+import java.util.LinkedList;
import java.util.Map;
/**
@@ -33,8 +44,13 @@
public class CoexCoordinator {
private static final String TAG = "BiometricCoexCoordinator";
+ public static final String SETTING_ENABLE_NAME =
+ "com.android.server.biometrics.sensors.CoexCoordinator.enable";
private static final boolean DEBUG = true;
+ // Successful authentications should be used within this amount of time.
+ static final long SUCCESSFUL_AUTH_VALID_DURATION_MS = 5000;
+
/**
* Callback interface notifying the owner of "results" from the CoexCoordinator's business
* logic.
@@ -50,24 +66,101 @@
* Requests the owner to initiate a vibration for this event.
*/
void sendHapticFeedback();
+
+ /**
+ * Requests the owner to handle the AuthenticationClient's lifecycle (e.g. finish and remove
+ * from scheduler if auth was successful).
+ */
+ void handleLifecycleAfterAuth();
}
private static CoexCoordinator sInstance;
+ @VisibleForTesting
+ public static class SuccessfulAuth {
+ final long mAuthTimestamp;
+ final @SensorType int mSensorType;
+ final AuthenticationClient<?> mAuthenticationClient;
+ final Callback mCallback;
+ final CleanupRunnable mCleanupRunnable;
+
+ public static class CleanupRunnable implements Runnable {
+ @NonNull final LinkedList<SuccessfulAuth> mSuccessfulAuths;
+ @NonNull final SuccessfulAuth mAuth;
+ @NonNull final Callback mCallback;
+
+ public CleanupRunnable(@NonNull LinkedList<SuccessfulAuth> successfulAuths,
+ @NonNull SuccessfulAuth auth, @NonNull Callback callback) {
+ mSuccessfulAuths = successfulAuths;
+ mAuth = auth;
+ mCallback = callback;
+ }
+
+ @Override
+ public void run() {
+ final boolean removed = mSuccessfulAuths.remove(mAuth);
+ Slog.w(TAG, "Removing stale successfulAuth: " + mAuth.toString()
+ + ", success: " + removed);
+ mCallback.handleLifecycleAfterAuth();
+ }
+ }
+
+ public SuccessfulAuth(@NonNull Handler handler,
+ @NonNull LinkedList<SuccessfulAuth> successfulAuths,
+ long currentTimeMillis,
+ @SensorType int sensorType,
+ @NonNull AuthenticationClient<?> authenticationClient,
+ @NonNull Callback callback) {
+ mAuthTimestamp = currentTimeMillis;
+ mSensorType = sensorType;
+ mAuthenticationClient = authenticationClient;
+ mCallback = callback;
+
+ mCleanupRunnable = new CleanupRunnable(successfulAuths, this, callback);
+
+ handler.postDelayed(mCleanupRunnable, SUCCESSFUL_AUTH_VALID_DURATION_MS);
+ }
+
+ @Override
+ public String toString() {
+ return "SensorType: " + sensorTypeToString(mSensorType)
+ + ", mAuthTimestamp: " + mAuthTimestamp
+ + ", authenticationClient: " + mAuthenticationClient;
+ }
+ }
+
+ /**
+ * @return a singleton instance.
+ */
@NonNull
- static CoexCoordinator getInstance() {
+ public static CoexCoordinator getInstance() {
if (sInstance == null) {
sInstance = new CoexCoordinator();
}
return sInstance;
}
+ @VisibleForTesting
+ public void setAdvancedLogicEnabled(boolean enabled) {
+ mAdvancedLogicEnabled = enabled;
+ }
+
+ @VisibleForTesting
+ void reset() {
+ mClientMap.clear();
+ }
+
// SensorType to AuthenticationClient map
private final Map<Integer, AuthenticationClient<?>> mClientMap;
+ @VisibleForTesting final LinkedList<SuccessfulAuth> mSuccessfulAuths;
+ private boolean mAdvancedLogicEnabled;
+ private final Handler mHandler;
private CoexCoordinator() {
// Singleton
mClientMap = new HashMap<>();
+ mSuccessfulAuths = new LinkedList<>();
+ mHandler = new Handler(Looper.getMainLooper());
}
public void addAuthenticationClient(@BiometricScheduler.SensorType int sensorType,
@@ -99,23 +192,132 @@
mClientMap.remove(sensorType);
}
- public void onAuthenticationSucceeded(@NonNull AuthenticationClient<?> client,
+ public void onAuthenticationSucceeded(long currentTimeMillis,
+ @NonNull AuthenticationClient<?> client,
@NonNull Callback callback) {
if (client.isBiometricPrompt()) {
callback.sendHapticFeedback();
// For BP, BiometricService will add the authToken to Keystore.
callback.sendAuthenticationResult(false /* addAuthTokenIfStrong */);
- } else {
- // Keyguard, FingerprintManager, FaceManager, etc
+ callback.handleLifecycleAfterAuth();
+ } else if (isUnknownClient(client)) {
+ // Client doesn't exist in our map for some reason. Give the user feedback so the
+ // device doesn't feel like it's stuck. All other cases below can assume that the
+ // client exists in our map.
callback.sendHapticFeedback();
callback.sendAuthenticationResult(true /* addAuthTokenIfStrong */);
+ callback.handleLifecycleAfterAuth();
+ } else if (mAdvancedLogicEnabled && client.isKeyguard()) {
+ if (isSingleAuthOnly(client)) {
+ // Single sensor authentication
+ callback.sendHapticFeedback();
+ callback.sendAuthenticationResult(true /* addAuthTokenIfStrong */);
+ callback.handleLifecycleAfterAuth();
+ } else {
+ // Multi sensor authentication
+ AuthenticationClient<?> udfps = mClientMap.getOrDefault(SENSOR_TYPE_UDFPS, null);
+ AuthenticationClient<?> face = mClientMap.getOrDefault(SENSOR_TYPE_FACE, null);
+ if (isCurrentFaceAuth(client)) {
+ if (isUdfpsActivelyAuthing(udfps)) {
+ // Face auth success while UDFPS is actively authing. No callback, no haptic
+ // Feedback will be provided after UDFPS result:
+ // 1) UDFPS succeeds - simply remove this from the queue
+ // 2) UDFPS rejected - use this face auth success to notify clients
+ mSuccessfulAuths.add(new SuccessfulAuth(mHandler, mSuccessfulAuths,
+ currentTimeMillis, SENSOR_TYPE_FACE, client, callback));
+ } else {
+ callback.sendHapticFeedback();
+ callback.sendAuthenticationResult(true /* addAuthTokenIfStrong */);
+ callback.handleLifecycleAfterAuth();
+ }
+ } else if (isCurrentUdfps(client)) {
+ if (isFaceScanning()) {
+ // UDFPS succeeds while face is still scanning
+ // Cancel face auth and/or prevent it from invoking haptics/callbacks after
+ face.cancel();
+ }
+
+ removeAndFinishAllFaceFromQueue();
+
+ callback.sendHapticFeedback();
+ callback.sendAuthenticationResult(true /* addAuthTokenIfStrong */);
+ callback.handleLifecycleAfterAuth();
+ }
+ }
+ } else {
+ // Non-keyguard authentication. For example, Fingerprint Settings use of
+ // FingerprintManager for highlighting fingers
+ callback.sendHapticFeedback();
+ callback.sendAuthenticationResult(true /* addAuthTokenIfStrong */);
+ callback.handleLifecycleAfterAuth();
}
}
- public void onAuthenticationRejected(@NonNull AuthenticationClient<?> client,
+ public void onAuthenticationRejected(long currentTimeMillis,
+ @NonNull AuthenticationClient<?> client,
@LockoutTracker.LockoutMode int lockoutMode,
@NonNull Callback callback) {
- callback.sendHapticFeedback();
+ final boolean keyguardAdvancedLogic = mAdvancedLogicEnabled && client.isKeyguard();
+
+ if (keyguardAdvancedLogic) {
+ if (isSingleAuthOnly(client)) {
+ callback.sendHapticFeedback();
+ callback.handleLifecycleAfterAuth();
+ } else {
+ // Multi sensor authentication
+ AuthenticationClient<?> udfps = mClientMap.getOrDefault(SENSOR_TYPE_UDFPS, null);
+ AuthenticationClient<?> face = mClientMap.getOrDefault(SENSOR_TYPE_FACE, null);
+ if (isCurrentFaceAuth(client)) {
+ if (isUdfpsActivelyAuthing(udfps)) {
+ // UDFPS should still be running in this case, do not vibrate. However, we
+ // should notify the callback and finish the client, so that Keyguard and
+ // BiometricScheduler do not get stuck.
+ Slog.d(TAG, "Face rejected in multi-sensor auth, udfps: " + udfps);
+ callback.handleLifecycleAfterAuth();
+ } else {
+ // UDFPS is not actively authenticating (finger not touching, already
+ // rejected, etc).
+ callback.sendHapticFeedback();
+ callback.handleLifecycleAfterAuth();
+ }
+ } else if (isCurrentUdfps(client)) {
+ // Face should either be running, or have already finished
+ SuccessfulAuth auth = popSuccessfulFaceAuthIfExists(currentTimeMillis);
+ if (auth != null) {
+ Slog.d(TAG, "Using recent auth: " + auth);
+ callback.handleLifecycleAfterAuth();
+
+ auth.mCallback.sendHapticFeedback();
+ auth.mCallback.sendAuthenticationResult(true /* addAuthTokenIfStrong */);
+ auth.mCallback.handleLifecycleAfterAuth();
+ } else if (isFaceScanning()) {
+ // UDFPS rejected but face is still scanning
+ Slog.d(TAG, "UDFPS rejected in multi-sensor auth, face: " + face);
+ callback.handleLifecycleAfterAuth();
+
+ // TODO(b/193089985): Enforce/ensure that face auth finishes (whether
+ // accept/reject) within X amount of time. Otherwise users will be stuck
+ // waiting with their finger down for a long time.
+ } else {
+ // Face not scanning, and was not found in the queue. Most likely, face
+ // auth was too long ago.
+ Slog.d(TAG, "UDFPS rejected in multi-sensor auth, face not scanning");
+ callback.sendHapticFeedback();
+ callback.handleLifecycleAfterAuth();
+ }
+ } else {
+ Slog.d(TAG, "Unknown client rejected: " + client);
+ callback.sendHapticFeedback();
+ callback.handleLifecycleAfterAuth();
+ }
+ }
+ } else {
+ callback.sendHapticFeedback();
+ callback.handleLifecycleAfterAuth();
+ }
+
+ // Always notify keyguard, otherwise the cached "running" state in KeyguardUpdateMonitor
+ // will get stuck.
if (lockoutMode == LockoutTracker.LOCKOUT_NONE) {
// Don't send onAuthenticationFailed if we're in lockout, it causes a
// janky UI on Keyguard/BiometricPrompt since "authentication failed"
@@ -123,4 +325,82 @@
callback.sendAuthenticationResult(false /* addAuthTokenIfStrong */);
}
}
+
+ @Nullable
+ private SuccessfulAuth popSuccessfulFaceAuthIfExists(long currentTimeMillis) {
+ for (SuccessfulAuth auth : mSuccessfulAuths) {
+ if (currentTimeMillis - auth.mAuthTimestamp >= SUCCESSFUL_AUTH_VALID_DURATION_MS) {
+ Slog.d(TAG, "Removing stale auth: " + auth);
+ mSuccessfulAuths.remove(auth);
+ } else if (auth.mSensorType == SENSOR_TYPE_FACE) {
+ mSuccessfulAuths.remove(auth);
+ return auth;
+ }
+ }
+ return null;
+ }
+
+ private void removeAndFinishAllFaceFromQueue() {
+ for (SuccessfulAuth auth : mSuccessfulAuths) {
+ if (auth.mSensorType == SENSOR_TYPE_FACE) {
+ Slog.d(TAG, "Removing from queue and finishing: " + auth);
+ auth.mCallback.handleLifecycleAfterAuth();
+ mSuccessfulAuths.remove(auth);
+ }
+ }
+ }
+
+ private boolean isCurrentFaceAuth(@NonNull AuthenticationClient<?> client) {
+ return client == mClientMap.getOrDefault(SENSOR_TYPE_FACE, null);
+ }
+
+ private boolean isCurrentUdfps(@NonNull AuthenticationClient<?> client) {
+ return client == mClientMap.getOrDefault(SENSOR_TYPE_UDFPS, null);
+ }
+
+ private boolean isFaceScanning() {
+ AuthenticationClient<?> client = mClientMap.getOrDefault(SENSOR_TYPE_FACE, null);
+ return client != null && client.getState() == AuthenticationClient.STATE_STARTED;
+ }
+
+ private static boolean isUdfpsActivelyAuthing(@Nullable AuthenticationClient<?> client) {
+ if (client instanceof Udfps) {
+ return client.getState() == AuthenticationClient.STATE_STARTED;
+ }
+ return false;
+ }
+
+ private boolean isUnknownClient(@NonNull AuthenticationClient<?> client) {
+ for (AuthenticationClient<?> c : mClientMap.values()) {
+ if (c == client) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private boolean isSingleAuthOnly(@NonNull AuthenticationClient<?> client) {
+ if (mClientMap.values().size() != 1) {
+ return false;
+ }
+
+ for (AuthenticationClient<?> c : mClientMap.values()) {
+ if (c != client) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("Enabled: ").append(mAdvancedLogicEnabled);
+ sb.append(", Queue size: " ).append(mSuccessfulAuths.size());
+ for (SuccessfulAuth auth : mSuccessfulAuths) {
+ sb.append(", Auth: ").append(auth.toString());
+ }
+
+ return sb.toString();
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
index 779558e..219e063 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
@@ -215,7 +215,7 @@
@Override // Binder call
public void enroll(int userId, final IBinder token, final byte[] hardwareAuthToken,
final IFaceServiceReceiver receiver, final String opPackageName,
- final int[] disabledFeatures, Surface surface, boolean debugConsent) {
+ final int[] disabledFeatures, Surface previewSurface, boolean debugConsent) {
Utils.checkPermission(getContext(), MANAGE_BIOMETRIC);
final Pair<Integer, ServiceProvider> provider = getSingleProvider();
@@ -225,8 +225,7 @@
}
provider.second.scheduleEnroll(provider.first, token, hardwareAuthToken, userId,
- receiver, opPackageName, disabledFeatures,
- convertSurfaceToNativeHandle(surface), debugConsent);
+ receiver, opPackageName, disabledFeatures, previewSurface, debugConsent);
}
@Override // Binder call
@@ -703,5 +702,27 @@
publishBinderService(Context.FACE_SERVICE, mServiceWrapper);
}
- private native NativeHandle convertSurfaceToNativeHandle(Surface surface);
+ /**
+ * Acquires a NativeHandle that can be used to access the provided surface. The returned handle
+ * must be explicitly released with {@link #releaseSurfaceHandle(NativeHandle)} to avoid memory
+ * leaks.
+ *
+ * The caller is responsible for ensuring that the surface is valid while using the handle.
+ * This method provides no lifecycle synchronization between the surface and the handle.
+ *
+ * @param surface a valid Surface.
+ * @return {@link android.os.NativeHandle} a NativeHandle for the provided surface.
+ */
+ public static native NativeHandle acquireSurfaceHandle(@NonNull Surface surface);
+
+ /**
+ * Releases resources associated with a NativeHandle that was acquired with
+ * {@link #acquireSurfaceHandle(Surface)}.
+ *
+ * This method has no affect on the surface for which the handle was acquired. It only frees up
+ * the resources that are associated with the handle.
+ *
+ * @param handle a handle that was obtained from {@link #acquireSurfaceHandle(Surface)}.
+ */
+ public static native void releaseSurfaceHandle(@NonNull NativeHandle handle);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java
index 6d6c2e9..1d2ac3b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java
@@ -26,8 +26,8 @@
import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.face.IFaceServiceReceiver;
import android.os.IBinder;
-import android.os.NativeHandle;
import android.util.proto.ProtoOutputStream;
+import android.view.Surface;
import com.android.server.biometrics.sensors.BaseClientMonitor;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
@@ -75,8 +75,8 @@
int getLockoutModeForUser(int sensorId, int userId);
/**
- * Requests for the authenticatorId (whose source of truth is in the TEE or equivalent) to
- * be invalidated. See {@link com.android.server.biometrics.sensors.InvalidationRequesterClient}
+ * Requests for the authenticatorId (whose source of truth is in the TEE or equivalent) to be
+ * invalidated. See {@link com.android.server.biometrics.sensors.InvalidationRequesterClient}
*/
default void scheduleInvalidateAuthenticatorId(int sensorId, int userId,
@NonNull IInvalidationCallback callback) {
@@ -96,7 +96,7 @@
void scheduleEnroll(int sensorId, @NonNull IBinder token, @NonNull byte[] hardwareAuthToken,
int userId, @NonNull IFaceServiceReceiver receiver, @NonNull String opPackageName,
- @NonNull int[] disabledFeatures, @Nullable NativeHandle surfaceHandle,
+ @NonNull int[] disabledFeatures, @Nullable Surface previewSurface,
boolean debugConsent);
void cancelEnrollment(int sensorId, @NonNull IBinder token);
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java
index 57c1c74..66b942b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java
@@ -150,8 +150,8 @@
Utils.checkPermission(mContext, TEST_BIOMETRIC);
mProvider.scheduleEnroll(mSensorId, new Binder(), new byte[69], userId, mReceiver,
- mContext.getOpPackageName(), new int[0] /* disabledFeatures */, null /* surface */,
- false /* debugConsent */);
+ mContext.getOpPackageName(), new int[0] /* disabledFeatures */,
+ null /* previewSurface */, false /* debugConsent */);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
index 0525d2d..35c1745 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
@@ -89,6 +89,12 @@
R.array.config_face_acquire_vendor_keyguard_ignorelist);
}
+ @Override
+ public void start(@NonNull Callback callback) {
+ super.start(callback);
+ mState = STATE_STARTED;
+ }
+
@NonNull
@Override
protected Callback wrapCallbackForStart(@NonNull Callback callback) {
@@ -128,10 +134,20 @@
}
@Override
+ protected void handleLifecycleAfterAuth(boolean authenticated) {
+ // For face, the authentication lifecycle ends either when
+ // 1) Authenticated == true
+ // 2) Error occurred
+ // 3) Authenticated == false
+ mCallback.onClientFinished(this, true /* success */);
+ }
+
+ @Override
public void onAuthenticated(BiometricAuthenticator.Identifier identifier,
boolean authenticated, ArrayList<Byte> token) {
super.onAuthenticated(identifier, authenticated, token);
+ mState = STATE_STOPPED;
mUsageStats.addEvent(new UsageStats.AuthenticationEvent(
getStartTimeMs(),
System.currentTimeMillis() - getStartTimeMs() /* latency */,
@@ -139,12 +155,6 @@
0 /* error */,
0 /* vendorError */,
getTargetUserId()));
-
- // For face, the authentication lifecycle ends either when
- // 1) Authenticated == true
- // 2) Error occurred
- // 3) Authenticated == false
- mCallback.onClientFinished(this, true /* success */);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java
index 0400e22..55c987a 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java
@@ -26,21 +26,24 @@
import android.hardware.biometrics.face.Feature;
import android.hardware.biometrics.face.IFace;
import android.hardware.biometrics.face.ISession;
+import android.hardware.common.NativeHandle;
import android.hardware.face.Face;
import android.hardware.face.FaceEnrollFrame;
import android.hardware.face.FaceManager;
import android.os.IBinder;
-import android.os.NativeHandle;
import android.os.RemoteException;
import android.util.Slog;
+import android.view.Surface;
import com.android.internal.R;
import com.android.server.biometrics.HardwareAuthTokenUtils;
import com.android.server.biometrics.Utils;
+import com.android.server.biometrics.sensors.BaseClientMonitor;
import com.android.server.biometrics.sensors.BiometricNotificationUtils;
import com.android.server.biometrics.sensors.BiometricUtils;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.EnrollClient;
+import com.android.server.biometrics.sensors.face.FaceService;
import com.android.server.biometrics.sensors.face.FaceUtils;
import java.io.IOException;
@@ -57,16 +60,31 @@
@NonNull private final int[] mEnrollIgnoreList;
@NonNull private final int[] mEnrollIgnoreListVendor;
@NonNull private final int[] mDisabledFeatures;
+ @Nullable private final Surface mPreviewSurface;
+ @Nullable private android.os.NativeHandle mOsPreviewHandle;
+ @Nullable private NativeHandle mHwPreviewHandle;
@Nullable private ICancellationSignal mCancellationSignal;
- @Nullable private android.hardware.common.NativeHandle mPreviewSurface;
private final int mMaxTemplatesPerUser;
private final boolean mDebugConsent;
+ private final BaseClientMonitor.Callback mPreviewHandleDeleterCallback =
+ new BaseClientMonitor.Callback() {
+ @Override
+ public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
+ }
+
+ @Override
+ public void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
+ boolean success) {
+ releaseSurfaceHandlesIfNeeded();
+ }
+ };
+
FaceEnrollClient(@NonNull Context context, @NonNull LazyDaemon<ISession> lazyDaemon,
@NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId,
@NonNull byte[] hardwareAuthToken, @NonNull String opPackageName,
@NonNull BiometricUtils<Face> utils, @NonNull int[] disabledFeatures, int timeoutSec,
- @Nullable NativeHandle previewSurface, int sensorId, int maxTemplatesPerUser,
+ @Nullable Surface previewSurface, int sensorId, int maxTemplatesPerUser,
boolean debugConsent) {
super(context, lazyDaemon, token, listener, userId, hardwareAuthToken, opPackageName, utils,
timeoutSec, BiometricsProtoEnums.MODALITY_FACE, sensorId,
@@ -78,14 +96,7 @@
mMaxTemplatesPerUser = maxTemplatesPerUser;
mDebugConsent = debugConsent;
mDisabledFeatures = disabledFeatures;
- try {
- // We must manually close the duplicate handle after it's no longer needed.
- // The caller is responsible for closing the original handle.
- mPreviewSurface = AidlNativeHandleUtils.dup(previewSurface);
- } catch (IOException e) {
- mPreviewSurface = null;
- Slog.e(TAG, "Failed to dup previewSurface", e);
- }
+ mPreviewSurface = previewSurface;
}
@Override
@@ -98,17 +109,7 @@
@NonNull
@Override
protected Callback wrapCallbackForStart(@NonNull Callback callback) {
- return new CompositeCallback(createALSCallback(), callback);
- }
-
- @Override
- public void destroy() {
- try {
- AidlNativeHandleUtils.close(mPreviewSurface);
- } catch (IOException e) {
- Slog.e(TAG, "Failed to close mPreviewSurface", e);
- }
- super.destroy();
+ return new CompositeCallback(mPreviewHandleDeleterCallback, createALSCallback(), callback);
}
@Override
@@ -153,22 +154,23 @@
@Override
protected void startHalOperation() {
+ obtainSurfaceHandlesIfNeeded();
try {
List<Byte> featureList = new ArrayList<Byte>();
if (mDebugConsent) {
- featureList.add(new Byte(Feature.DEBUG));
+ featureList.add(Feature.DEBUG);
}
boolean shouldAddDiversePoses = true;
- for (int i = 0; i < mDisabledFeatures.length; i++) {
- if (AidlConversionUtils.convertFrameworkToAidlFeature(mDisabledFeatures[i])
+ for (int disabledFeature : mDisabledFeatures) {
+ if (AidlConversionUtils.convertFrameworkToAidlFeature(disabledFeature)
== Feature.REQUIRE_DIVERSE_POSES) {
shouldAddDiversePoses = false;
}
}
if (shouldAddDiversePoses) {
- featureList.add(new Byte(Feature.REQUIRE_DIVERSE_POSES));
+ featureList.add(Feature.REQUIRE_DIVERSE_POSES);
}
byte[] features = new byte[featureList.size()];
@@ -178,7 +180,7 @@
mCancellationSignal = getFreshDaemon().enroll(
HardwareAuthTokenUtils.toHardwareAuthToken(mHardwareAuthToken),
- EnrollmentType.DEFAULT, features, mPreviewSurface);
+ EnrollmentType.DEFAULT, features, mHwPreviewHandle);
} catch (RemoteException | IllegalArgumentException e) {
Slog.e(TAG, "Exception when requesting enroll", e);
onError(BiometricFaceConstants.FACE_ERROR_UNABLE_TO_PROCESS, 0 /* vendorCode */);
@@ -198,4 +200,55 @@
}
}
}
+
+ private void obtainSurfaceHandlesIfNeeded() {
+ if (mPreviewSurface != null) {
+ // There is no direct way to convert Surface to android.hardware.common.NativeHandle. We
+ // first convert Surface to android.os.NativeHandle, and then android.os.NativeHandle to
+ // android.hardware.common.NativeHandle, which can be passed to the HAL.
+ // The resources for both handles must be explicitly freed to avoid memory leaks.
+ mOsPreviewHandle = FaceService.acquireSurfaceHandle(mPreviewSurface);
+ try {
+ // We must manually free up the resources for both handles after they are no longer
+ // needed. mHwPreviewHandle must be closed, but mOsPreviewHandle must be released
+ // through FaceService.
+ mHwPreviewHandle = AidlNativeHandleUtils.dup(mOsPreviewHandle);
+ Slog.v(TAG, "Obtained handles for the preview surface.");
+ } catch (IOException e) {
+ mHwPreviewHandle = null;
+ Slog.e(TAG, "Failed to dup mOsPreviewHandle", e);
+ }
+ }
+ }
+
+ private void releaseSurfaceHandlesIfNeeded() {
+ if (mPreviewSurface != null && mHwPreviewHandle == null) {
+ Slog.w(TAG, "mHwPreviewHandle is null even though mPreviewSurface is not null.");
+ }
+ if (mHwPreviewHandle != null) {
+ try {
+ Slog.v(TAG, "Closing mHwPreviewHandle");
+ AidlNativeHandleUtils.close(mHwPreviewHandle);
+ } catch (IOException e) {
+ Slog.e(TAG, "Failed to close mPreviewSurface", e);
+ }
+ mHwPreviewHandle = null;
+ }
+ if (mOsPreviewHandle != null) {
+ Slog.v(TAG, "Releasing mOsPreviewHandle");
+ FaceService.releaseSurfaceHandle(mOsPreviewHandle);
+ mOsPreviewHandle = null;
+ }
+ if (mPreviewSurface != null) {
+ Slog.v(TAG, "Releasing mPreviewSurface");
+ // We need to manually release this surface because it's a copy of the original surface
+ // that was sent to us by an app (e.g. Settings). The app cleans up its own surface (as
+ // part of the SurfaceView lifecycle, for example), but there is no mechanism in place
+ // that will clean up this copy.
+ // If this copy isn't cleaned up, it will eventually be garbage collected. However, this
+ // surface could be holding onto the native buffers that the GC is not aware of,
+ // exhausting the native memory before the GC feels the need to garbage collect.
+ mPreviewSurface.release();
+ }
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
index 36a1292..5c24108 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
@@ -37,13 +37,13 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
-import android.os.NativeHandle;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserManager;
import android.util.Slog;
import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
+import android.view.Surface;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.biometrics.Utils;
@@ -327,7 +327,7 @@
public void scheduleEnroll(int sensorId, @NonNull IBinder token,
@NonNull byte[] hardwareAuthToken, int userId, @NonNull IFaceServiceReceiver receiver,
@NonNull String opPackageName, @NonNull int[] disabledFeatures,
- @Nullable NativeHandle previewSurface, boolean debugConsent) {
+ @Nullable Surface previewSurface, boolean debugConsent) {
mHandler.post(() -> {
final int maxTemplatesPerUser = mSensors.get(
sensorId).getSensorProperties().maxEnrollmentsPerUser;
@@ -400,7 +400,7 @@
@Override
public void scheduleRemove(int sensorId, @NonNull IBinder token, int faceId, int userId,
@NonNull IFaceServiceReceiver receiver, @NonNull String opPackageName) {
- scheduleRemoveSpecifiedIds(sensorId, token, new int[] {faceId}, userId, receiver,
+ scheduleRemoveSpecifiedIds(sensorId, token, new int[]{faceId}, userId, receiver,
opPackageName);
}
@@ -561,7 +561,8 @@
}
@Override
- public void dumpHal(int sensorId, @NonNull FileDescriptor fd, @NonNull String[] args) {}
+ public void dumpHal(int sensorId, @NonNull FileDescriptor fd, @NonNull String[] args) {
+ }
@Override
public void binderDied() {
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
index 4abd402..206b8f0 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
@@ -494,8 +494,8 @@
mToken = new Binder();
mHandler = handler;
mSensorProperties = sensorProperties;
- mScheduler = new UserAwareBiometricScheduler(tag, BiometricScheduler.SENSOR_TYPE_FACE,
- null /* gestureAvailabilityDispatcher */,
+ mScheduler = new UserAwareBiometricScheduler(tag,
+ BiometricScheduler.SENSOR_TYPE_FACE, null /* gestureAvailabilityDispatcher */,
() -> mCurrentSession != null ? mCurrentSession.mUserId : UserHandle.USER_NULL,
new UserAwareBiometricScheduler.UserSwitchCallback() {
@NonNull
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java
index d0580c7..b45578b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java
@@ -139,7 +139,7 @@
mFace10.scheduleEnroll(mSensorId, new Binder(), new byte[69], userId, mReceiver,
mContext.getOpPackageName(), new int[0] /* disabledFeatures */,
- null /* surfaceHandle */, false /* debugConsent */);
+ null /* previewSurface */, false /* debugConsent */);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
index e95273a..da4ad86 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
@@ -47,6 +47,7 @@
import android.provider.Settings;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
+import android.view.Surface;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FrameworkStatsLog;
@@ -88,8 +89,8 @@
import java.util.Map;
/**
- * Supports a single instance of the {@link android.hardware.biometrics.face.V1_0} or
- * its extended minor versions.
+ * Supports a single instance of the {@link android.hardware.biometrics.face.V1_0} or its extended
+ * minor versions.
*/
public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
@@ -325,7 +326,8 @@
}
}
- @VisibleForTesting Face10(@NonNull Context context,
+ @VisibleForTesting
+ Face10(@NonNull Context context,
@NonNull FaceSensorPropertiesInternal sensorProps,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull BiometricScheduler scheduler) {
@@ -571,7 +573,7 @@
public void scheduleEnroll(int sensorId, @NonNull IBinder token,
@NonNull byte[] hardwareAuthToken, int userId, @NonNull IFaceServiceReceiver receiver,
@NonNull String opPackageName, @NonNull int[] disabledFeatures,
- @Nullable NativeHandle surfaceHandle, boolean debugConsent) {
+ @Nullable Surface previewSurface, boolean debugConsent) {
mHandler.post(() -> {
scheduleUpdateActiveUserWithoutHandler(userId);
@@ -580,7 +582,7 @@
final FaceEnrollClient client = new FaceEnrollClient(mContext, mLazyDaemon, token,
new ClientMonitorCallbackConverter(receiver), userId, hardwareAuthToken,
opPackageName, FaceUtils.getLegacyInstance(mSensorId), disabledFeatures,
- ENROLL_TIMEOUT_SEC, surfaceHandle, mSensorId);
+ ENROLL_TIMEOUT_SEC, previewSurface, mSensorId);
mScheduler.scheduleClientMonitor(client, new BaseClientMonitor.Callback() {
@Override
@@ -858,8 +860,8 @@
}
/**
- * Schedules the {@link FaceUpdateActiveUserClient} without posting the work onto the
- * handler. Many/most APIs are user-specific. However, the HAL requires explicit "setActiveUser"
+ * Schedules the {@link FaceUpdateActiveUserClient} without posting the work onto the handler.
+ * Many/most APIs are user-specific. However, the HAL requires explicit "setActiveUser"
* invocation prior to authenticate/enroll/etc. Thus, internally we usually want to schedule
* this operation on the same lambda/runnable as those operations so that the ordering is
* correct.
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
index 5731d73..e65245b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
@@ -79,6 +79,12 @@
R.array.config_face_acquire_vendor_keyguard_ignorelist);
}
+ @Override
+ public void start(@NonNull Callback callback) {
+ super.start(callback);
+ mState = STATE_STARTED;
+ }
+
@NonNull
@Override
protected Callback wrapCallbackForStart(@NonNull Callback callback) {
@@ -115,10 +121,20 @@
}
@Override
+ protected void handleLifecycleAfterAuth(boolean authenticated) {
+ // For face, the authentication lifecycle ends either when
+ // 1) Authenticated == true
+ // 2) Error occurred
+ // 3) Authenticated == false
+ mCallback.onClientFinished(this, true /* success */);
+ }
+
+ @Override
public void onAuthenticated(BiometricAuthenticator.Identifier identifier,
boolean authenticated, ArrayList<Byte> token) {
super.onAuthenticated(identifier, authenticated, token);
+ mState = STATE_STOPPED;
mUsageStats.addEvent(new UsageStats.AuthenticationEvent(
getStartTimeMs(),
System.currentTimeMillis() - getStartTimeMs() /* latency */,
@@ -126,12 +142,6 @@
0 /* error */,
0 /* vendorError */,
getTargetUserId()));
-
- // For face, the authentication lifecycle ends either when
- // 1) Authenticated == true
- // 2) Error occurred
- // 3) Authenticated == false
- mCallback.onClientFinished(this, true /* success */);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceEnrollClient.java
index d3bd18b..455d6f8 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceEnrollClient.java
@@ -26,9 +26,9 @@
import android.hardware.face.Face;
import android.hardware.face.FaceManager;
import android.os.IBinder;
-import android.os.NativeHandle;
import android.os.RemoteException;
import android.util.Slog;
+import android.view.Surface;
import com.android.internal.R;
import com.android.server.biometrics.Utils;
@@ -40,15 +40,14 @@
import java.util.Arrays;
/**
- * Face-specific enroll client supporting the {@link android.hardware.biometrics.face.V1_0}
- * HIDL interface.
+ * Face-specific enroll client supporting the {@link android.hardware.biometrics.face.V1_0} HIDL
+ * interface.
*/
public class FaceEnrollClient extends EnrollClient<IBiometricsFace> {
private static final String TAG = "FaceEnrollClient";
@NonNull private final int[] mDisabledFeatures;
- @Nullable private final NativeHandle mSurfaceHandle;
@NonNull private final int[] mEnrollIgnoreList;
@NonNull private final int[] mEnrollIgnoreListVendor;
@@ -56,12 +55,11 @@
@NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId,
@NonNull byte[] hardwareAuthToken, @NonNull String owner,
@NonNull BiometricUtils<Face> utils, @NonNull int[] disabledFeatures, int timeoutSec,
- @Nullable NativeHandle surfaceHandle, int sensorId) {
+ @Nullable Surface previewSurface, int sensorId) {
super(context, lazyDaemon, token, listener, userId, hardwareAuthToken, owner, utils,
timeoutSec, BiometricsProtoEnums.MODALITY_FACE, sensorId,
false /* shouldVibrate */);
mDisabledFeatures = Arrays.copyOf(disabledFeatures, disabledFeatures.length);
- mSurfaceHandle = surfaceHandle;
mEnrollIgnoreList = getContext().getResources()
.getIntArray(R.array.config_face_acquire_enroll_ignorelist);
mEnrollIgnoreListVendor = getContext().getResources()
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/Udfps.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/Udfps.java
index 150e69c6..a2c0751 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/Udfps.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/Udfps.java
@@ -27,4 +27,5 @@
void onPointerDown(int x, int y, float minor, float major);
void onPointerUp();
void onUiReady();
+ boolean isPointerDown();
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
index 8681ad7..14d1822 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
@@ -54,7 +54,10 @@
@NonNull private final LockoutCache mLockoutCache;
@Nullable private final IUdfpsOverlayController mUdfpsOverlayController;
+ @NonNull private final FingerprintSensorPropertiesInternal mSensorProps;
+
@Nullable private ICancellationSignal mCancellationSignal;
+ private boolean mIsPointerDown;
FingerprintAuthenticationClient(@NonNull Context context,
@NonNull LazyDaemon<ISession> lazyDaemon, @NonNull IBinder token,
@@ -71,6 +74,19 @@
lockoutCache, allowBackgroundAuthentication, true /* shouldVibrate */);
mLockoutCache = lockoutCache;
mUdfpsOverlayController = udfpsOverlayController;
+ mSensorProps = sensorProps;
+ }
+
+ @Override
+ public void start(@NonNull Callback callback) {
+ super.start(callback);
+
+ if (mSensorProps.isAnyUdfpsType()) {
+ // UDFPS requires user to touch before becoming "active"
+ mState = STATE_STARTED_PAUSED;
+ } else {
+ mState = STATE_STARTED;
+ }
}
@NonNull
@@ -80,13 +96,22 @@
}
@Override
+ protected void handleLifecycleAfterAuth(boolean authenticated) {
+ if (authenticated) {
+ mCallback.onClientFinished(this, true /* success */);
+ }
+ }
+
+ @Override
public void onAuthenticated(BiometricAuthenticator.Identifier identifier,
boolean authenticated, ArrayList<Byte> token) {
super.onAuthenticated(identifier, authenticated, token);
if (authenticated) {
+ mState = STATE_STOPPED;
UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
- mCallback.onClientFinished(this, true /* success */);
+ } else {
+ mState = STATE_STARTED_PAUSED;
}
}
@@ -143,6 +168,8 @@
@Override
public void onPointerDown(int x, int y, float minor, float major) {
try {
+ mIsPointerDown = true;
+ mState = STATE_STARTED;
getFreshDaemon().onPointerDown(0 /* pointerId */, x, y, minor, major);
if (getListener() != null) {
getListener().onUdfpsPointerDown(getSensorId());
@@ -155,6 +182,8 @@
@Override
public void onPointerUp() {
try {
+ mIsPointerDown = false;
+ mState = STATE_STARTED_PAUSED;
getFreshDaemon().onPointerUp(0 /* pointerId */);
if (getListener() != null) {
getListener().onUdfpsPointerUp(getSensorId());
@@ -165,6 +194,11 @@
}
@Override
+ public boolean isPointerDown() {
+ return mIsPointerDown;
+ }
+
+ @Override
public void onUiReady() {
try {
getFreshDaemon().onUiReady();
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
index a211bb5..e8200af 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
@@ -55,6 +55,7 @@
private final @FingerprintManager.EnrollReason int mEnrollReason;
@Nullable private ICancellationSignal mCancellationSignal;
private final int mMaxTemplatesPerUser;
+ private boolean mIsPointerDown;
FingerprintEnrollClient(@NonNull Context context,
@NonNull LazyDaemon<ISession> lazyDaemon, @NonNull IBinder token,
@@ -167,6 +168,7 @@
@Override
public void onPointerDown(int x, int y, float minor, float major) {
try {
+ mIsPointerDown = true;
getFreshDaemon().onPointerDown(0 /* pointerId */, x, y, minor, major);
} catch (RemoteException e) {
Slog.e(TAG, "Unable to send pointer down", e);
@@ -176,6 +178,7 @@
@Override
public void onPointerUp() {
try {
+ mIsPointerDown = false;
getFreshDaemon().onPointerUp(0 /* pointerId */);
} catch (RemoteException e) {
Slog.e(TAG, "Unable to send pointer up", e);
@@ -183,6 +186,11 @@
}
@Override
+ public boolean isPointerDown() {
+ return mIsPointerDown;
+ }
+
+ @Override
public void onUiReady() {
try {
getFreshDaemon().onUiReady();
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
index a6385a5..2f5b5c7 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
@@ -622,7 +622,7 @@
opPackageName, cookie, false /* requireConfirmation */,
mSensorProperties.sensorId, isStrongBiometric, statsClient,
mTaskStackListener, mLockoutTracker, mUdfpsOverlayController,
- allowBackgroundAuthentication);
+ allowBackgroundAuthentication, mSensorProperties);
mScheduler.scheduleClientMonitor(client, fingerprintStateCallback);
});
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
index 312c52c..24ce867 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
@@ -138,7 +138,8 @@
TestableBiometricScheduler(@NonNull String tag,
@Nullable GestureAvailabilityDispatcher gestureAvailabilityDispatcher) {
- super(tag, BiometricScheduler.SENSOR_TYPE_FP_OTHER, gestureAvailabilityDispatcher);
+ super(tag, BiometricScheduler.SENSOR_TYPE_FP_OTHER,
+ gestureAvailabilityDispatcher);
mInternalCallback = new TestableInternalCallback();
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
index 40e3bc3..9347244 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
@@ -25,6 +25,7 @@
import android.hardware.biometrics.BiometricFingerprintConstants;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.os.IBinder;
import android.os.RemoteException;
@@ -52,6 +53,9 @@
private final LockoutFrameworkImpl mLockoutFrameworkImpl;
@Nullable private final IUdfpsOverlayController mUdfpsOverlayController;
+ @NonNull private final FingerprintSensorPropertiesInternal mSensorProps;
+
+ private boolean mIsPointerDown;
FingerprintAuthenticationClient(@NonNull Context context,
@NonNull LazyDaemon<IBiometricsFingerprint> lazyDaemon, @NonNull IBinder token,
@@ -61,13 +65,27 @@
@NonNull TaskStackListener taskStackListener,
@NonNull LockoutFrameworkImpl lockoutTracker,
@Nullable IUdfpsOverlayController udfpsOverlayController,
- boolean allowBackgroundAuthentication) {
+ boolean allowBackgroundAuthentication,
+ @NonNull FingerprintSensorPropertiesInternal sensorProps) {
super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted,
owner, cookie, requireConfirmation, sensorId, isStrongBiometric,
BiometricsProtoEnums.MODALITY_FINGERPRINT, statsClient, taskStackListener,
lockoutTracker, allowBackgroundAuthentication, true /* shouldVibrate */);
mLockoutFrameworkImpl = lockoutTracker;
mUdfpsOverlayController = udfpsOverlayController;
+ mSensorProps = sensorProps;
+ }
+
+ @Override
+ public void start(@NonNull Callback callback) {
+ super.start(callback);
+
+ if (mSensorProps.isAnyUdfpsType()) {
+ // UDFPS requires user to touch before becoming "active"
+ mState = STATE_STARTED_PAUSED;
+ } else {
+ mState = STATE_STARTED;
+ }
}
@NonNull
@@ -87,10 +105,11 @@
// Note that authentication doesn't end when Authenticated == false
if (authenticated) {
+ mState = STATE_STOPPED;
resetFailedAttempts(getTargetUserId());
UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
- mCallback.onClientFinished(this, true /* success */);
} else {
+ mState = STATE_STARTED_PAUSED;
final @LockoutTracker.LockoutMode int lockoutMode =
mLockoutFrameworkImpl.getLockoutModeForUser(getTargetUserId());
if (lockoutMode != LockoutTracker.LOCKOUT_NONE) {
@@ -124,6 +143,13 @@
}
@Override
+ protected void handleLifecycleAfterAuth(boolean authenticated) {
+ if (authenticated) {
+ mCallback.onClientFinished(this, true /* success */);
+ }
+ }
+
+ @Override
public @LockoutTracker.LockoutMode int handleFailedAttempt(int userId) {
mLockoutFrameworkImpl.addFailedAttemptForUser(userId);
return super.handleFailedAttempt(userId);
@@ -160,6 +186,8 @@
@Override
public void onPointerDown(int x, int y, float minor, float major) {
+ mIsPointerDown = true;
+ mState = STATE_STARTED;
UdfpsHelper.onFingerDown(getFreshDaemon(), x, y, minor, major);
if (getListener() != null) {
try {
@@ -172,6 +200,8 @@
@Override
public void onPointerUp() {
+ mIsPointerDown = false;
+ mState = STATE_STARTED_PAUSED;
UdfpsHelper.onFingerUp(getFreshDaemon());
if (getListener() != null) {
try {
@@ -183,6 +213,11 @@
}
@Override
+ public boolean isPointerDown() {
+ return mIsPointerDown;
+ }
+
+ @Override
public void onUiReady() {
// Unsupported in HIDL.
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
index af1e49d..8e73ee6b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
@@ -49,6 +49,7 @@
private final boolean mIsStrongBiometric;
@Nullable private final IUdfpsOverlayController mUdfpsOverlayController;
+ private boolean mIsPointerDown;
public FingerprintDetectClient(@NonNull Context context,
@NonNull LazyDaemon<IBiometricsFingerprint> lazyDaemon, @NonNull IBinder token,
@@ -99,15 +100,22 @@
@Override
public void onPointerDown(int x, int y, float minor, float major) {
+ mIsPointerDown = true;
UdfpsHelper.onFingerDown(getFreshDaemon(), x, y, minor, major);
}
@Override
public void onPointerUp() {
+ mIsPointerDown = false;
UdfpsHelper.onFingerUp(getFreshDaemon());
}
@Override
+ public boolean isPointerDown() {
+ return mIsPointerDown;
+ }
+
+ @Override
public void onUiReady() {
// Unsupported in HIDL.
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
index eba445f..250e132 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
@@ -52,6 +52,7 @@
@Nullable private final IUdfpsOverlayController mUdfpsOverlayController;
@Nullable private final ISidefpsController mSidefpsController;
private final @FingerprintManager.EnrollReason int mEnrollReason;
+ private boolean mIsPointerDown;
FingerprintEnrollClient(@NonNull Context context,
@NonNull LazyDaemon<IBiometricsFingerprint> lazyDaemon, @NonNull IBinder token,
@@ -157,15 +158,22 @@
@Override
public void onPointerDown(int x, int y, float minor, float major) {
+ mIsPointerDown = true;
UdfpsHelper.onFingerDown(getFreshDaemon(), x, y, minor, major);
}
@Override
public void onPointerUp() {
+ mIsPointerDown = false;
UdfpsHelper.onFingerUp(getFreshDaemon());
}
@Override
+ public boolean isPointerDown() {
+ return mIsPointerDown;
+ }
+
+ @Override
public void onUiReady() {
// Unsupported in HIDL.
}
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index b6d65197..1108937 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -96,7 +96,6 @@
*/
final class DisplayPowerController implements AutomaticBrightnessController.Callbacks,
DisplayWhiteBalanceController.Callbacks {
- private static final String TAG = "DisplayPowerController";
private static final String SCREEN_ON_BLOCKED_TRACE_NAME = "Screen on blocked";
private static final String SCREEN_OFF_BLOCKED_TRACE_NAME = "Screen off blocked";
@@ -149,6 +148,8 @@
private static final int REPORTED_TO_POLICY_SCREEN_ON = 2;
private static final int REPORTED_TO_POLICY_SCREEN_TURNING_OFF = 3;
+ private final String TAG;
+
private final Object mLock = new Object();
private final Context mContext;
@@ -450,6 +451,7 @@
Runnable onBrightnessChangeRunnable) {
mLogicalDisplay = logicalDisplay;
mDisplayId = mLogicalDisplay.getDisplayIdLocked();
+ TAG = "DisplayPowerController[" + mDisplayId + "]";
mDisplayDevice = mLogicalDisplay.getPrimaryDisplayDeviceLocked();
mUniqueDisplayId = logicalDisplay.getPrimaryDisplayDeviceLocked().getUniqueId();
mHandler = new DisplayControllerHandler(handler.getLooper());
@@ -776,7 +778,7 @@
setUpAutoBrightness(mContext.getResources(), mHandler);
reloadReduceBrightColours();
mHbmController.resetHbmData(info.width, info.height, token,
- mDisplayDeviceConfig.getHighBrightnessModeData(), mBrightnessSetting);
+ mDisplayDeviceConfig.getHighBrightnessModeData());
}
private void sendUpdatePowerState() {
@@ -966,7 +968,6 @@
final boolean mustNotify;
final int previousPolicy;
boolean mustInitialize = false;
- boolean shouldSaveBrightnessInfo = true;
int brightnessAdjustmentFlags = 0;
mBrightnessReasonTemp.set(null);
synchronized (mLock) {
@@ -1097,7 +1098,6 @@
if (state == Display.STATE_OFF) {
brightnessState = PowerManager.BRIGHTNESS_OFF_FLOAT;
mBrightnessReasonTemp.setReason(BrightnessReason.REASON_SCREEN_OFF);
- shouldSaveBrightnessInfo = false;
}
// Always use the VR brightness when in the VR state.
@@ -1215,6 +1215,10 @@
brightnessAdjustmentFlags = 0;
}
} else {
+ // Any non-auto-brightness values such as override or temporary should still be subject
+ // to clamping so that they don't go beyond the current max as specified by HBM
+ // Controller.
+ brightnessState = clampScreenBrightness(brightnessState);
mAppliedAutoBrightness = false;
brightnessAdjustmentFlags = 0;
}
@@ -1222,9 +1226,8 @@
// Use default brightness when dozing unless overridden.
if ((Float.isNaN(brightnessState))
&& Display.isDozeState(state)) {
- brightnessState = mScreenBrightnessDozeConfig;
+ brightnessState = clampScreenBrightness(mScreenBrightnessDozeConfig);
mBrightnessReasonTemp.setReason(BrightnessReason.REASON_DOZE_DEFAULT);
- shouldSaveBrightnessInfo = false;
}
// Apply manual brightness.
@@ -1239,12 +1242,13 @@
mBrightnessReasonTemp.setReason(BrightnessReason.REASON_MANUAL);
}
- // Save out the brightness info now that the brightness state for this iteration has been
- // finalized and before we send out notifications about the brightness changing.
- if (shouldSaveBrightnessInfo) {
- saveBrightnessInfo(brightnessState);
-
- }
+ // The current brightness to use has been calculated at this point (minus the adjustments
+ // like low-power and dim), and HbmController should be notified so that it can accurately
+ // calculate HDR or HBM levels. We specifically do it here instead of having HbmController
+ // listen to the brightness setting because certain brightness sources (just as an app
+ // override) are not saved to the setting, but should be reflected in HBM
+ // calculations.
+ mHbmController.onBrightnessChanged(brightnessState);
if (updateScreenBrightnessSetting) {
// Tell the rest of the system about the new brightness in case we had to change it
@@ -1255,6 +1259,10 @@
putScreenBrightnessSetting(brightnessState, /* updateCurrent */ true);
}
+ // We save the brightness info *after* the brightness setting has been changed so that
+ // the brightness info reflects the latest value.
+ saveBrightnessInfo(getScreenBrightnessSetting());
+
// Apply dimming by at least some minimum amount when user activity
// timeout is about to expire.
if (mPowerRequest.policy == DisplayPowerRequest.POLICY_DIM) {
@@ -1531,7 +1539,7 @@
mHandler.post(mOnBrightnessChangeRunnable);
// TODO(b/192258832): Switch the HBMChangeCallback to a listener pattern.
mAutomaticBrightnessController.update();
- }, mContext, mBrightnessSetting);
+ }, mContext);
}
private void blockScreenOn() {
diff --git a/services/core/java/com/android/server/display/HighBrightnessModeController.java b/services/core/java/com/android/server/display/HighBrightnessModeController.java
index 645131c..2791f6a 100644
--- a/services/core/java/com/android/server/display/HighBrightnessModeController.java
+++ b/services/core/java/com/android/server/display/HighBrightnessModeController.java
@@ -37,7 +37,6 @@
import android.view.SurfaceControlHdrLayerInfoListener;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.display.BrightnessSetting.BrightnessSettingListener;
import com.android.server.display.DisplayDeviceConfig.HighBrightnessModeData;
import com.android.server.display.DisplayManagerService.Clock;
@@ -70,7 +69,6 @@
private final Context mContext;
private final SettingsObserver mSettingsObserver;
private final Injector mInjector;
- private final BrightnessSettingListener mBrightnessSettingListener = this::onBrightnessChanged;
private HdrListener mHdrListener;
private HighBrightnessModeData mHbmData;
@@ -86,7 +84,6 @@
private boolean mIsBlockedByLowPowerMode = false;
private int mWidth;
private int mHeight;
- private BrightnessSetting mBrightnessSetting;
private float mAmbientLux;
/**
@@ -103,30 +100,30 @@
HighBrightnessModeController(Handler handler, int width, int height, IBinder displayToken,
float brightnessMin, float brightnessMax, HighBrightnessModeData hbmData,
- Runnable hbmChangeCallback, Context context, BrightnessSetting brightnessSetting) {
+ Runnable hbmChangeCallback, Context context) {
this(new Injector(), handler, width, height, displayToken, brightnessMin, brightnessMax,
- hbmData, hbmChangeCallback, context, brightnessSetting);
+ hbmData, hbmChangeCallback, context);
}
@VisibleForTesting
HighBrightnessModeController(Injector injector, Handler handler, int width, int height,
IBinder displayToken, float brightnessMin, float brightnessMax,
HighBrightnessModeData hbmData, Runnable hbmChangeCallback,
- Context context, BrightnessSetting brightnessSetting) {
+ Context context) {
mInjector = injector;
mContext = context;
mClock = injector.getClock();
mHandler = handler;
+ mBrightness = brightnessMin;
mBrightnessMin = brightnessMin;
mBrightnessMax = brightnessMax;
- mBrightness = brightnessSetting.getBrightness();
mHbmChangeCallback = hbmChangeCallback;
mSkinThermalStatusObserver = new SkinThermalStatusObserver(mInjector, mHandler);
mSettingsObserver = new SettingsObserver(mHandler);
mRecalcRunnable = this::recalculateTimeAllowance;
mHdrListener = new HdrListener();
- resetHbmData(width, height, displayToken, hbmData, brightnessSetting);
+ resetHbmData(width, height, displayToken, hbmData);
}
void setAutoBrightnessEnabled(boolean isEnabled) {
@@ -185,7 +182,6 @@
}
}
- @VisibleForTesting
void onBrightnessChanged(float brightness) {
if (!deviceSupportsHbm()) {
return;
@@ -224,12 +220,11 @@
mSettingsObserver.stopObserving();
}
- void resetHbmData(int width, int height, IBinder displayToken, HighBrightnessModeData hbmData,
- BrightnessSetting brightnessSetting) {
+ void resetHbmData(int width, int height, IBinder displayToken, HighBrightnessModeData hbmData) {
mWidth = width;
mHeight = height;
mHbmData = hbmData;
- resetBrightnessSetting(brightnessSetting);
+
unregisterHdrListener();
mSkinThermalStatusObserver.stopObserving();
mSettingsObserver.stopObserving();
@@ -261,9 +256,12 @@
pw.println(" mBrightness=" + mBrightness);
pw.println(" mCurrentMin=" + getCurrentBrightnessMin());
pw.println(" mCurrentMax=" + getCurrentBrightnessMax());
- pw.println(" mHbmMode=" + BrightnessInfo.hbmToString(mHbmMode));
+ pw.println(" mHbmMode=" + BrightnessInfo.hbmToString(mHbmMode)
+ + (mHbmMode == BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR
+ ? "(" + getHdrBrightnessValue() + ")" : ""));
pw.println(" mHbmData=" + mHbmData);
- pw.println(" mAmbientLux=" + mAmbientLux);
+ pw.println(" mAmbientLux=" + mAmbientLux
+ + (mIsAutoBrightnessEnabled ? "" : " (old/invalid)"));
pw.println(" mIsInAllowedAmbientRange=" + mIsInAllowedAmbientRange);
pw.println(" mIsAutoBrightnessEnabled=" + mIsAutoBrightnessEnabled);
pw.println(" mIsHdrLayerPresent=" + mIsHdrLayerPresent);
@@ -301,16 +299,6 @@
return event.startTimeMillis;
}
- private void resetBrightnessSetting(BrightnessSetting brightnessSetting) {
- if (mBrightnessSetting != null) {
- mBrightnessSetting.unregisterListener(mBrightnessSettingListener);
- }
- mBrightnessSetting = brightnessSetting;
- if (mBrightnessSetting != null) {
- mBrightnessSetting.registerListener(mBrightnessSettingListener);
- }
- }
-
private boolean isCurrentlyAllowed() {
// Returns true if HBM is allowed (above the ambient lux threshold) and there's still
// time within the current window for additional HBM usage. We return false if there is an
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index de78bec..50d5b66 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -154,8 +154,8 @@
import com.android.internal.content.PackageMonitor;
import com.android.internal.inputmethod.CallbackUtils;
import com.android.internal.inputmethod.IBooleanResultCallback;
-import com.android.internal.inputmethod.IIInputContentUriTokenResultCallback;
import com.android.internal.inputmethod.IInputContentUriToken;
+import com.android.internal.inputmethod.IInputContentUriTokenResultCallback;
import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
import com.android.internal.inputmethod.IVoidResultCallback;
import com.android.internal.inputmethod.ImeTracing;
@@ -5831,7 +5831,7 @@
@BinderThread
@Override
public void createInputContentUriToken(Uri contentUri, String packageName,
- IIInputContentUriTokenResultCallback resultCallback) {
+ IInputContentUriTokenResultCallback resultCallback) {
CallbackUtils.onResult(resultCallback,
() -> mImms.createInputContentUriToken(mToken, contentUri, packageName));
}
diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
index b61c6a7..f2ccf9f 100644
--- a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
+++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
@@ -44,8 +44,11 @@
import android.content.pm.PackageUserState;
import android.content.pm.ParceledListSlice;
import android.content.pm.Signature;
+import android.content.pm.SigningDetails;
import android.content.pm.SigningInfo;
import android.content.pm.parsing.ParsingPackageUtils;
+import android.content.pm.parsing.result.ParseResult;
+import android.content.pm.parsing.result.ParseTypeImpl;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
@@ -580,8 +583,14 @@
int flags = PackageManager.GET_SIGNING_CERTIFICATES | PackageManager.GET_META_DATA;
// APK signatures is already verified elsewhere in PackageManager. We do not need to
// verify it again since it could cause a timeout for large APKs.
- pkg.setSigningDetails(
- ParsingPackageUtils.getSigningDetails(pkg, /* skipVerify= */ true));
+ final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
+ final ParseResult<SigningDetails> result = ParsingPackageUtils.getSigningDetails(
+ input, pkg, /* skipVerify= */ true);
+ if (result.isError()) {
+ Slog.w(TAG, result.getErrorMessage(), result.getException());
+ return null;
+ }
+ pkg.setSigningDetails(result.getResult());
return PackageInfoUtils.generate(
pkg,
null,
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 49d061c..fab11a1 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -2485,6 +2485,7 @@
private void removeUser(int userId, boolean unknownUser) {
Slog.i(TAG, "RemoveUser: " + userId);
+ removeBiometricsForUser(userId);
mSpManager.removeUser(userId);
mStrongAuth.removeUser(userId);
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 491cd18..9aaa577 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -1302,6 +1302,10 @@
@Override
public void addSessionsListener(IActiveSessionsListener listener,
ComponentName componentName, int userId) throws RemoteException {
+ if (listener == null) {
+ Log.w(TAG, "addSessionsListener: listener is null, ignoring");
+ return;
+ }
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
final long token = Binder.clearCallingIdentity();
@@ -1348,6 +1352,10 @@
@Override
public void addSession2TokensListener(ISession2TokensListener listener,
int userId) {
+ if (listener == null) {
+ Log.w(TAG, "addSession2TokensListener: listener is null, ignoring");
+ return;
+ }
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
final long token = Binder.clearCallingIdentity();
@@ -1358,7 +1366,8 @@
synchronized (mLock) {
int index = findIndexOfSession2TokensListenerLocked(listener);
if (index >= 0) {
- Log.w(TAG, "addSession2TokensListener is already added, ignoring");
+ Log.w(TAG, "addSession2TokensListener: "
+ + "listener is already added, ignoring");
return;
}
mSession2TokensListenerRecords.add(
@@ -1515,6 +1524,10 @@
@Override
public void addOnMediaKeyEventDispatchedListener(
final IOnMediaKeyEventDispatchedListener listener) {
+ if (listener == null) {
+ Log.w(TAG, "addOnMediaKeyEventDispatchedListener: listener is null, ignoring");
+ return;
+ }
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier();
@@ -1543,6 +1556,10 @@
@Override
public void removeOnMediaKeyEventDispatchedListener(
final IOnMediaKeyEventDispatchedListener listener) {
+ if (listener == null) {
+ Log.w(TAG, "removeOnMediaKeyEventDispatchedListener: listener is null, ignoring");
+ return;
+ }
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier();
@@ -1571,6 +1588,10 @@
@Override
public void addOnMediaKeyEventSessionChangedListener(
final IOnMediaKeyEventSessionChangedListener listener) {
+ if (listener == null) {
+ Log.w(TAG, "addOnMediaKeyEventSessionChangedListener: lister is null, ignoring");
+ return;
+ }
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier();
@@ -1599,6 +1620,10 @@
@Override
public void removeOnMediaKeyEventSessionChangedListener(
final IOnMediaKeyEventSessionChangedListener listener) {
+ if (listener == null) {
+ Log.w(TAG, "removeOnMediaKeyEventSessionChangedListener: lister is null, ignoring");
+ return;
+ }
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier();
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index c0a378a6..6ae4dd0 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -31,10 +31,11 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
-import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.SigningDetails;
import android.content.pm.parsing.PackageInfoWithoutStateUtils;
import android.content.pm.parsing.ParsingPackageUtils;
+import android.content.pm.parsing.result.ParseResult;
+import android.content.pm.parsing.result.ParseTypeImpl;
import android.os.Binder;
import android.os.Environment;
import android.os.RemoteException;
@@ -583,8 +584,8 @@
}
factoryPackagesSet.add(packageInfo.packageName);
}
- } else if (throwable instanceof PackageParserException) {
- final PackageParserException e = (PackageParserException) throwable;
+ } else if (throwable instanceof PackageManagerException) {
+ final PackageManagerException e = (PackageManagerException) throwable;
// Skip parsing non-coreApp apex file if system is in minimal boot state.
if (e.error == PackageManager.INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED) {
Slog.w(TAG, "Scan apex failed, not a coreApp:" + ai.modulePath);
@@ -988,15 +989,17 @@
}
private SigningDetails getSigningDetails(PackageInfo pkg) throws PackageManagerException {
- int minSignatureScheme =
+ final int minSignatureScheme =
ApkSignatureVerifier.getMinimumSignatureSchemeVersionForTargetSdk(
pkg.applicationInfo.targetSdkVersion);
- try {
- return ApkSignatureVerifier.verify(pkg.applicationInfo.sourceDir,
- minSignatureScheme);
- } catch (PackageParserException e) {
- throw PackageManagerException.from(e);
+ final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
+ final ParseResult<SigningDetails> result = ApkSignatureVerifier.verify(
+ input, pkg.applicationInfo.sourceDir, minSignatureScheme);
+ if (result.isError()) {
+ throw new PackageManagerException(result.getErrorCode(), result.getErrorMessage(),
+ result.getException());
}
+ return result.getResult();
}
private void checkApexSignature(PackageInfo existingApexPkg, PackageInfo newApexPkg)
diff --git a/services/core/java/com/android/server/pm/ApkChecksums.java b/services/core/java/com/android/server/pm/ApkChecksums.java
index e0f1065..a44cad8 100644
--- a/services/core/java/com/android/server/pm/ApkChecksums.java
+++ b/services/core/java/com/android/server/pm/ApkChecksums.java
@@ -35,10 +35,11 @@
import android.content.pm.Checksum;
import android.content.pm.IOnChecksumsReadyListener;
import android.content.pm.PackageManagerInternal;
-import android.content.pm.PackageParser;
import android.content.pm.Signature;
import android.content.pm.SigningDetails.SignatureSchemeVersion;
import android.content.pm.parsing.ApkLiteParseUtils;
+import android.content.pm.parsing.result.ParseResult;
+import android.content.pm.parsing.result.ParseTypeImpl;
import android.os.Handler;
import android.os.RemoteException;
import android.os.SystemClock;
@@ -663,13 +664,16 @@
private static Map<Integer, ApkChecksum> extractHashFromV2V3Signature(
String split, String filePath, int types) {
Map<Integer, byte[]> contentDigests = null;
- try {
- contentDigests = ApkSignatureVerifier.verifySignaturesInternal(filePath,
- SignatureSchemeVersion.SIGNING_BLOCK_V2, /* verifyFull */ false).contentDigests;
- } catch (PackageParser.PackageParserException e) {
- if (!(e.getCause() instanceof SignatureNotFoundException)) {
- Slog.e(TAG, "Signature verification error", e);
+ final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
+ final ParseResult<ApkSignatureVerifier.SigningDetailsWithDigests> result =
+ ApkSignatureVerifier.verifySignaturesInternal(input, filePath,
+ SignatureSchemeVersion.SIGNING_BLOCK_V2, false /*verifyFull*/);
+ if (result.isError()) {
+ if (!(result.getException() instanceof SignatureNotFoundException)) {
+ Slog.e(TAG, "Signature verification error", result.getException());
}
+ } else {
+ contentDigests = result.getResult().contentDigests;
}
if (contentDigests == null) {
diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java
index affacbb..d4ebbe3 100644
--- a/services/core/java/com/android/server/pm/InstantAppRegistry.java
+++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java
@@ -23,6 +23,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.InstantAppInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.PermissionInfo;
import android.content.pm.SigningDetails;
import android.graphics.Bitmap;
@@ -123,6 +124,7 @@
private final PackageManagerService mService;
private final PermissionManagerServiceInternal mPermissionManager;
private final CookiePersistence mCookiePersistence;
+ private final PackageManagerInternal mPmInternal;
/** State for uninstalled instant apps */
@Watched
@@ -191,9 +193,11 @@
}
public InstantAppRegistry(PackageManagerService service,
- PermissionManagerServiceInternal permissionManager) {
+ PermissionManagerServiceInternal permissionManager,
+ PackageManagerInternal pmInternal) {
mService = service;
mPermissionManager = permissionManager;
+ mPmInternal = pmInternal;
mCookiePersistence = new CookiePersistence(BackgroundThread.getHandler().getLooper());
mUninstalledInstantApps = new WatchedSparseArray<List<UninstalledInstantAppState>>();
@@ -214,6 +218,7 @@
private InstantAppRegistry(InstantAppRegistry r) {
mService = r.mService;
mPermissionManager = r.mPermissionManager;
+ mPmInternal = r.mPmInternal;
mCookiePersistence = null;
mUninstalledInstantApps = new WatchedSparseArray<List<UninstalledInstantAppState>>(
@@ -366,7 +371,7 @@
@GuardedBy("mService.mLock")
public void onPackageInstalledLPw(@NonNull AndroidPackage pkg, @NonNull int[] userIds) {
- PackageSetting ps = mService.getPackageSetting(pkg.getPackageName());
+ PackageSetting ps = mPmInternal.getPackageSetting(pkg.getPackageName());
if (ps == null) {
return;
}
@@ -784,7 +789,7 @@
final int packageCount = mService.mPackages.size();
for (int i = 0; i < packageCount; i++) {
final AndroidPackage pkg = mService.mPackages.valueAt(i);
- final PackageSetting ps = mService.getPackageSetting(pkg.getPackageName());
+ final PackageSetting ps = mPmInternal.getPackageSetting(pkg.getPackageName());
if (ps == null) {
continue;
}
@@ -824,13 +829,13 @@
} else if (rhsPkg == null) {
return 1;
} else {
- final PackageSetting lhsPs = mService.getPackageSetting(
+ final PackageSetting lhsPs = mPmInternal.getPackageSetting(
lhsPkg.getPackageName());
if (lhsPs == null) {
return 0;
}
- final PackageSetting rhsPs = mService.getPackageSetting(
+ final PackageSetting rhsPs = mPmInternal.getPackageSetting(
rhsPkg.getPackageName());
if (rhsPs == null) {
return 0;
@@ -918,7 +923,7 @@
final int packageCount = mService.mPackages.size();
for (int i = 0; i < packageCount; i++) {
final AndroidPackage pkg = mService.mPackages.valueAt(i);
- final PackageSetting ps = mService.getPackageSetting(pkg.getPackageName());
+ final PackageSetting ps = mPmInternal.getPackageSetting(pkg.getPackageName());
if (ps == null || !ps.getInstantApp(userId)) {
continue;
}
@@ -940,7 +945,7 @@
InstantAppInfo createInstantAppInfoForPackage(
@NonNull AndroidPackage pkg, @UserIdInt int userId,
boolean addApplicationInfo) {
- PackageSetting ps = mService.getPackageSetting(pkg.getPackageName());
+ PackageSetting ps = mPmInternal.getPackageSetting(pkg.getPackageName());
if (ps == null) {
return null;
}
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index d6400f3..f968daf 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -23,6 +23,7 @@
import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.IOtaDexopt;
+import android.content.pm.PackageManagerInternal;
import android.os.Environment;
import android.os.RemoteException;
import android.os.ResultReceiver;
@@ -33,6 +34,7 @@
import android.util.Slog;
import com.android.internal.logging.MetricsLogger;
+import com.android.server.LocalServices;
import com.android.server.pm.Installer.InstallerException;
import com.android.server.pm.dex.DexoptOptions;
import com.android.server.pm.parsing.pkg.AndroidPackage;
@@ -41,7 +43,6 @@
import java.io.File;
import java.io.FileDescriptor;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
@@ -371,8 +372,10 @@
return;
}
- // Look into all packages.
- Collection<AndroidPackage> pkgs = mPackageManagerService.getPackages();
+ // Make a copy of all packages and look into each package.
+ final PackageManagerInternal pmInt = LocalServices.getService(PackageManagerInternal.class);
+ final ArrayList<AndroidPackage> pkgs = new ArrayList<>();
+ pmInt.forEachPackage(pkgs::add);
int packagePaths = 0;
int pathsSuccessful = 0;
for (AndroidPackage pkg : pkgs) {
@@ -398,7 +401,7 @@
continue;
}
- PackageSetting pkgSetting = mPackageManagerService.getPackageSetting(pkg.getPackageName());
+ PackageSetting pkgSetting = pmInt.getPackageSetting(pkg.getPackageName());
final String[] instructionSets = getAppDexInstructionSets(
AndroidPackageUtils.getPrimaryCpuAbi(pkg, pkgSetting),
AndroidPackageUtils.getSecondaryCpuAbi(pkg, pkgSetting));
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index e605652..ed6823f 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -84,7 +84,6 @@
import android.content.pm.PackageInstaller.SessionParams;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
-import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.SigningDetails;
import android.content.pm.dex.DexMetadataHelper;
import android.content.pm.parsing.ApkLite;
@@ -2213,7 +2212,6 @@
@Override
public void transfer(String packageName) {
Preconditions.checkArgument(!TextUtils.isEmpty(packageName));
-
ApplicationInfo newOwnerAppInfo = mPm.getApplicationInfo(packageName, 0, userId);
if (newOwnerAppInfo == null) {
throw new ParcelableException(new PackageManager.NameNotFoundException(packageName));
@@ -2333,12 +2331,29 @@
(params.installFlags & PackageManager.INSTALL_DISABLE_ALLOWED_APEX_UPDATE_CHECK)
== 0;
synchronized (mLock) {
- if (checkApexUpdateAllowed && !isApexUpdateAllowed(mPackageName)) {
+ if (checkApexUpdateAllowed && !isApexUpdateAllowed(mPackageName,
+ mInstallSource.installerPackageName)) {
onSessionValidationFailure(PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
- "Update of APEX package " + mPackageName + " is not allowed");
+ "Update of APEX package " + mPackageName + " is not allowed for "
+ + mInstallSource.installerPackageName);
return;
}
}
+
+ if (!params.isStaged) {
+ // For non-staged APEX installs also check if there is a staged session that
+ // contains the same APEX. If that's the case, we should fail this session.
+ synchronized (mLock) {
+ int sessionId = mStagingManager.getSessionIdByPackageName(mPackageName);
+ if (sessionId != -1) {
+ onSessionValidationFailure(
+ PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
+ "Staged session " + sessionId + " already contains "
+ + mPackageName);
+ return;
+ }
+ }
+ }
}
if (params.isStaged) {
@@ -2763,7 +2778,8 @@
}
private long getApksSize(String packageName) {
- final PackageSetting ps = mPm.getPackageSetting(packageName);
+ final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
+ final PackageSetting ps = pmi.getPackageSetting(packageName);
if (ps == null) {
return 0;
}
@@ -2825,9 +2841,23 @@
return sessionContains((s) -> !s.isApexSession());
}
- private boolean isApexUpdateAllowed(String apexPackageName) {
- return mPm.getModuleInfo(apexPackageName, 0) != null
- || SystemConfig.getInstance().getAllowedVendorApexes().contains(apexPackageName);
+ private boolean isApexUpdateAllowed(String apexPackageName, String installerPackageName) {
+ if (mPm.getModuleInfo(apexPackageName, 0) != null) {
+ final String modulesInstaller =
+ SystemConfig.getInstance().getModulesInstallerPackageName();
+ if (modulesInstaller == null) {
+ Slog.w(TAG, "No modules installer defined");
+ return false;
+ }
+ return modulesInstaller.equals(installerPackageName);
+ }
+ final String vendorApexInstaller =
+ SystemConfig.getInstance().getAllowedVendorApexes().get(apexPackageName);
+ if (vendorApexInstaller == null) {
+ Slog.w(TAG, apexPackageName + " is not allowed to be updated");
+ return false;
+ }
+ return vendorApexInstaller.equals(installerPackageName);
}
/**
@@ -3431,13 +3461,15 @@
private SigningDetails unsafeGetCertsWithoutVerification(String path)
throws PackageManagerException {
- try {
- return ApkSignatureVerifier.unsafeGetCertsWithoutVerification(path,
- SigningDetails.SignatureSchemeVersion.JAR);
- } catch (PackageParserException e) {
+ final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
+ final ParseResult<SigningDetails> result =
+ ApkSignatureVerifier.unsafeGetCertsWithoutVerification(
+ input, path, SigningDetails.SignatureSchemeVersion.JAR);
+ if (result.isError()) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
"Couldn't obtain signatures from APK : " + path);
}
+ return result.getResult();
}
/**
diff --git a/services/core/java/com/android/server/pm/PackageManagerException.java b/services/core/java/com/android/server/pm/PackageManagerException.java
index 0793b09..4662389 100644
--- a/services/core/java/com/android/server/pm/PackageManagerException.java
+++ b/services/core/java/com/android/server/pm/PackageManagerException.java
@@ -17,7 +17,6 @@
package com.android.server.pm;
import android.content.pm.PackageManager;
-import android.content.pm.PackageParser.PackageParserException;
import com.android.server.pm.Installer.InstallerException;
@@ -45,11 +44,6 @@
this.error = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
}
- public static PackageManagerException from(PackageParserException e)
- throws PackageManagerException {
- throw new PackageManagerException(e.error, e.getMessage(), e.getCause());
- }
-
public static PackageManagerException from(InstallerException e)
throws PackageManagerException {
throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 9085e49..4fa602f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -132,6 +132,7 @@
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;
@@ -211,7 +212,6 @@
import android.content.pm.PackageManagerInternal.PackageListObserver;
import android.content.pm.PackageManagerInternal.PrivateResolveFlags;
import android.content.pm.PackageParser;
-import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.PackagePartitions;
import android.content.pm.PackagePartitions.SystemPartition;
import android.content.pm.PackageStats;
@@ -4407,11 +4407,11 @@
// reader
final AndroidPackage p = mPackages.get(packageName);
if (p != null && AndroidPackageUtils.isMatchForSystemOnly(p, flags)) {
- PackageSetting ps = getPackageSettingInternal(p.getPackageName(), callingUid);
- if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
- return -1;
+ final PackageSetting ps = getPackageSettingInternal(p.getPackageName(), callingUid);
+ if (ps != null && ps.getInstalled(userId)
+ && !shouldFilterApplicationLocked(ps, callingUid, userId)) {
+ return UserHandle.getUid(userId, p.getUid());
}
- return UserHandle.getUid(userId, p.getUid());
}
if ((flags & MATCH_KNOWN_PACKAGES) != 0) {
final PackageSetting ps = mSettings.getPackageLPr(packageName);
@@ -5966,7 +5966,8 @@
final VerificationParams params = state.getVerificationParams();
final Uri originUri = Uri.fromFile(params.origin.resolvedFile);
- Slog.i(TAG, "Verification timed out for " + originUri);
+ String errorMsg = "Verification timed out for " + originUri;
+ Slog.i(TAG, errorMsg);
final UserHandle user = params.getUser();
if (getDefaultVerificationResponse(user)
@@ -5982,7 +5983,7 @@
PackageManager.VERIFICATION_REJECT, null,
params.mDataLoaderType, user);
params.setReturnCode(
- PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE);
+ PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE, errorMsg);
state.setVerifierResponse(Binder.getCallingUid(),
PackageManager.VERIFICATION_REJECT);
}
@@ -6007,7 +6008,8 @@
final VerificationParams params = state.getVerificationParams();
final Uri originUri = Uri.fromFile(params.origin.resolvedFile);
- Slog.i(TAG, "Integrity verification timed out for " + originUri);
+ String errorMsg = "Integrity verification timed out for " + originUri;
+ Slog.i(TAG, errorMsg);
state.setIntegrityVerificationResult(
getDefaultIntegrityVerificationResponse());
@@ -6017,7 +6019,8 @@
Slog.i(TAG, "Integrity check times out, continuing with " + originUri);
} else {
params.setReturnCode(
- PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE);
+ PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
+ errorMsg);
}
if (state.areAllVerificationsComplete()) {
@@ -6057,7 +6060,8 @@
response.code, null, params.mDataLoaderType, params.getUser());
} else {
params.setReturnCode(
- PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE);
+ PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
+ "Install not allowed");
}
if (state.areAllVerificationsComplete()) {
@@ -6092,7 +6096,8 @@
Slog.i(TAG, "Integrity check passed for " + originUri);
} else {
params.setReturnCode(
- PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE);
+ PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
+ "Integrity check failed for " + originUri);
}
if (state.areAllVerificationsComplete()) {
@@ -7179,7 +7184,7 @@
}
}
- mInstantAppRegistry = new InstantAppRegistry(this, mPermissionManager);
+ mInstantAppRegistry = new InstantAppRegistry(this, mPermissionManager, mPmInternal);
mDirsToScanAsSystem = new ArrayList<>();
mDirsToScanAsSystem.addAll(injector.getSystemPartitions());
@@ -7975,7 +7980,7 @@
private boolean enableCompressedPackage(AndroidPackage stubPkg,
@NonNull PackageSetting stubPkgSetting) {
final int parseFlags = mDefParseFlags | ParsingPackageUtils.PARSE_CHATTY
- | PackageParser.PARSE_ENFORCE_CODE;
+ | ParsingPackageUtils.PARSE_ENFORCE_CODE;
synchronized (mInstallLock) {
final AndroidPackage pkg;
try (PackageFreezer freezer =
@@ -8634,7 +8639,7 @@
if (ps != null) {
final PackageUserState state = ps.readUserState(userId);
if (state != null) {
- return PackageParser.isAvailable(state);
+ return checkUseInstalledOrHidden(p, ps, state, 0 /*flags*/);
}
}
}
@@ -8799,13 +8804,11 @@
synchronized (mLock) {
final AndroidPackage p = mPackages.get(packageName);
if (p != null && AndroidPackageUtils.isMatchForSystemOnly(p, flags)) {
- PackageSetting ps = getPackageSetting(p.getPackageName());
- if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
- return null;
+ final PackageSetting ps = getPackageSetting(p.getPackageName());
+ if (ps != null && ps.getInstalled(userId)
+ && !shouldFilterApplicationLocked(ps, callingUid, userId)) {
+ return mPermissionManager.getGidsForUid(UserHandle.getUid(userId, ps.appId));
}
- // TODO: Shouldn't this be checking for package installed state for userId and
- // return null?
- return mPermissionManager.getGidsForUid(UserHandle.getUid(userId, ps.appId));
}
if ((flags & MATCH_KNOWN_PACKAGES) != 0) {
final PackageSetting ps = mSettings.getPackageLPr(packageName);
@@ -10057,24 +10060,26 @@
@Override
public int getUidForSharedUser(String sharedUserName) {
- if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
- return -1;
- }
if (sharedUserName == null) {
- return -1;
+ return Process.INVALID_UID;
+ }
+ final int callingUid = Binder.getCallingUid();
+ if (getInstantAppPackageName(callingUid) != null) {
+ return Process.INVALID_UID;
}
// reader
synchronized (mLock) {
- SharedUserSetting suid;
try {
- suid = mSettings.getSharedUserLPw(sharedUserName, 0, 0, false);
- if (suid != null) {
+ final SharedUserSetting suid = mSettings.getSharedUserLPw(sharedUserName,
+ 0 /* pkgFlags */, 0 /* pkgPrivateFlags */, false /* create */);
+ if (suid != null && !shouldFilterApplicationLocked(suid, callingUid,
+ UserHandle.getUserId(callingUid))) {
return suid.userId;
}
} catch (PackageManagerException ignore) {
// can't happen, but, still need to catch it
}
- return -1;
+ return Process.INVALID_UID;
}
}
@@ -11896,9 +11901,8 @@
errorMsg = "Failed to scan " + parseResult.scanFile + ": " + e.getMessage();
Slog.w(TAG, errorMsg);
}
- } else if (throwable instanceof PackageParserException) {
- PackageParserException e = (PackageParserException)
- throwable;
+ } else if (throwable instanceof PackageManagerException) {
+ PackageManagerException e = (PackageManagerException) throwable;
errorCode = e.error;
errorMsg = "Failed to parse " + parseResult.scanFile + ": " + e.getMessage();
Slog.w(TAG, errorMsg);
@@ -11958,10 +11962,14 @@
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
- parsedPackage.setSigningDetails(
- ParsingPackageUtils.getSigningDetails(parsedPackage, skipVerify));
- } catch (PackageParserException e) {
- throw PackageManagerException.from(e);
+ final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
+ final ParseResult<SigningDetails> result = ParsingPackageUtils.getSigningDetails(
+ input, parsedPackage, skipVerify);
+ if (result.isError()) {
+ throw new PackageManagerException(
+ result.getErrorCode(), result.getErrorMessage(), result.getException());
+ }
+ parsedPackage.setSigningDetails(result.getResult());
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
@@ -12018,8 +12026,6 @@
final ParsedPackage parsedPackage;
try (PackageParser2 pp = mInjector.getScanningPackageParser()) {
parsedPackage = pp.parsePackage(scanFile, parseFlags, false);
- } catch (PackageParserException e) {
- throw PackageManagerException.from(e);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
@@ -12488,6 +12494,7 @@
}
}
builder.append(" to access user ");
+ builder.append(userId);
builder.append(".");
return builder.toString();
}
@@ -18036,8 +18043,9 @@
// state can change within this delay and hence we need to re-verify certain conditions.
boolean isStaged = (installFlags & INSTALL_STAGED) != 0;
if (isStaged) {
- mRet = verifyReplacingVersionCode(
+ Pair<Integer, String> ret = verifyReplacingVersionCode(
pkgLite, requiredInstalledVersionCode, installFlags);
+ mRet = ret.first;
if (mRet != INSTALL_SUCCEEDED) {
return;
}
@@ -18118,17 +18126,20 @@
return;
}
int completeStatus = PackageManager.INSTALL_SUCCEEDED;
- for (Integer status : mVerificationState.values()) {
+ String errorMsg = null;
+ for (VerificationParams params : mVerificationState.keySet()) {
+ int status = params.mRet;
if (status == PackageManager.INSTALL_UNKNOWN) {
return;
} else if (status != PackageManager.INSTALL_SUCCEEDED) {
completeStatus = status;
+ errorMsg = params.mErrorMessage;
break;
}
}
try {
mObserver.onPackageInstalled(null, completeStatus,
- "Package Verification Result", new Bundle());
+ errorMsg, new Bundle());
} catch (RemoteException e) {
Slog.i(TAG, "Observer no longer exists.");
}
@@ -18151,7 +18162,8 @@
private boolean mWaitForVerificationToComplete;
private boolean mWaitForIntegrityVerificationToComplete;
private boolean mWaitForEnableRollbackToComplete;
- private int mRet;
+ private int mRet = PackageManager.INSTALL_SUCCEEDED;
+ private String mErrorMessage = null;
final PackageLite mPackageLite;
@@ -18188,7 +18200,9 @@
PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
mPackageLite, origin.resolvedPath, installFlags, packageAbiOverride);
- mRet = verifyReplacingVersionCode(pkgLite, requiredInstalledVersionCode, installFlags);
+ Pair<Integer, String> ret = verifyReplacingVersionCode(
+ pkgLite, requiredInstalledVersionCode, installFlags);
+ setReturnCode(ret.first, ret.second);
if (mRet != INSTALL_SUCCEEDED) {
return;
}
@@ -18214,7 +18228,7 @@
mPendingVerification.append(verificationId, verificationState);
sendIntegrityVerificationRequest(verificationId, pkgLite, verificationState);
- mRet = sendPackageVerificationRequest(
+ sendPackageVerificationRequest(
verificationId, pkgLite, verificationState);
// If both verifications are skipped, we should remove the state.
@@ -18326,14 +18340,12 @@
}
/**
- * Send a request to verifier(s) to verify the package if necessary, and return
- * {@link PackageManager#INSTALL_SUCCEEDED} if succeeded.
+ * Send a request to verifier(s) to verify the package if necessary.
*/
- int sendPackageVerificationRequest(
+ void sendPackageVerificationRequest(
int verificationId,
PackageInfoLite pkgLite,
PackageVerificationState verificationState) {
- int ret = INSTALL_SUCCEEDED;
// TODO: http://b/22976637
// Apps installed for "all" users use the device owner to verify the app
@@ -18416,8 +18428,9 @@
if (sufficientVerifiers != null) {
final int n = sufficientVerifiers.size();
if (n == 0) {
- Slog.i(TAG, "Additional verifiers required, but none installed.");
- ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;
+ String errorMsg = "Additional verifiers required, but none installed.";
+ Slog.i(TAG, errorMsg);
+ setReturnCode(PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE, errorMsg);
} else {
for (int i = 0; i < n; i++) {
final ComponentName verifierComponent = sufficientVerifiers.get(i);
@@ -18475,7 +18488,6 @@
verificationState.setVerifierResponse(
requiredUid, PackageManager.VERIFICATION_ALLOW);
}
- return ret;
}
void populateInstallerExtras(Intent intent) {
@@ -18502,11 +18514,12 @@
}
}
- void setReturnCode(int ret) {
+ void setReturnCode(int ret, String message) {
if (mRet == PackageManager.INSTALL_SUCCEEDED) {
// Only update mRet if it was previously INSTALL_SUCCEEDED to
// ensure we do not overwrite any previous failure results.
mRet = ret;
+ mErrorMessage = message;
}
}
@@ -18542,7 +18555,7 @@
mParentVerificationParams.trySendVerificationCompleteNotification(this, mRet);
} else {
try {
- observer.onPackageInstalled(null, mRet, "Package Verification Result",
+ observer.onPackageInstalled(null, mRet, mErrorMessage,
new Bundle());
} catch (RemoteException e) {
Slog.i(TAG, "Observer no longer exists.");
@@ -18825,12 +18838,12 @@
// Reflect the rename in scanned details
try {
- parsedPackage.setCodePath(afterCodeFile.getCanonicalPath());
+ parsedPackage.setPath(afterCodeFile.getCanonicalPath());
} catch (IOException e) {
Slog.e(TAG, "Failed to get path: " + afterCodeFile, e);
return false;
}
- parsedPackage.setBaseCodePath(FileUtils.rewriteAfterRename(beforeCodeFile,
+ parsedPackage.setBaseApkPath(FileUtils.rewriteAfterRename(beforeCodeFile,
afterCodeFile, parsedPackage.getBaseApkPath()));
parsedPackage.setSplitCodePaths(FileUtils.rewriteAfterRename(beforeCodeFile,
afterCodeFile, parsedPackage.getSplitCodePaths()));
@@ -19040,12 +19053,6 @@
Slog.w(TAG, msg);
}
- public void setError(String msg, PackageParserException e) {
- setReturnCode(e.error);
- setReturnMessage(ExceptionUtils.getCompleteMessage(msg, e));
- Slog.w(TAG, msg, e);
- }
-
public void setError(String msg, PackageManagerException e) {
returnCode = e.error;
setReturnMessage(ExceptionUtils.getCompleteMessage(msg, e));
@@ -20370,9 +20377,7 @@
}
PrepareFailure(String message, Exception e) {
- super(e instanceof PackageParserException
- ? ((PackageParserException) e).error
- : ((PackageManagerException) e).error,
+ super(((PackageManagerException) e).error,
ExceptionUtils.getCompleteMessage(message, e));
}
@@ -20485,7 +20490,7 @@
try (PackageParser2 pp = mInjector.getPreparingPackageParser()) {
parsedPackage = pp.parsePackage(tmpPackageFile, parseFlags, false);
AndroidPackageUtils.validatePackageDexMetadata(parsedPackage);
- } catch (PackageParserException e) {
+ } catch (PackageManagerException e) {
throw new PrepareFailure("Failed parse during installPackageLI", e);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
@@ -20526,16 +20531,18 @@
}
}
- try {
- // either use what we've been given or parse directly from the APK
- if (args.signingDetails != SigningDetails.UNKNOWN) {
- parsedPackage.setSigningDetails(args.signingDetails);
- } else {
- parsedPackage.setSigningDetails(ParsingPackageUtils.getSigningDetails(
- parsedPackage, false /* skipVerify */));
+ // either use what we've been given or parse directly from the APK
+ if (args.signingDetails != SigningDetails.UNKNOWN) {
+ parsedPackage.setSigningDetails(args.signingDetails);
+ } else {
+ final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
+ final ParseResult<SigningDetails> result = ParsingPackageUtils.getSigningDetails(
+ input, parsedPackage, false /*skipVerify*/);
+ if (result.isError()) {
+ throw new PrepareFailure("Failed collect during installPackageLI",
+ result.getException());
}
- } catch (PackageParserException e) {
- throw new PrepareFailure("Failed collect during installPackageLI", e);
+ parsedPackage.setSigningDetails(result.getResult());
}
if (instantApp && parsedPackage.getSigningDetails().getSignatureSchemeVersion()
@@ -26728,7 +26735,7 @@
}
}
- private int verifyReplacingVersionCode(PackageInfoLite pkgLite,
+ private Pair<Integer, String> verifyReplacingVersionCode(PackageInfoLite pkgLite,
long requiredInstalledVersionCode, int installFlags) {
if ((installFlags & PackageManager.INSTALL_APEX) != 0) {
return verifyReplacingVersionCodeForApex(
@@ -26751,18 +26758,22 @@
if (requiredInstalledVersionCode != PackageManager.VERSION_CODE_HIGHEST) {
if (dataOwnerPkg == null) {
- Slog.w(TAG, "Required installed version code was "
+ String errorMsg = "Required installed version code was "
+ requiredInstalledVersionCode
- + " but package is not installed");
- return PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION;
+ + " but package is not installed";
+ Slog.w(TAG, errorMsg);
+ return Pair.create(
+ PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION, errorMsg);
}
if (dataOwnerPkg.getLongVersionCode() != requiredInstalledVersionCode) {
- Slog.w(TAG, "Required installed version code was "
+ String errorMsg = "Required installed version code was "
+ requiredInstalledVersionCode
+ " but actual installed version is "
- + dataOwnerPkg.getLongVersionCode());
- return PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION;
+ + dataOwnerPkg.getLongVersionCode();
+ Slog.w(TAG, errorMsg);
+ return Pair.create(
+ PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION, errorMsg);
}
}
@@ -26772,33 +26783,37 @@
try {
checkDowngrade(dataOwnerPkg, pkgLite);
} catch (PackageManagerException e) {
- Slog.w(TAG, "Downgrade detected: " + e.getMessage());
- return PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
+ String errorMsg = "Downgrade detected: " + e.getMessage();
+ Slog.w(TAG, errorMsg);
+ return Pair.create(
+ PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE, errorMsg);
}
}
}
}
- return PackageManager.INSTALL_SUCCEEDED;
+ return Pair.create(PackageManager.INSTALL_SUCCEEDED, null);
}
- private int verifyReplacingVersionCodeForApex(PackageInfoLite pkgLite,
+ private Pair<Integer, String> verifyReplacingVersionCodeForApex(PackageInfoLite pkgLite,
long requiredInstalledVersionCode, int installFlags) {
String packageName = pkgLite.packageName;
final PackageInfo activePackage = mApexManager.getPackageInfo(packageName,
ApexManager.MATCH_ACTIVE_PACKAGE);
if (activePackage == null) {
- Slog.w(TAG, "Attempting to install new APEX package " + packageName);
- return PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION;
+ String errorMsg = "Attempting to install new APEX package " + packageName;
+ Slog.w(TAG, errorMsg);
+ return Pair.create(PackageManager.INSTALL_FAILED_PACKAGE_CHANGED, errorMsg);
}
final long activeVersion = activePackage.getLongVersionCode();
if (requiredInstalledVersionCode != PackageManager.VERSION_CODE_HIGHEST
&& activeVersion != requiredInstalledVersionCode) {
- Slog.w(TAG, "Installed version of APEX package " + packageName
+ String errorMsg = "Installed version of APEX package " + packageName
+ " does not match required. Active version: " + activeVersion
- + " required: " + requiredInstalledVersionCode);
- return PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION;
+ + " required: " + requiredInstalledVersionCode;
+ Slog.w(TAG, errorMsg);
+ return Pair.create(PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION, errorMsg);
}
final boolean isAppDebuggable = (activePackage.applicationInfo.flags
@@ -26806,13 +26821,14 @@
final long newVersionCode = pkgLite.getLongVersionCode();
if (!PackageManagerServiceUtils.isDowngradePermitted(installFlags, isAppDebuggable)
&& newVersionCode < activeVersion) {
- Slog.w(TAG, "Downgrade of APEX package " + packageName
+ String errorMsg = "Downgrade of APEX package " + packageName
+ " is not allowed. Active version: " + activeVersion
- + " attempted: " + newVersionCode);
- return PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
+ + " attempted: " + newVersionCode;
+ Slog.w(TAG, errorMsg);
+ return Pair.create(PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE, errorMsg);
}
- return PackageManager.INSTALL_SUCCEEDED;
+ return Pair.create(PackageManager.INSTALL_SUCCEEDED, null);
}
/**
@@ -27126,6 +27142,18 @@
return mComputer.filterAppAccess(uid, callingUid);
}
+ private int[] getVisibilityAllowList(@NonNull String packageName, int userId) {
+ synchronized (mLock) {
+ final PackageSetting ps = getPackageSettingInternal(packageName, Process.SYSTEM_UID);
+ if (ps == null) {
+ return null;
+ }
+ final SparseArray<int[]> visibilityAllowList = mAppsFilter.getVisibilityAllowList(ps,
+ new int[]{userId}, mSettings.getPackagesLocked());
+ return visibilityAllowList != null ? visibilityAllowList.get(userId) : null;
+ }
+ }
+
private class PackageManagerInternalImpl extends PackageManagerInternal {
@Override
public List<ApplicationInfo> getInstalledApplications(int flags, int userId,
@@ -27213,6 +27241,11 @@
return PackageManagerService.this.filterAppAccess(uid, callingUid);
}
+ @Nullable
+ public int[] getVisibilityAllowList(@NonNull String packageName, int userId) {
+ return PackageManagerService.this.getVisibilityAllowList(packageName, userId);
+ }
+
@Override
public AndroidPackage getPackage(String packageName) {
return PackageManagerService.this.getPackage(packageName);
@@ -27269,8 +27302,7 @@
}
/**
- * Only keep package names that refer to {@link PackageParser.Package#isSystem system}
- * packages.
+ * Only keep package names that refer to {@link AndroidPackage#isSystem system} packages.
*
* @param pkgNames The packages to filter
*
@@ -28407,7 +28439,8 @@
}
@Nullable
- public PackageSetting getPackageSetting(String packageName) {
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ PackageSetting getPackageSetting(String packageName) {
return mComputer.getPackageSetting(packageName);
}
@@ -28446,16 +28479,6 @@
}
/**
- * Return a <b>copy</b> of the collection of packages known to the package manager.
- * @return A copy of the values of mPackages.
- */
- Collection<AndroidPackage> getPackages() {
- synchronized (mLock) {
- return new ArrayList<>(mPackages.values());
- }
- }
-
- /**
* Logs process start information (including base APK hash) to the security log.
* @hide
*/
diff --git a/services/core/java/com/android/server/pm/ParallelPackageParser.java b/services/core/java/com/android/server/pm/ParallelPackageParser.java
index 21334c0..5625884 100644
--- a/services/core/java/com/android/server/pm/ParallelPackageParser.java
+++ b/services/core/java/com/android/server/pm/ParallelPackageParser.java
@@ -18,7 +18,6 @@
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
-import android.content.pm.PackageParser;
import android.os.Process;
import android.os.Trace;
@@ -33,7 +32,7 @@
import java.util.concurrent.ExecutorService;
/**
- * Helper class for parallel parsing of packages using {@link PackageParser}.
+ * Helper class for parallel parsing of packages using {@link PackageParser2}.
* <p>Parsing requests are processed by a thread-pool of {@link #MAX_THREADS}.
* At any time, at most {@link #QUEUE_CAPACITY} results are kept in RAM</p>
*/
@@ -125,7 +124,7 @@
@VisibleForTesting
protected ParsedPackage parsePackage(File scanFile, int parseFlags)
- throws PackageParser.PackageParserException {
+ throws PackageManagerException {
return mPackageParser.parsePackage(scanFile, parseFlags, true);
}
}
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index b8a2dc8..9dcae3d 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -34,10 +34,11 @@
import android.content.pm.PackageInstaller.SessionInfo.StagedSessionErrorCode;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
-import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.SigningDetails;
import android.content.pm.SigningDetails.SignatureSchemeVersion;
import android.content.pm.parsing.PackageInfoWithoutStateUtils;
+import android.content.pm.parsing.result.ParseResult;
+import android.content.pm.parsing.result.ParseTypeImpl;
import android.content.rollback.RollbackInfo;
import android.content.rollback.RollbackManager;
import android.os.Bundle;
@@ -216,13 +217,15 @@
int minSignatureScheme = ApkSignatureVerifier.getMinimumSignatureSchemeVersionForTargetSdk(
newApexPkg.applicationInfo.targetSdkVersion);
- final SigningDetails newSigningDetails;
- try {
- newSigningDetails = ApkSignatureVerifier.verify(apexPath, minSignatureScheme);
- } catch (PackageParserException e) {
+ final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
+ final ParseResult<SigningDetails> newResult = ApkSignatureVerifier.verify(
+ input.reset(), apexPath, minSignatureScheme);
+ if (newResult.isError()) {
throw new PackageManagerException(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
- "Failed to parse APEX package " + apexPath + " : " + e, e);
+ "Failed to parse APEX package " + apexPath + " : "
+ + newResult.getException(), newResult.getException());
}
+ final SigningDetails newSigningDetails = newResult.getResult();
// Get signing details of the existing package
final PackageInfo existingApexPkg = mApexManager.getPackageInfo(packageName,
@@ -233,15 +236,15 @@
throw new IllegalStateException("Unknown apex package " + packageName);
}
- final SigningDetails existingSigningDetails;
- try {
- existingSigningDetails = ApkSignatureVerifier.verify(
- existingApexPkg.applicationInfo.sourceDir, SignatureSchemeVersion.JAR);
- } catch (PackageParserException e) {
+ final ParseResult<SigningDetails> existingResult = ApkSignatureVerifier.verify(
+ input.reset(), existingApexPkg.applicationInfo.sourceDir,
+ SignatureSchemeVersion.JAR);
+ if (existingResult.isError()) {
throw new PackageManagerException(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
"Failed to parse APEX package " + existingApexPkg.applicationInfo.sourceDir
- + " : " + e, e);
+ + " : " + existingResult.getException(), existingResult.getException());
}
+ final SigningDetails existingSigningDetails = existingResult.getResult();
// Verify signing details for upgrade
if (newSigningDetails.checkCapability(existingSigningDetails,
@@ -297,7 +300,7 @@
SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
"Unable to generate package info: " + apexInfo.modulePath);
}
- } catch (PackageParserException e) {
+ } catch (PackageManagerException e) {
throw new PackageManagerException(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
"Failed to parse APEX package " + apexInfo.modulePath + " : " + e, e);
}
@@ -746,6 +749,26 @@
}
}
+ /**
+ * Returns id of a committed and non-finalized stated session that contains same
+ * {@code packageName}, or {@code -1} if no sessions have this {@code packageName} staged.
+ */
+ int getSessionIdByPackageName(@NonNull String packageName) {
+ synchronized (mStagedSessions) {
+ for (int i = 0; i < mStagedSessions.size(); i++) {
+ StagedSession stagedSession = mStagedSessions.valueAt(i);
+ if (!stagedSession.isCommitted() || stagedSession.isDestroyed()
+ || stagedSession.isInTerminalState()) {
+ continue;
+ }
+ if (stagedSession.getPackageName().equals(packageName)) {
+ return stagedSession.sessionId();
+ }
+ }
+ }
+ return -1;
+ }
+
@VisibleForTesting
void createSession(@NonNull StagedSession sessionInfo) {
synchronized (mStagedSessions) {
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 0f67be7..fa9ed66 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 @@
* 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/parsing/PackageParser2.java b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
index e8be9b6..203356d 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageParser2.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
@@ -23,7 +23,6 @@
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageParser;
-import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.parsing.ParsingPackage;
import android.content.pm.parsing.ParsingPackageUtils;
import android.content.pm.parsing.ParsingUtils;
@@ -39,6 +38,7 @@
import android.util.Slog;
import com.android.internal.compat.IPlatformCompat;
+import com.android.server.pm.PackageManagerException;
import com.android.server.pm.PackageManagerService;
import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.parsing.pkg.ParsedPackage;
@@ -147,7 +147,7 @@
*/
@AnyThread
public ParsedPackage parsePackage(File packageFile, int flags, boolean useCaches)
- throws PackageParserException {
+ throws PackageManagerException {
if (useCaches && mCacher != null) {
ParsedPackage parsed = mCacher.getCachedResult(packageFile, flags);
if (parsed != null) {
@@ -159,7 +159,7 @@
ParseInput input = mSharedResult.get().reset();
ParseResult<ParsingPackage> result = parsingUtils.parsePackage(input, packageFile, flags);
if (result.isError()) {
- throw new PackageParserException(result.getErrorCode(), result.getErrorMessage(),
+ throw new PackageManagerException(result.getErrorCode(), result.getErrorMessage(),
result.getException());
}
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
index b30c9da..d40aada 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
@@ -21,7 +21,6 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.SharedLibraryInfo;
import android.content.pm.VersionedPackage;
import android.content.pm.dex.DexMetadataHelper;
@@ -31,12 +30,15 @@
import android.content.pm.parsing.component.ParsedInstrumentation;
import android.content.pm.parsing.component.ParsedProvider;
import android.content.pm.parsing.component.ParsedService;
+import android.content.pm.parsing.result.ParseResult;
+import android.content.pm.parsing.result.ParseTypeImpl;
import android.os.incremental.IncrementalManager;
import android.text.TextUtils;
import com.android.internal.content.NativeLibraryHelper;
import com.android.internal.util.ArrayUtils;
import com.android.server.SystemConfig;
+import com.android.server.pm.PackageManagerException;
import com.android.server.pm.PackageSetting;
import java.io.IOException;
@@ -120,15 +122,21 @@
/**
* Validate the dex metadata files installed for the given package.
*
- * @throws PackageParserException in case of errors.
+ * @throws PackageManagerException in case of errors.
*/
public static void validatePackageDexMetadata(AndroidPackage pkg)
- throws PackageParserException {
+ throws PackageManagerException {
Collection<String> apkToDexMetadataList = getPackageDexMetadata(pkg).values();
String packageName = pkg.getPackageName();
long versionCode = pkg.toAppInfoWithoutState().longVersionCode;
+ final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
for (String dexMetadata : apkToDexMetadataList) {
- DexMetadataHelper.validateDexMetadataFile(dexMetadata, packageName, versionCode);
+ final ParseResult result = DexMetadataHelper.validateDexMetadataFile(
+ input.reset(), dexMetadata, packageName, versionCode);
+ if (result.isError()) {
+ throw new PackageManagerException(
+ result.getErrorCode(), result.getErrorMessage(), result.getException());
+ }
}
}
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
index 2234022..3eb4bde 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
@@ -306,8 +306,8 @@
}
@Override
- public PackageImpl setCodePath(@NonNull String value) {
- this.mPath = value;
+ public PackageImpl setPath(@NonNull String path) {
+ this.mPath = path;
return this;
}
@@ -381,8 +381,8 @@
}
@Override
- public PackageImpl setBaseCodePath(@NonNull String baseCodePath) {
- this.mBaseApkPath = TextUtils.safeIntern(baseCodePath);
+ public PackageImpl setBaseApkPath(@NonNull String baseApkPath) {
+ this.mBaseApkPath = TextUtils.safeIntern(baseApkPath);
return this;
}
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/ParsedPackage.java b/services/core/java/com/android/server/pm/parsing/pkg/ParsedPackage.java
index 8e4ee6a..0051bab 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/ParsedPackage.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/ParsedPackage.java
@@ -43,9 +43,9 @@
ParsedPackage clearProtectedBroadcasts();
- ParsedPackage setBaseCodePath(String baseCodePath);
+ ParsedPackage setBaseApkPath(String baseApkPath);
- ParsedPackage setCodePath(String codePath);
+ ParsedPackage setPath(String path);
ParsedPackage setNativeLibraryDir(String nativeLibraryDir);
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 56e6f9b..fbe14ce 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -3385,7 +3385,7 @@
boolean allowed = false;
for (int i = 0, size = CompatibilityPermissionInfo.COMPAT_PERMS.length; i < size; i++) {
final CompatibilityPermissionInfo info = CompatibilityPermissionInfo.COMPAT_PERMS[i];
- if (info.name.equals(perm)
+ if (info.getName().equals(perm)
&& pkg.getTargetSdkVersion() < info.sdkVersion) {
allowed = true;
Log.i(TAG, "Auto-granting " + perm + " to old pkg "
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java
index 32ba852..76927e1 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java
@@ -121,13 +121,8 @@
* Throws a {@link SecurityException} iff the originator has permission to receive data.
*/
void enforcePermissionsForDataDelivery(@NonNull Identity identity, @NonNull String reason) {
- // TODO(b/186164881): remove
- // START TEMP HACK
- enforcePermissionForPreflight(mContext, identity, RECORD_AUDIO);
- int hotwordOp = AppOpsManager.strOpToOp(AppOpsManager.OPSTR_RECORD_AUDIO_HOTWORD);
- mContext.getSystemService(AppOpsManager.class).noteOpNoThrow(hotwordOp, identity.uid,
- identity.packageName, identity.attributionTag, reason);
- // END TEMP HACK
+ enforcePermissionForDataDelivery(mContext, identity, RECORD_AUDIO,
+ reason);
enforcePermissionForDataDelivery(mContext, identity, CAPTURE_AUDIO_HOTWORD,
reason);
}
@@ -155,8 +150,8 @@
/**
* Throws a {@link SecurityException} if originator permanently doesn't have the given
- * permission, or a {@link ServiceSpecificException} with a {@link
- * Status#TEMPORARY_PERMISSION_DENIED} if caller originator doesn't have the given permission.
+ * permission.
+ * Soft (temporary) denials are considered OK for preflight purposes.
*
* @param context A {@link Context}, used for permission checks.
* @param identity The identity to check.
@@ -168,15 +163,12 @@
permission);
switch (status) {
case PermissionChecker.PERMISSION_GRANTED:
+ case PermissionChecker.PERMISSION_SOFT_DENIED:
return;
case PermissionChecker.PERMISSION_HARD_DENIED:
throw new SecurityException(
String.format("Failed to obtain permission %s for identity %s", permission,
ObjectPrinter.print(identity, true, 16)));
- case PermissionChecker.PERMISSION_SOFT_DENIED:
- throw new ServiceSpecificException(Status.TEMPORARY_PERMISSION_DENIED,
- String.format("Failed to obtain permission %s for identity %s", permission,
- ObjectPrinter.print(identity, true, 16)));
default:
throw new RuntimeException("Unexpected perimission check result.");
}
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
index d9fa792..7b31946 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
@@ -279,6 +279,9 @@
/** Activity state. */
Activity activityState = Activity.LOADED;
+ /** Recognition config, used to start the model. */
+ RecognitionConfig config;
+
/** Human-readable description of the model. */
final String description;
@@ -455,6 +458,7 @@
// From here on, every exception isn't client's fault.
try {
mDelegate.startRecognition(modelHandle, config);
+ modelState.config = config;
modelState.activityState = ModelState.Activity.ACTIVE;
} catch (Exception e) {
throw handleException(e);
@@ -512,6 +516,27 @@
}
}
+ private void restartIfIntercepted(int modelHandle) {
+ synchronized (SoundTriggerMiddlewareValidation.this) {
+ // State validation.
+ if (mState == ModuleStatus.DETACHED) {
+ return;
+ }
+ ModelState modelState = mLoadedModels.get(modelHandle);
+ if (modelState == null
+ || modelState.activityState != ModelState.Activity.INTERCEPTED) {
+ return;
+ }
+ try {
+ mDelegate.startRecognition(modelHandle, modelState.config);
+ modelState.activityState = ModelState.Activity.ACTIVE;
+ Log.i(TAG, "Restarted intercepted model " + modelHandle);
+ } catch (Exception e) {
+ Log.i(TAG, "Failed to restart intercepted model " + modelHandle, e);
+ }
+ }
+ }
+
@Override
public void forceRecognitionEvent(int modelHandle) {
// Input validation (always valid).
@@ -720,6 +745,11 @@
ModelState modelState = mLoadedModels.get(modelHandle);
if (event.status != RecognitionStatus.FORCED) {
modelState.activityState = ModelState.Activity.INTERCEPTED;
+ // If we failed to deliver an actual event to the client, they would
+ // never know to restart it whenever circumstances change. Thus, we
+ // restart it here. We do this from a separate thread to avoid any
+ // race conditions.
+ new Thread(() -> restartIfIntercepted(modelHandle)).start();
}
}
}
@@ -744,6 +774,11 @@
ModelState modelState = mLoadedModels.get(modelHandle);
if (event.common.status != RecognitionStatus.FORCED) {
modelState.activityState = ModelState.Activity.INTERCEPTED;
+ // If we failed to deliver an actual event to the client, they would
+ // never know to restart it whenever circumstances change. Thus, we
+ // restart it here. We do this from a separate thread to avoid any
+ // race conditions.
+ new Thread(() -> restartIfIntercepted(modelHandle)).start();
}
}
}
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 8658334..36a854e 100755
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -209,10 +209,11 @@
private void registerBroadcastReceivers() {
PackageMonitor monitor = new PackageMonitor() {
private void buildTvInputList(String[] packages) {
+ int userId = getChangingUserId();
synchronized (mLock) {
- if (mCurrentUserId == getChangingUserId()) {
- buildTvInputListLocked(mCurrentUserId, packages);
- buildTvContentRatingSystemListLocked(mCurrentUserId);
+ if (mCurrentUserId == userId || mRunningProfiles.contains(userId)) {
+ buildTvInputListLocked(userId, packages);
+ buildTvContentRatingSystemListLocked(userId);
}
}
}
diff --git a/services/core/java/com/android/server/vcn/Vcn.java b/services/core/java/com/android/server/vcn/Vcn.java
index 9c3721b1..382398a 100644
--- a/services/core/java/com/android/server/vcn/Vcn.java
+++ b/services/core/java/com/android/server/vcn/Vcn.java
@@ -596,7 +596,12 @@
/** Retrieves the network score for a VCN Network */
// Package visibility for use in VcnGatewayConnection and VcnNetworkProvider
static NetworkScore getNetworkScore() {
- return new NetworkScore.Builder().setLegacyInt(VCN_LEGACY_SCORE_INT).build();
+ // TODO(b/193687515): Stop setting TRANSPORT_PRIMARY, define a TRANSPORT_VCN, and set in
+ // NetworkOffer/NetworkAgent.
+ return new NetworkScore.Builder()
+ .setLegacyInt(VCN_LEGACY_SCORE_INT)
+ .setTransportPrimary(true)
+ .build();
}
/** Callback used for passing status signals from a VcnGatewayConnection to its managing Vcn. */
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 54d97ee..fe4eead 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -74,7 +74,6 @@
import android.os.Process;
import android.os.SystemClock;
import android.util.ArraySet;
-import android.util.IntArray;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TypedValue;
@@ -94,7 +93,6 @@
import com.android.internal.R;
import com.android.internal.os.SomeArgs;
import com.android.internal.util.TraceBuffer;
-import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.LocalServices;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.wm.WindowManagerInternal.AccessibilityControllerInternal;
@@ -177,17 +175,12 @@
/**
* Sets a callback for observing which windows are touchable for the purposes
- * of accessibility on specified display. When a display is reparented and becomes
- * an embedded one, the {@link WindowsForAccessibilityCallback#onDisplayReparented(int)}
- * will notify the accessibility framework to remove the un-used window observer of
- * this embedded display.
+ * of accessibility on specified display.
*
* @param displayId The logical display id.
* @param callback The callback.
- * @return {@code false} if display id is not valid or an embedded display when the callback
- * isn't null.
*/
- boolean setWindowsForAccessibilityCallback(int displayId,
+ void setWindowsForAccessibilityCallback(int displayId,
WindowsForAccessibilityCallback callback) {
if (mAccessibilityTracing.isTracingEnabled(FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
mAccessibilityTracing.logTrace(
@@ -197,30 +190,15 @@
}
if (callback != null) {
- final DisplayContent dc = mService.mRoot.getDisplayContentOrCreate(displayId);
- if (dc == null) {
- return false;
- }
-
WindowsForAccessibilityObserver observer =
mWindowsForAccessibilityObserver.get(displayId);
- if (isEmbeddedDisplay(dc)) {
- // If this display is an embedded one, its window observer should have been set from
- // window manager after setting its parent window. But if its window observer is
- // empty, that means this mapping didn't be set, and needs to do this again.
- // This happened when accessibility window observer is disabled and enabled again.
- if (observer == null) {
- handleWindowObserverOfEmbeddedDisplay(displayId, dc.getParentWindow());
- }
- return false;
- } else if (observer != null) {
+ if (observer != null) {
final String errorMessage = "Windows for accessibility callback of display "
+ displayId + " already set!";
Slog.e(TAG, errorMessage);
if (Build.IS_DEBUGGABLE) {
throw new IllegalStateException(errorMessage);
}
- removeObserversForEmbeddedChildDisplays(observer);
mWindowsForAccessibilityObserver.remove(displayId);
}
observer = new WindowsForAccessibilityObserver(mService, displayId, callback);
@@ -237,10 +215,8 @@
throw new IllegalStateException(errorMessage);
}
}
- removeObserversForEmbeddedChildDisplays(windowsForA11yObserver);
mWindowsForAccessibilityObserver.remove(displayId);
}
- return true;
}
void performComputeChangedWindowsNot(int displayId, boolean forceSend) {
@@ -507,54 +483,6 @@
}
}
- void handleWindowObserverOfEmbeddedDisplay(int embeddedDisplayId,
- WindowState parentWindow) {
- handleWindowObserverOfEmbeddedDisplay(
- embeddedDisplayId, parentWindow, Binder.getCallingUid());
- }
-
- void handleWindowObserverOfEmbeddedDisplay(
- int embeddedDisplayId, WindowState parentWindow, int callingUid) {
- if (mAccessibilityTracing.isTracingEnabled(FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
- mAccessibilityTracing.logTrace(TAG + ".handleWindowObserverOfEmbeddedDisplay",
- FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK,
- "embeddedDisplayId=" + embeddedDisplayId + "; parentWindowState={"
- + parentWindow + "}", "".getBytes(), callingUid);
- }
- if (embeddedDisplayId == Display.DEFAULT_DISPLAY || parentWindow == null) {
- return;
- }
- mService.mH.sendMessage(PooledLambda.obtainMessage(
- AccessibilityController::updateWindowObserverOfEmbeddedDisplay,
- this, embeddedDisplayId, parentWindow));
- }
-
- private void updateWindowObserverOfEmbeddedDisplay(int embeddedDisplayId,
- WindowState parentWindow) {
- final WindowsForAccessibilityObserver windowsForA11yObserver;
-
- synchronized (mService.mGlobalLock) {
- // Finds the parent display of this embedded display
- WindowState candidate = parentWindow;
- while (candidate != null) {
- parentWindow = candidate;
- candidate = parentWindow.getDisplayContent().getParentWindow();
- }
- final int parentDisplayId = parentWindow.getDisplayId();
- // Uses the observer of parent display
- windowsForA11yObserver = mWindowsForAccessibilityObserver.get(parentDisplayId);
- }
-
- if (windowsForA11yObserver != null) {
- windowsForA11yObserver.notifyDisplayReparented(embeddedDisplayId);
- windowsForA11yObserver.addEmbeddedDisplay(embeddedDisplayId);
- synchronized (mService.mGlobalLock) {
- // Replaces the observer of embedded display to the one of parent display
- mWindowsForAccessibilityObserver.put(embeddedDisplayId, windowsForA11yObserver);
- }
- }
- }
-
void onImeSurfaceShownChanged(WindowState windowState, boolean shown) {
if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
mAccessibilityTracing.logTrace(TAG + ".onImeSurfaceShownChanged",
@@ -584,23 +512,6 @@
+ "mWindowsForAccessibilityObserver=" + mWindowsForAccessibilityObserver);
}
- private void removeObserversForEmbeddedChildDisplays(WindowsForAccessibilityObserver
- observerOfParentDisplay) {
- final IntArray embeddedDisplayIdList =
- observerOfParentDisplay.getAndClearEmbeddedDisplayIdList();
-
- for (int index = 0; index < embeddedDisplayIdList.size(); index++) {
- final int embeddedDisplayId = embeddedDisplayIdList.get(index);
- mWindowsForAccessibilityObserver.remove(embeddedDisplayId);
- }
- }
-
- private static boolean isEmbeddedDisplay(DisplayContent dc) {
- final Display display = dc.getDisplay();
-
- return display.getType() == Display.TYPE_VIRTUAL && dc.getParentWindow() != null;
- }
-
/**
* This class encapsulates the functionality related to display magnification.
*/
@@ -1534,8 +1445,6 @@
private final long mRecurringAccessibilityEventsIntervalMillis;
- private final IntArray mEmbeddedDisplayIdList = new IntArray(0);
-
// Set to true if initializing window population complete.
private boolean mInitialized;
@@ -1573,28 +1482,6 @@
}
}
- IntArray getAndClearEmbeddedDisplayIdList() {
- final IntArray returnedArray = new IntArray(mEmbeddedDisplayIdList.size());
- returnedArray.addAll(mEmbeddedDisplayIdList);
- mEmbeddedDisplayIdList.clear();
-
- return returnedArray;
- }
-
- void addEmbeddedDisplay(int displayId) {
- if (displayId == mDisplayId) {
- return;
- }
- mEmbeddedDisplayIdList.add(displayId);
- }
-
- void notifyDisplayReparented(int embeddedDisplayId) {
- // Notifies the A11y framework the display is reparented and
- // becomes an embedded display for removing the un-used
- // displayWindowObserver of this embedded one.
- mCallback.onDisplayReparented(embeddedDisplayId);
- }
-
boolean shellRootIsAbove(WindowState windowState, ShellRoot shellRoot) {
int wsLayer = mService.mPolicy.getWindowLayerLw(windowState);
int shellLayer = mService.mPolicy.getWindowLayerFromTypeLw(shellRoot.getWindowType(),
@@ -1761,12 +1648,7 @@
addedWindows.clear();
// Gets the top focused display Id and window token for supporting multi-display.
- // If this top focused display is an embedded one, using its parent display as the
- // top focused display.
- final DisplayContent topFocusedDisplayContent =
- mService.mRoot.getTopFocusedDisplayContent();
- topFocusedDisplayId = isEmbeddedDisplay(topFocusedDisplayContent) ? mDisplayId
- : topFocusedDisplayContent.getDisplayId();
+ topFocusedDisplayId = mService.mRoot.getTopFocusedDisplayContent().getDisplayId();
topFocusedWindowToken = topFocusedWindowState.mClient.asBinder();
}
mCallback.onWindowsForAccessibilityChanged(forceSend, topFocusedDisplayId,
@@ -1970,8 +1852,6 @@
public String toString() {
return "WindowsForAccessibilityObserver{"
+ "mDisplayId=" + mDisplayId
- + ", mEmbeddedDisplayIdList="
- + Arrays.toString(mEmbeddedDisplayIdList.toArray())
+ ", mInitialized=" + mInitialized
+ '}';
}
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index 8a76e3e5..331b8de 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -42,6 +42,7 @@
import static com.android.server.wm.ActivityTaskManagerService.enforceNotIsolatedCaller;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
@@ -539,6 +540,27 @@
}
@Override
+ @Nullable
+ public IBinder getActivityTokenBelow(IBinder activityToken) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ final ActivityRecord ar = ActivityRecord.isInAnyTask(activityToken);
+ if (ar == null) {
+ return null;
+ }
+ final ActivityRecord below = ar.getTask().getActivityBelow(ar);
+ if (below != null && below.getUid() == ar.getUid()) {
+ return below.appToken.asBinder();
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ return null;
+ }
+
+ @Override
public ComponentName getCallingActivity(IBinder token) {
synchronized (mGlobalLock) {
final ActivityRecord r = getCallingRecord(token);
@@ -1020,7 +1042,8 @@
r.mOverrideTaskTransition);
mService.getTransitionController().setOverrideAnimation(
TransitionInfo.AnimationOptions.makeCustomAnimOptions(packageName,
- enterAnim, exitAnim, r.mOverrideTaskTransition));
+ enterAnim, exitAnim, r.mOverrideTaskTransition),
+ null /* startCallback */, null /* finishCallback */);
}
}
Binder.restoreCallingIdentity(origId);
@@ -1160,7 +1183,7 @@
try {
final Intent baseActivityIntent;
final boolean launchedFromHome;
-
+ final boolean isLastRunningActivity;
synchronized (mGlobalLock) {
final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token);
if (r == null) return;
@@ -1172,7 +1195,9 @@
return;
}
- final Intent baseIntent = r.getTask().getBaseIntent();
+ final Task task = r.getTask();
+ isLastRunningActivity = task.topRunningActivity() == r;
+ final Intent baseIntent = task.getBaseIntent();
final boolean activityIsBaseActivity = baseIntent != null
&& r.mActivityComponent.equals(baseIntent.getComponent());
baseActivityIntent = activityIsBaseActivity ? r.intent : null;
@@ -1182,12 +1207,13 @@
// If the activity is one of the main entry points for the application, then we should
// refrain from finishing the activity and instead move it to the back to keep it in
// memory. The requirements for this are:
- // 1. The current activity is the base activity for the task.
- // 2. a. If the activity was launched by the home process, we trust that its intent
+ // 1. The activity is the last running activity in the task.
+ // 2. The current activity is the base activity for the task.
+ // 3. a. If the activity was launched by the home process, we trust that its intent
// was resolved, so we check if the it is a main intent for the application.
// b. Otherwise, we query Package Manager to verify whether the activity is a
// launcher activity for the application.
- if (baseActivityIntent != null
+ if (baseActivityIntent != null && isLastRunningActivity
&& ((launchedFromHome && ActivityRecord.isMainIntent(baseActivityIntent))
|| isLauncherActivity(baseActivityIntent.getComponent()))) {
moveActivityTaskToBack(token, false /* nonRoot */);
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index b1163c4..005a62a 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -936,9 +936,11 @@
// This will avoid any races with other operations that modify the ActivityRecord.
final TransitionInfoSnapshot infoSnapshot = new TransitionInfoSnapshot(info);
if (info.isInterestingToLoggerAndObserver()) {
+ final long timestamp = info.mTransitionStartTimeNs;
+ final long uptime = info.mTransitionDeviceUptimeMs;
+ final int transitionDelay = info.mCurrentTransitionDelayMs;
mLoggerHandler.post(() -> logAppTransition(
- info.mTransitionDeviceUptimeMs, info.mCurrentTransitionDelayMs,
- infoSnapshot, isHibernating));
+ timestamp, uptime, transitionDelay, infoSnapshot, isHibernating));
}
mLoggerHandler.post(() -> logAppDisplayed(infoSnapshot));
if (info.mPendingFullyDrawn != null) {
@@ -949,8 +951,8 @@
}
// This gets called on another thread without holding the activity manager lock.
- private void logAppTransition(long transitionDeviceUptimeMs, int currentTransitionDelayMs,
- TransitionInfoSnapshot info, boolean isHibernating) {
+ private void logAppTransition(long transitionStartTimeNs, long transitionDeviceUptimeMs,
+ int currentTransitionDelayMs, TransitionInfoSnapshot info, boolean isHibernating) {
final LogMaker builder = new LogMaker(APP_TRANSITION);
builder.setPackageName(info.packageName);
builder.setType(info.type);
@@ -1001,7 +1003,7 @@
info.launchedActivityName,
info.launchedActivityLaunchedFromPackage,
isInstantApp,
- transitionDeviceUptimeMs,
+ 0 /* deprecated transitionDeviceUptimeMs */,
info.reason,
currentTransitionDelayMs,
info.startingWindowDelayMs,
@@ -1015,7 +1017,8 @@
isHibernating,
isIncremental,
isLoading,
- info.launchedActivityName.hashCode());
+ info.launchedActivityName.hashCode(),
+ TimeUnit.NANOSECONDS.toMillis(transitionStartTimeNs));
if (DEBUG_METRICS) {
Slog.i(TAG, String.format("APP_START_OCCURRED(%s, %s, %s, %s, %s)",
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index e7c89dc..bc551df 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -273,6 +273,7 @@
import android.os.Bundle;
import android.os.Debug;
import android.os.IBinder;
+import android.os.IRemoteCallback;
import android.os.PersistableBundle;
import android.os.Process;
import android.os.RemoteException;
@@ -543,11 +544,6 @@
final ActivityTaskSupervisor mTaskSupervisor;
final RootWindowContainer mRootWindowContainer;
- static final int STARTING_WINDOW_NOT_SHOWN = 0;
- static final int STARTING_WINDOW_SHOWN = 1;
- static final int STARTING_WINDOW_REMOVED = 2;
- int mStartingWindowState = STARTING_WINDOW_NOT_SHOWN;
-
// Tracking splash screen status from previous activity
boolean mSplashScreenStyleEmpty = false;
@@ -888,19 +884,6 @@
}
};
- private static String startingWindowStateToString(int state) {
- switch (state) {
- case STARTING_WINDOW_NOT_SHOWN:
- return "STARTING_WINDOW_NOT_SHOWN";
- case STARTING_WINDOW_SHOWN:
- return "STARTING_WINDOW_SHOWN";
- case STARTING_WINDOW_REMOVED:
- return "STARTING_WINDOW_REMOVED";
- default:
- return "unknown state=" + state;
- }
- }
-
@Override
void dump(PrintWriter pw, String prefix, boolean dumpAll) {
final long now = SystemClock.uptimeMillis();
@@ -1057,9 +1040,7 @@
pw.print(" finishing="); pw.println(finishing);
pw.print(prefix); pw.print("keysPaused="); pw.print(keysPaused);
pw.print(" inHistory="); pw.print(inHistory);
- pw.print(" idle="); pw.print(idle);
- pw.print(" mStartingWindowState=");
- pw.println(startingWindowStateToString(mStartingWindowState));
+ pw.print(" idle="); pw.println(idle);
pw.print(prefix); pw.print("occludesParent="); pw.print(occludesParent());
pw.print(" noDisplay="); pw.print(noDisplay);
pw.print(" immersive="); pw.print(immersive);
@@ -1885,6 +1866,13 @@
task.setRootProcess(proc);
}
proc.addActivityIfNeeded(this);
+
+ // Update the associated task fragment after setting the process, since it's required for
+ // filtering to only report activities that belong to the same process.
+ final TaskFragment tf = getTaskFragment();
+ if (tf != null) {
+ tf.sendTaskFragmentInfoChanged();
+ }
}
boolean hasProcess() {
@@ -2014,6 +2002,7 @@
}
}
+ @VisibleForTesting
boolean addStartingWindow(String pkg, int resolvedTheme, CompatibilityInfo compatInfo,
CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags,
IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning,
@@ -2349,13 +2338,13 @@
}
void removeStartingWindow() {
+ if (transferSplashScreenIfNeeded()) {
+ return;
+ }
removeStartingWindowAnimation(true /* prepareAnimation */);
}
void removeStartingWindowAnimation(boolean prepareAnimation) {
- if (transferSplashScreenIfNeeded()) {
- return;
- }
mTransferringSplashScreenState = TRANSFER_SPLASH_SCREEN_IDLE;
if (mStartingWindow == null) {
if (mStartingData != null) {
@@ -3457,6 +3446,10 @@
return;
}
finishing = true;
+ final TaskFragment taskFragment = getTaskFragment();
+ if (taskFragment != null) {
+ taskFragment.sendTaskFragmentInfoChanged();
+ }
if (stopped) {
abortAndClearOptionsAnimation();
}
@@ -4327,6 +4320,8 @@
final int animationType = pendingOptions.getAnimationType();
final DisplayContent displayContent = getDisplayContent();
AnimationOptions options = null;
+ IRemoteCallback startCallback = null;
+ IRemoteCallback finishCallback = null;
switch (animationType) {
case ANIM_CUSTOM:
displayContent.mAppTransition.overridePendingAppTransition(
@@ -4339,6 +4334,8 @@
options = AnimationOptions.makeCustomAnimOptions(pendingOptions.getPackageName(),
pendingOptions.getCustomEnterResId(), pendingOptions.getCustomExitResId(),
pendingOptions.getOverrideTaskTransition());
+ startCallback = pendingOptions.getAnimationStartedListener();
+ finishCallback = pendingOptions.getAnimationFinishedListener();
break;
case ANIM_CLIP_REVEAL:
displayContent.mAppTransition.overridePendingAppTransitionClipReveal(
@@ -4378,6 +4375,7 @@
scaleUp);
options = AnimationOptions.makeThumnbnailAnimOptions(buffer,
pendingOptions.getStartX(), pendingOptions.getStartY(), scaleUp);
+ startCallback = pendingOptions.getAnimationStartedListener();
if (intent.getSourceBounds() == null && buffer != null) {
intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
pendingOptions.getStartY(),
@@ -4428,7 +4426,8 @@
}
if (options != null) {
- mAtmService.getTransitionController().setOverrideAnimation(options);
+ mAtmService.getTransitionController().setOverrideAnimation(options,
+ startCallback, finishCallback);
}
}
@@ -6288,6 +6287,12 @@
return null;
}
+ @Nullable
+ static ActivityRecord isInAnyTask(IBinder token) {
+ final ActivityRecord r = ActivityRecord.forTokenLocked(token);
+ return (r != null && r.isAttached()) ? r : null;
+ }
+
/**
* @return display id to which this record is attached,
* {@link android.view.Display#INVALID_DISPLAY} if not attached.
@@ -6493,13 +6498,13 @@
final boolean newSingleActivity = !newTask && !activityCreated
&& task.getActivity((r) -> !r.finishing && r != this) == null;
- final boolean shown = addStartingWindow(packageName, resolvedTheme,
+ final boolean scheduled = addStartingWindow(packageName, resolvedTheme,
compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
prev != null ? prev.appToken : null,
newTask || newSingleActivity, taskSwitch, isProcessRunning(),
allowTaskSnapshot(), activityCreated, mSplashScreenStyleEmpty);
- if (shown) {
- mStartingWindowState = STARTING_WINDOW_SHOWN;
+ if (DEBUG_STARTING_WINDOW_VERBOSE && scheduled) {
+ Slog.d(TAG, "Scheduled starting window for " + this);
}
}
@@ -6511,14 +6516,12 @@
* It should only be called if this activity is behind other fullscreen activity.
*/
void cancelInitializing() {
- if (mStartingWindowState == STARTING_WINDOW_SHOWN) {
+ if (mStartingData != null) {
// Remove orphaned starting window.
if (DEBUG_VISIBILITY) Slog.w(TAG_VISIBILITY, "Found orphaned starting window " + this);
- mStartingWindowState = STARTING_WINDOW_REMOVED;
removeStartingWindowAnimation(false /* prepareAnimation */);
}
- if (isState(INITIALIZING) && !shouldBeVisible(
- true /* behindFullscreenActivity */, true /* ignoringKeyguard */)) {
+ if (!mDisplayContent.mUnknownAppVisibilityController.allResolved()) {
// Remove the unknown visibility record because an invisible activity shouldn't block
// the keyguard transition.
mDisplayContent.mUnknownAppVisibilityController.appRemovedOrHidden(this);
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index d08d285..b71ad2e 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -490,11 +490,22 @@
return START_SUCCESS;
}
- void startActivityInTaskFragment(@NonNull TaskFragment taskFragment,
- @NonNull Intent activityIntent, @Nullable Bundle activityOptions) {
- obtainStarter(activityIntent, "startActivityInTaskFragment")
+ /**
+ * Starts an activity in the TaskFragment.
+ * @param taskFragment TaskFragment {@link TaskFragment} to start the activity in.
+ * @param activityIntent intent to start the activity.
+ * @param activityOptions ActivityOptions to start the activity with.
+ * @param resultTo the caller activity
+ * @return the start result.
+ */
+ int startActivityInTaskFragment(@NonNull TaskFragment taskFragment,
+ @NonNull Intent activityIntent, @Nullable Bundle activityOptions,
+ @Nullable IBinder resultTo) {
+ return obtainStarter(activityIntent, "startActivityInTaskFragment")
.setActivityOptions(activityOptions)
.setInTaskFragment(taskFragment)
+ .setResultTo(resultTo)
+ .setRequestCode(-1)
.setCallingUid(Binder.getCallingUid())
.setCallingPid(Binder.getCallingPid())
.execute();
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 9d127a6..c881359 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -872,7 +872,7 @@
ActivityRecord sourceRecord = null;
ActivityRecord resultRecord = null;
if (resultTo != null) {
- sourceRecord = mRootWindowContainer.isInAnyTask(resultTo);
+ sourceRecord = ActivityRecord.isInAnyTask(resultTo);
if (DEBUG_RESULTS) {
Slog.v(TAG_RESULTS, "Will send result to " + resultTo + " " + sourceRecord);
}
@@ -1559,6 +1559,7 @@
TaskFragment inTaskFragment, boolean restrictedBgActivity,
NeededUriGrants intentGrants) {
int result = START_CANCELED;
+ boolean startResultSuccessful = false;
final Task startedActivityRootTask;
// Create a transition now to record the original intent of actions taken within
@@ -1584,6 +1585,15 @@
result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,
startFlags, doResume, options, inTask, inTaskFragment, restrictedBgActivity,
intentGrants);
+ startResultSuccessful = ActivityManager.isStartResultSuccessful(result);
+ final boolean taskAlwaysOnTop = options != null && options.getTaskAlwaysOnTop();
+ // Apply setAlwaysOnTop when starting an Activity is successful regardless of creating
+ // a new Activity or recycling the existing Activity.
+ if (taskAlwaysOnTop && startResultSuccessful) {
+ final Task targetRootTask =
+ mTargetRootTask != null ? mTargetRootTask : mTargetTask.getRootTask();
+ targetRootTask.setAlwaysOnTop(true);
+ }
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
startedActivityRootTask = handleStartResult(r, result);
@@ -1591,7 +1601,7 @@
mSupervisor.mUserLeaving = false;
// Transition housekeeping
- if (!ActivityManager.isStartResultSuccessful(result)) {
+ if (!startResultSuccessful) {
if (newTransition != null) {
newTransition.abort();
}
@@ -1755,11 +1765,6 @@
if (!mAvoidMoveToFront && mDoResume) {
mTargetRootTask.getRootTask().moveToFront("reuseOrNewTask", targetTask);
- if (mOptions != null) {
- if (mOptions.getTaskAlwaysOnTop()) {
- mTargetRootTask.setAlwaysOnTop(true);
- }
- }
if (!mTargetRootTask.isTopRootTaskInDisplayArea() && mService.mInternal.isDreaming()) {
// Launching underneath dream activity (fullscreen, always-on-top). Run the launch-
// -behind transition so the Activity gets created and starts in visible state.
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index b3aa057..48a6626 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -1539,7 +1539,7 @@
sourceToken = resultTo;
}
- sourceRecord = mRootWindowContainer.isInAnyTask(sourceToken);
+ sourceRecord = ActivityRecord.isInAnyTask(sourceToken);
if (sourceRecord == null) {
throw new SecurityException("Called with bad activity token: " + sourceToken);
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index f6cca84..f728a48 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.Manifest.permission.ACTIVITY_EMBEDDING;
+import static android.Manifest.permission.CAMERA;
import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
import static android.Manifest.permission.START_ANY_ACTIVITY;
import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED;
@@ -89,6 +90,7 @@
import android.app.ActivityManagerInternal;
import android.app.ActivityOptions;
import android.app.AppOpsManager;
+import android.app.AppOpsManagerInternal;
import android.app.IActivityClientController;
import android.app.ProfilerInfo;
import android.app.ResultInfo;
@@ -109,6 +111,8 @@
import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
+import android.hardware.SensorPrivacyManager;
+import android.hardware.SensorPrivacyManagerInternal;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -141,6 +145,7 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.function.pooled.PooledConsumer;
import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.server.LocalServices;
import com.android.server.am.ActivityManagerService;
import com.android.server.am.UserState;
import com.android.server.wm.ActivityMetricsLogger.LaunchingState;
@@ -347,12 +352,6 @@
*/
private int mVisibilityTransactionDepth;
- /**
- * Whether to the visibility updates that started from {@code RootWindowContainer} should be
- * deferred.
- */
- private boolean mDeferRootVisibilityUpdate;
-
private ActivityMetricsLogger mActivityMetricsLogger;
/** Check if placing task or activity on specified display is allowed. */
@@ -1226,6 +1225,24 @@
if (getAppOpsManager().noteOpNoThrow(opCode, callingUid,
callingPackage, callingFeatureId, "") != AppOpsManager.MODE_ALLOWED) {
+ if (CAMERA.equals(permission)) {
+ SensorPrivacyManagerInternal spmi =
+ LocalServices.getService(SensorPrivacyManagerInternal.class);
+
+ final UserHandle user = UserHandle.getUserHandleForUid(callingUid);
+ final boolean cameraPrivacyEnabled = spmi.isSensorPrivacyEnabled(
+ user.getIdentifier(), SensorPrivacyManager.Sensors.CAMERA);
+ if (cameraPrivacyEnabled) {
+ AppOpsManagerInternal aomi = LocalServices.getService(
+ AppOpsManagerInternal.class);
+ int numCameraRestrictions = aomi.getOpRestrictionCount(
+ AppOpsManager.OP_CAMERA, user, callingPackage, null);
+ if (numCameraRestrictions == 1) {
+ // Only restricted by the toggles, do not restrict
+ return ACTIVITY_RESTRICTION_NONE;
+ }
+ }
+ }
return ACTIVITY_RESTRICTION_APPOP;
}
@@ -2270,14 +2287,6 @@
return mVisibilityTransactionDepth > 0;
}
- void setDeferRootVisibilityUpdate(boolean deferUpdate) {
- mDeferRootVisibilityUpdate = deferUpdate;
- }
-
- boolean isRootVisibilityUpdateDeferred() {
- return mDeferRootVisibilityUpdate;
- }
-
/**
* Called when the state or visibility of an attached activity is changed.
*
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 3dea686..c869ec6 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -362,8 +362,10 @@
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Wallpaper animation!");
switch (firstTransit) {
case TRANSIT_OPEN:
+ case TRANSIT_TO_FRONT:
return TRANSIT_OLD_WALLPAPER_INTRA_OPEN;
case TRANSIT_CLOSE:
+ case TRANSIT_TO_BACK:
return TRANSIT_OLD_WALLPAPER_INTRA_CLOSE;
}
} else if (oldWallpaper != null && !openingApps.isEmpty()
diff --git a/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java b/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
index 35add12..f61cc94 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
@@ -26,6 +26,7 @@
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
+import android.util.Slog;
import android.view.SurfaceControl;
import android.window.DisplayAreaAppearedInfo;
import android.window.IDisplayAreaOrganizer;
@@ -49,7 +50,8 @@
final ActivityTaskManagerService mService;
private final WindowManagerGlobalLock mGlobalLock;
- private final HashMap<Integer, IDisplayAreaOrganizer> mOrganizersByFeatureIds = new HashMap();
+ private final HashMap<Integer, DisplayAreaOrganizerState> mOrganizersByFeatureIds =
+ new HashMap();
private class DeathRecipient implements IBinder.DeathRecipient {
int mFeature;
@@ -63,12 +65,41 @@
@Override
public void binderDied() {
synchronized (mGlobalLock) {
- mOrganizersByFeatureIds.remove(mFeature);
- removeOrganizer(mOrganizer);
+ mOrganizersByFeatureIds.remove(mFeature).destroy();
}
}
}
+ private class DisplayAreaOrganizerState {
+ private final IDisplayAreaOrganizer mOrganizer;
+ private final DeathRecipient mDeathRecipient;
+
+ DisplayAreaOrganizerState(IDisplayAreaOrganizer organizer, int feature) {
+ mOrganizer = organizer;
+ mDeathRecipient = new DeathRecipient(organizer, feature);
+ try {
+ organizer.asBinder().linkToDeath(mDeathRecipient, 0);
+ } catch (RemoteException e) {
+ // Oh well...
+ }
+ }
+
+ void destroy() {
+ IBinder organizerBinder = mOrganizer.asBinder();
+ mService.mRootWindowContainer.forAllDisplayAreas((da) -> {
+ if (da.mOrganizer != null && da.mOrganizer.asBinder().equals(organizerBinder)) {
+ if (da.isTaskDisplayArea() && da.asTaskDisplayArea().mCreatedByOrganizer) {
+ // Delete the organizer created TDA when unregister.
+ deleteTaskDisplayArea(da.asTaskDisplayArea());
+ } else {
+ da.setOrganizer(null);
+ }
+ }
+ });
+ organizerBinder.unlinkToDeath(mDeathRecipient, 0);
+ }
+ }
+
DisplayAreaOrganizerController(ActivityTaskManagerService atm) {
mService = atm;
mGlobalLock = atm.mGlobalLock;
@@ -80,7 +111,8 @@
@Nullable
IDisplayAreaOrganizer getOrganizerByFeature(int featureId) {
- return mOrganizersByFeatureIds.get(featureId);
+ final DisplayAreaOrganizerState state = mOrganizersByFeatureIds.get(featureId);
+ return state != null ? state.mOrganizer : null;
}
@Override
@@ -94,17 +126,18 @@
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Register display organizer=%s uid=%d",
organizer.asBinder(), uid);
if (mOrganizersByFeatureIds.get(feature) != null) {
- throw new IllegalStateException(
- "Replacing existing organizer currently unsupported");
+ if (mOrganizersByFeatureIds.get(feature).mOrganizer.asBinder()
+ .isBinderAlive()) {
+ throw new IllegalStateException(
+ "Replacing existing organizer currently unsupported");
+ }
+
+ mOrganizersByFeatureIds.remove(feature).destroy();
+ Slog.d(TAG, "Replacing dead organizer for feature=" + feature);
}
- final DeathRecipient dr = new DeathRecipient(organizer, feature);
- try {
- organizer.asBinder().linkToDeath(dr, 0);
- } catch (RemoteException e) {
- // Oh well...
- }
-
+ final DisplayAreaOrganizerState state = new DisplayAreaOrganizerState(organizer,
+ feature);
final List<DisplayAreaAppearedInfo> displayAreaInfos = new ArrayList<>();
mService.mRootWindowContainer.forAllDisplays(dc -> {
if (!dc.isTrusted()) {
@@ -120,7 +153,7 @@
});
});
- mOrganizersByFeatureIds.put(feature, organizer);
+ mOrganizersByFeatureIds.put(feature, state);
return new ParceledListSlice<>(displayAreaInfos);
}
} finally {
@@ -137,9 +170,14 @@
synchronized (mGlobalLock) {
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Unregister display organizer=%s uid=%d",
organizer.asBinder(), uid);
- mOrganizersByFeatureIds.entrySet().removeIf(
- entry -> entry.getValue().asBinder() == organizer.asBinder());
- removeOrganizer(organizer);
+ mOrganizersByFeatureIds.entrySet().removeIf((entry) -> {
+ final boolean matches = entry.getValue().mOrganizer.asBinder()
+ == organizer.asBinder();
+ if (matches) {
+ entry.getValue().destroy();
+ }
+ return matches;
+ });
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -190,19 +228,15 @@
}
final int taskDisplayAreaFeatureId = mNextTaskDisplayAreaFeatureId++;
- final DeathRecipient dr = new DeathRecipient(organizer, taskDisplayAreaFeatureId);
- try {
- organizer.asBinder().linkToDeath(dr, 0);
- } catch (RemoteException e) {
- // Oh well...
- }
+ final DisplayAreaOrganizerState state = new DisplayAreaOrganizerState(organizer,
+ taskDisplayAreaFeatureId);
final TaskDisplayArea tda = parentRoot != null
? createTaskDisplayArea(parentRoot, name, taskDisplayAreaFeatureId)
: createTaskDisplayArea(parentTda, name, taskDisplayAreaFeatureId);
final DisplayAreaAppearedInfo tdaInfo = organizeDisplayArea(organizer, tda,
"DisplayAreaOrganizerController.createTaskDisplayArea");
- mOrganizersByFeatureIds.put(taskDisplayAreaFeatureId, organizer);
+ mOrganizersByFeatureIds.put(taskDisplayAreaFeatureId, state);
return tdaInfo;
}
} finally {
@@ -230,8 +264,7 @@
+ "TaskDisplayArea=" + taskDisplayArea);
}
- mOrganizersByFeatureIds.remove(taskDisplayArea.mFeatureId);
- deleteTaskDisplayArea(taskDisplayArea);
+ mOrganizersByFeatureIds.remove(taskDisplayArea.mFeatureId).destroy();
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -251,6 +284,10 @@
void onDisplayAreaVanished(IDisplayAreaOrganizer organizer, DisplayArea da) {
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "DisplayArea vanished name=%s", da.getName());
+ if (!organizer.asBinder().isBinderAlive()) {
+ Slog.d(TAG, "Organizer died before sending onDisplayAreaVanished");
+ return;
+ }
try {
organizer.onDisplayAreaVanished(da.getDisplayAreaInfo());
} catch (RemoteException e) {
@@ -267,20 +304,6 @@
}
}
- private void removeOrganizer(IDisplayAreaOrganizer organizer) {
- IBinder organizerBinder = organizer.asBinder();
- mService.mRootWindowContainer.forAllDisplayAreas((da) -> {
- if (da.mOrganizer != null && da.mOrganizer.asBinder().equals(organizerBinder)) {
- if (da.isTaskDisplayArea() && da.asTaskDisplayArea().mCreatedByOrganizer) {
- // Delete the organizer created TDA when unregister.
- deleteTaskDisplayArea(da.asTaskDisplayArea());
- } else {
- da.setOrganizer(null);
- }
- }
- });
- }
-
private DisplayAreaAppearedInfo organizeDisplayArea(IDisplayAreaOrganizer organizer,
DisplayArea displayArea, String callsite) {
displayArea.setOrganizer(organizer, true /* skipDisplayAreaAppeared */);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index a4e2949..fef82ac 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1895,7 +1895,7 @@
forAllWindows(w -> {
w.seamlesslyRotateIfAllowed(transaction, oldRotation, rotation, rotateSeamlessly);
}, true /* traverseTopToBottom */);
- mPinnedTaskController.startSeamlessRotationIfNeeded(transaction);
+ mPinnedTaskController.startSeamlessRotationIfNeeded(transaction, oldRotation, rotation);
}
mWmService.mDisplayManagerInternal.performTraversal(transaction);
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index f19a2c1..517d946 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -3152,7 +3152,7 @@
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
lp.setFitInsetsTypes(0);
- lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+ lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
if (ActivityManager.isHighEndGfx()) {
lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
lp.privateFlags |=
diff --git a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
index 2f0d703..45f401b 100644
--- a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
+++ b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static com.android.server.wm.ActivityRecord.State.INITIALIZING;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_VISIBILITY;
import static com.android.server.wm.Task.TAG_VISIBILITY;
@@ -141,6 +142,8 @@
} else {
mBehindFullyOccludedContainer = false;
}
+ } else if (r.isState(INITIALIZING)) {
+ r.cancelInitializing();
}
if (reallyVisible) {
diff --git a/services/core/java/com/android/server/wm/PinnedTaskController.java b/services/core/java/com/android/server/wm/PinnedTaskController.java
index 31e2ede..4f7c9a4 100644
--- a/services/core/java/com/android/server/wm/PinnedTaskController.java
+++ b/services/core/java/com/android/server/wm/PinnedTaskController.java
@@ -27,13 +27,16 @@
import android.content.ComponentName;
import android.content.pm.ParceledListSlice;
import android.content.res.Resources;
+import android.graphics.Insets;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
+import android.util.RotationUtils;
import android.util.Slog;
import android.view.IPinnedTaskListener;
+import android.view.Surface;
import android.view.SurfaceControl;
import android.window.PictureInPictureSurfaceTransaction;
@@ -208,7 +211,9 @@
}
mFreezingTaskConfig = true;
mDestRotatedBounds = new Rect(bounds);
- continueOrientationChange();
+ if (!mService.mAtmService.getTransitionController().isShellTransitionsEnabled()) {
+ continueOrientationChange();
+ }
}
/**
@@ -237,7 +242,8 @@
* rotation of display. The final surface matrix will be replaced by PiPTaskOrganizer after it
* receives the callback of fixed rotation completion.
*/
- void startSeamlessRotationIfNeeded(SurfaceControl.Transaction t) {
+ void startSeamlessRotationIfNeeded(SurfaceControl.Transaction t,
+ int oldRotation, int newRotation) {
final Rect bounds = mDestRotatedBounds;
final PictureInPictureSurfaceTransaction pipTx = mPipTransaction;
if (bounds == null && pipTx == null) {
@@ -280,6 +286,16 @@
? params.getSourceRectHint()
: null;
Slog.i(TAG, "Seamless rotation PiP bounds=" + bounds + " hintRect=" + sourceHintRect);
+ final int rotationDelta = RotationUtils.deltaRotation(oldRotation, newRotation);
+ // Adjust for display cutout if applicable.
+ if (sourceHintRect != null && rotationDelta == Surface.ROTATION_270) {
+ if (pinnedTask.getDisplayCutoutInsets() != null) {
+ final int rotationBackDelta = RotationUtils.deltaRotation(newRotation, oldRotation);
+ final Rect displayCutoutInsets = RotationUtils.rotateInsets(
+ Insets.of(pinnedTask.getDisplayCutoutInsets()), rotationBackDelta).toRect();
+ sourceHintRect.offset(displayCutoutInsets.left, displayCutoutInsets.top);
+ }
+ }
final Rect contentBounds = sourceHintRect != null && areaBounds.contains(sourceHintRect)
? sourceHintRect : areaBounds;
final int w = contentBounds.width();
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index 47129c2..ba1cf8a 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -125,6 +125,11 @@
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "Updated config=%s",
targetActivity.getConfiguration());
}
+ } else if (mDefaultTaskDisplayArea.getActivity(
+ ActivityRecord::occludesParent, false /* traverseTopToBottom */) == null) {
+ // Skip because none of above activities can occlude the target activity. The preload
+ // should be done silently in background without being visible.
+ return;
} else {
// Create the activity record. Because the activity is invisible, this doesn't really
// start the client.
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index bad12b5..0b463a9 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -1980,8 +1980,7 @@
*/
void ensureActivitiesVisible(ActivityRecord starting, int configChanges,
boolean preserveWindows, boolean notifyClients) {
- if (mTaskSupervisor.inActivityVisibilityUpdate()
- || mTaskSupervisor.isRootVisibilityUpdateDeferred()) {
+ if (mTaskSupervisor.inActivityVisibilityUpdate()) {
// Don't do recursive work.
return;
}
@@ -2213,16 +2212,17 @@
ensureActivitiesVisible(null, 0, false /* preserveWindows */);
resumeFocusedTasksTopActivities();
- notifyActivityPipModeChanged(r);
+ notifyActivityPipModeChanged(r.getTask(), r);
}
/**
* Notifies when an activity enters or leaves PIP mode.
*
+ * @param task the task of {@param r}
* @param r indicates the activity currently in PIP, can be null to indicate no activity is
* currently in PIP mode.
*/
- void notifyActivityPipModeChanged(@Nullable ActivityRecord r) {
+ void notifyActivityPipModeChanged(@NonNull Task task, @Nullable ActivityRecord r) {
final boolean inPip = r != null;
if (inPip) {
mService.getTaskChangeNotificationController().notifyActivityPinned(r);
@@ -2230,6 +2230,9 @@
mService.getTaskChangeNotificationController().notifyActivityUnpinned();
}
mWindowManager.mPolicy.setPipVisibilityLw(inPip);
+ mWmService.mTransactionFactory.get()
+ .setTrustedOverlay(task.getSurfaceControl(), inPip)
+ .apply();
}
void executeAppTransitionForAllDisplay() {
@@ -3437,14 +3440,6 @@
}, true /* traverseTopToBottom */);
}
- void cancelInitializingActivities() {
- forAllRootTasks(task -> {
- // We don't want to clear starting window for activities that aren't occluded
- // as we need to display their starting window until they are done initializing.
- task.forAllOccludedActivities(ActivityRecord::cancelInitializing);
- });
- }
-
Task anyTaskForId(int id) {
return anyTaskForId(id, MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE);
}
@@ -3524,11 +3519,6 @@
return task;
}
- ActivityRecord isInAnyTask(IBinder token) {
- final ActivityRecord r = ActivityRecord.forTokenLocked(token);
- return (r != null && r.isDescendantOf(this)) ? r : null;
- }
-
@VisibleForTesting
void getRunningTasks(int maxNum, List<ActivityManager.RunningTaskInfo> list,
int flags, int callingUid, ArraySet<Integer> profileIds) {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index f635a4c..5af242d 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -76,7 +76,6 @@
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
-import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_SHOWN;
import static com.android.server.wm.ActivityRecord.State.INITIALIZING;
import static com.android.server.wm.ActivityRecord.State.PAUSED;
import static com.android.server.wm.ActivityRecord.State.PAUSING;
@@ -150,6 +149,7 @@
import android.app.PictureInPictureParams;
import android.app.RemoteAction;
import android.app.TaskInfo;
+import android.app.WindowConfiguration;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
@@ -1203,7 +1203,7 @@
&& (newParent == null || !newParent.inPinnedWindowingMode())) {
// Notify if a task from the root pinned task is being removed
// (or moved depending on the mode).
- mRootWindowContainer.notifyActivityPipModeChanged(null);
+ mRootWindowContainer.notifyActivityPipModeChanged(this, null);
}
}
@@ -1429,14 +1429,6 @@
window.getBaseType() == TYPE_APPLICATION_STARTING) != null);
}
- ActivityRecord topActivityWithStartingWindow() {
- if (getParent() == null) {
- return null;
- }
- return getActivity((r) -> r.mStartingWindowState == STARTING_WINDOW_SHOWN
- && r.okToShowLocked());
- }
-
/**
* Return the number of running activities, and the number of non-finishing/initializing
* activities in the provided {@param reportOut} respectively.
@@ -2043,6 +2035,156 @@
}
}
+ void resolveLeafTaskOnlyOverrideConfigs(Configuration newParentConfig, Rect previousBounds) {
+ if (!isLeafTask()) {
+ return;
+ }
+
+ int windowingMode =
+ getResolvedOverrideConfiguration().windowConfiguration.getWindowingMode();
+ if (windowingMode == WINDOWING_MODE_UNDEFINED) {
+ windowingMode = newParentConfig.windowConfiguration.getWindowingMode();
+ }
+ // Commit the resolved windowing mode so the canSpecifyOrientation won't get the old
+ // mode that may cause the bounds to be miscalculated, e.g. letterboxed.
+ getConfiguration().windowConfiguration.setWindowingMode(windowingMode);
+ Rect outOverrideBounds = getResolvedOverrideConfiguration().windowConfiguration.getBounds();
+
+ if (windowingMode == WINDOWING_MODE_FULLSCREEN) {
+ // Use empty bounds to indicate "fill parent".
+ outOverrideBounds.setEmpty();
+ // The bounds for fullscreen mode shouldn't be adjusted by minimal size. Otherwise if
+ // the parent or display is smaller than the size, the content may be cropped.
+ return;
+ }
+
+ adjustForMinimalTaskDimensions(outOverrideBounds, previousBounds, newParentConfig);
+ if (windowingMode == WINDOWING_MODE_FREEFORM) {
+ computeFreeformBounds(outOverrideBounds, newParentConfig);
+ return;
+ }
+ }
+
+ void adjustForMinimalTaskDimensions(@NonNull Rect bounds, @NonNull Rect previousBounds,
+ @NonNull Configuration parentConfig) {
+ int minWidth = mMinWidth;
+ int minHeight = mMinHeight;
+ // If the task has no requested minimal size, we'd like to enforce a minimal size
+ // so that the user can not render the task fragment too small to manipulate. We don't need
+ // to do this for the root pinned task as the bounds are controlled by the system.
+ if (!inPinnedWindowingMode()) {
+ final int defaultMinSizeDp = mRootWindowContainer.mDefaultMinSizeOfResizeableTaskDp;
+ final float density = (float) parentConfig.densityDpi / DisplayMetrics.DENSITY_DEFAULT;
+ final int defaultMinSize = (int) (defaultMinSizeDp * density);
+
+ if (minWidth == INVALID_MIN_SIZE) {
+ minWidth = defaultMinSize;
+ }
+ if (minHeight == INVALID_MIN_SIZE) {
+ minHeight = defaultMinSize;
+ }
+ }
+ if (bounds.isEmpty()) {
+ // If inheriting parent bounds, check if parent bounds adhere to minimum size. If they
+ // do, we can just skip.
+ final Rect parentBounds = parentConfig.windowConfiguration.getBounds();
+ if (parentBounds.width() >= minWidth && parentBounds.height() >= minHeight) {
+ return;
+ }
+ bounds.set(parentBounds);
+ }
+ final boolean adjustWidth = minWidth > bounds.width();
+ final boolean adjustHeight = minHeight > bounds.height();
+ if (!(adjustWidth || adjustHeight)) {
+ return;
+ }
+
+ if (adjustWidth) {
+ if (!previousBounds.isEmpty() && bounds.right == previousBounds.right) {
+ bounds.left = bounds.right - minWidth;
+ } else {
+ // Either left bounds match, or neither match, or the previous bounds were
+ // fullscreen and we default to keeping left.
+ bounds.right = bounds.left + minWidth;
+ }
+ }
+ if (adjustHeight) {
+ if (!previousBounds.isEmpty() && bounds.bottom == previousBounds.bottom) {
+ bounds.top = bounds.bottom - minHeight;
+ } else {
+ // Either top bounds match, or neither match, or the previous bounds were
+ // fullscreen and we default to keeping top.
+ bounds.bottom = bounds.top + minHeight;
+ }
+ }
+ }
+
+ /** Computes bounds for {@link WindowConfiguration#WINDOWING_MODE_FREEFORM}. */
+ private void computeFreeformBounds(@NonNull Rect outBounds,
+ @NonNull Configuration newParentConfig) {
+ // by policy, make sure the window remains within parent somewhere
+ final float density =
+ ((float) newParentConfig.densityDpi) / DisplayMetrics.DENSITY_DEFAULT;
+ final Rect parentBounds =
+ new Rect(newParentConfig.windowConfiguration.getBounds());
+ final DisplayContent display = getDisplayContent();
+ if (display != null) {
+ // If a freeform window moves below system bar, there is no way to move it again
+ // by touch. Because its caption is covered by system bar. So we exclude them
+ // from root task bounds. and then caption will be shown inside stable area.
+ final Rect stableBounds = new Rect();
+ display.getStableRect(stableBounds);
+ parentBounds.intersect(stableBounds);
+ }
+
+ fitWithinBounds(outBounds, parentBounds,
+ (int) (density * WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP),
+ (int) (density * WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP));
+
+ // Prevent to overlap caption with stable insets.
+ final int offsetTop = parentBounds.top - outBounds.top;
+ if (offsetTop > 0) {
+ outBounds.offset(0, offsetTop);
+ }
+ }
+
+ /**
+ * Adjusts bounds to stay within root task bounds.
+ *
+ * Since bounds might be outside of root task bounds, this method tries to move the bounds in
+ * a way that keep them unchanged, but be contained within the root task bounds.
+ *
+ * @param bounds Bounds to be adjusted.
+ * @param rootTaskBounds Bounds within which the other bounds should remain.
+ * @param overlapPxX The amount of px required to be visible in the X dimension.
+ * @param overlapPxY The amount of px required to be visible in the Y dimension.
+ */
+ private static void fitWithinBounds(Rect bounds, Rect rootTaskBounds, int overlapPxX,
+ int overlapPxY) {
+ if (rootTaskBounds == null || rootTaskBounds.isEmpty() || rootTaskBounds.contains(bounds)) {
+ return;
+ }
+
+ // For each side of the parent (eg. left), check if the opposing side of the window (eg.
+ // right) is at least overlap pixels away. If less, offset the window by that difference.
+ int horizontalDiff = 0;
+ // If window is smaller than overlap, use it's smallest dimension instead
+ int overlapLR = Math.min(overlapPxX, bounds.width());
+ if (bounds.right < (rootTaskBounds.left + overlapLR)) {
+ horizontalDiff = overlapLR - (bounds.right - rootTaskBounds.left);
+ } else if (bounds.left > (rootTaskBounds.right - overlapLR)) {
+ horizontalDiff = -(overlapLR - (rootTaskBounds.right - bounds.left));
+ }
+ int verticalDiff = 0;
+ int overlapTB = Math.min(overlapPxY, bounds.width());
+ if (bounds.bottom < (rootTaskBounds.top + overlapTB)) {
+ verticalDiff = overlapTB - (bounds.bottom - rootTaskBounds.top);
+ } else if (bounds.top > (rootTaskBounds.bottom - overlapTB)) {
+ verticalDiff = -(overlapTB - (rootTaskBounds.bottom - bounds.top));
+ }
+ bounds.offset(horizontalDiff, verticalDiff);
+ }
+
/**
* Initializes a change transition. See {@link SurfaceFreezer} for more information.
*/
@@ -2840,25 +2982,6 @@
return top != activity ? top : null;
}
- /** Iterates through all occluded activities. */
- void forAllOccludedActivities(Consumer<ActivityRecord> handleOccludedActivity) {
- if (!shouldBeVisible(null /* starting */)) {
- // The root task is invisible so all activities are occluded.
- forAllActivities(handleOccludedActivity);
- return;
- }
- final ActivityRecord topOccluding = getOccludingActivityAbove(null);
- if (topOccluding == null) {
- // No activities are occluded.
- return;
- }
- // Invoke the callback on the activities behind the top occluding activity.
- forAllActivities(r -> {
- handleOccludedActivity.accept(r);
- return false;
- }, topOccluding, false /* includeBoundary */, true /* traverseTopToBottom */);
- }
-
@Override
public SurfaceControl.Builder makeAnimationLeash() {
return super.makeAnimationLeash().setMetadata(METADATA_TASK_ID, mTaskId);
@@ -3341,7 +3464,7 @@
info.positionInParent = getRelativePosition();
info.pictureInPictureParams = getPictureInPictureParams(top);
- info.displayCutoutInsets = getDisplayCutoutInsets(top);
+ info.displayCutoutInsets = top != null ? top.getDisplayCutoutInsets() : null;
info.topActivityInfo = mReuseActivitiesReport.top != null
? mReuseActivitiesReport.top.info
: null;
@@ -3377,16 +3500,15 @@
? null : new PictureInPictureParams(topMostActivity.pictureInPictureArgs);
}
- private Rect getDisplayCutoutInsets(Task top) {
- if (top == null || top.mDisplayContent == null
- || top.getDisplayInfo().displayCutout == null) return null;
- final WindowState w = top.getTopVisibleAppMainWindow();
+ Rect getDisplayCutoutInsets() {
+ if (mDisplayContent == null || getDisplayInfo().displayCutout == null) return null;
+ final WindowState w = getTopVisibleAppMainWindow();
final int displayCutoutMode = w == null
? WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
: w.getAttrs().layoutInDisplayCutoutMode;
return (displayCutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
|| displayCutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES)
- ? null : top.getDisplayInfo().displayCutout.getSafeInsets();
+ ? null : getDisplayInfo().displayCutout.getSafeInsets();
}
/**
@@ -3405,7 +3527,9 @@
StartingWindowInfo getStartingWindowInfo(ActivityRecord activity) {
final StartingWindowInfo info = new StartingWindowInfo();
info.taskInfo = getTaskInfo();
-
+ info.targetActivityInfo = info.taskInfo.topActivityInfo != null
+ && activity.info != info.taskInfo.topActivityInfo
+ ? activity.info : null;
info.isKeyguardOccluded =
mAtmService.mKeyguardController.isDisplayOccluded(DEFAULT_DISPLAY);
@@ -3569,6 +3693,8 @@
}
sb.append(" visible=");
sb.append(shouldBeVisible(null /* starting */));
+ sb.append(" visibleRequested=");
+ sb.append(isVisibleRequested());
sb.append(" mode=");
sb.append(windowingModeToString(getWindowingMode()));
sb.append(" translucent=");
@@ -4452,7 +4578,7 @@
: WINDOWING_MODE_FULLSCREEN;
}
if (currentMode == WINDOWING_MODE_PINNED) {
- mRootWindowContainer.notifyActivityPipModeChanged(null);
+ mRootWindowContainer.notifyActivityPipModeChanged(this, null);
}
if (likelyResolvedMode == WINDOWING_MODE_PINNED) {
// In the case that we've disabled affecting the SysUI flags as a part of seamlessly
@@ -4510,7 +4636,8 @@
// From fullscreen to PiP.
if (topActivity != null && currentMode == WINDOWING_MODE_FULLSCREEN
- && windowingMode == WINDOWING_MODE_PINNED) {
+ && windowingMode == WINDOWING_MODE_PINNED
+ && !mAtmService.getTransitionController().isShellTransitionsEnabled()) {
mDisplayContent.mPinnedTaskController
.deferOrientationChangeForEnteringPipFromFullScreenIfNeeded();
}
@@ -4518,10 +4645,8 @@
mAtmService.continueWindowLayout();
}
- if (!mTaskSupervisor.isRootVisibilityUpdateDeferred()) {
- mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
- mRootWindowContainer.resumeFocusedTasksTopActivities();
- }
+ mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
+ mRootWindowContainer.resumeFocusedTasksTopActivities();
}
void resumeNextFocusAfterReparent() {
@@ -4897,8 +5022,6 @@
return false;
}
- mRootWindowContainer.cancelInitializingActivities();
-
final ActivityRecord topActivity = topRunningActivity(true /* focusableOnly */);
if (topActivity == null) {
// There are no activities left in this task, let's look somewhere else.
@@ -5056,7 +5179,8 @@
// window manager to keep the previous window it had previously
// created, if it still had one.
Task prevTask = r.getTask();
- ActivityRecord prev = prevTask.topActivityWithStartingWindow();
+ ActivityRecord prev = prevTask.getActivity(
+ a -> a.mStartingData != null && a.okToShowLocked());
if (prev != null) {
// We don't want to reuse the previous starting preview if:
// (1) The current activity is in a different task.
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 59c3ffe..ba13546 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -75,6 +75,7 @@
import android.app.servertransaction.PauseActivityItem;
import android.app.servertransaction.ResumeActivityItem;
import android.content.res.Configuration;
+import android.graphics.Point;
import android.graphics.Rect;
import android.os.IBinder;
import android.os.RemoteException;
@@ -1475,6 +1476,12 @@
}
}
+ void onChildPositionChanged(WindowContainer child) {
+ super.onChildPositionChanged(child);
+
+ sendTaskFragmentInfoChanged();
+ }
+
void executeAppTransition(ActivityOptions options) {
// No app transition applied to the task fragment.
}
@@ -1512,8 +1519,10 @@
}
}
- if (isLeafTaskFragment()) {
- resolveLeafOnlyOverrideConfigs(newParentConfig, mTmpBounds /* previousBounds */);
+ final Task thisTask = asTask();
+ if (thisTask != null) {
+ thisTask.resolveLeafTaskOnlyOverrideConfigs(newParentConfig,
+ mTmpBounds /* previousBounds */);
}
computeConfigResourceOverrides(getResolvedOverrideConfiguration(), newParentConfig);
}
@@ -1551,100 +1560,6 @@
return getTask() != null ? getTask().mTaskId : INVALID_TASK_ID;
}
- private void resolveLeafOnlyOverrideConfigs(Configuration newParentConfig,
- Rect previousBounds) {
-
- int windowingMode =
- getResolvedOverrideConfiguration().windowConfiguration.getWindowingMode();
- if (windowingMode == WINDOWING_MODE_UNDEFINED) {
- windowingMode = newParentConfig.windowConfiguration.getWindowingMode();
- }
- // Commit the resolved windowing mode so the canSpecifyOrientation won't get the old
- // mode that may cause the bounds to be miscalculated, e.g. letterboxed.
- getConfiguration().windowConfiguration.setWindowingMode(windowingMode);
- Rect outOverrideBounds = getResolvedOverrideConfiguration().windowConfiguration.getBounds();
-
- if (windowingMode == WINDOWING_MODE_FULLSCREEN) {
- // Use empty bounds to indicate "fill parent".
- outOverrideBounds.setEmpty();
- // The bounds for fullscreen mode shouldn't be adjusted by minimal size. Otherwise if
- // the parent or display is smaller than the size, the content may be cropped.
- return;
- }
-
- adjustForMinimalTaskDimensions(outOverrideBounds, previousBounds, newParentConfig);
- if (windowingMode == WINDOWING_MODE_FREEFORM) {
- computeFreeformBounds(outOverrideBounds, newParentConfig);
- return;
- }
- }
-
- /** Computes bounds for {@link WindowConfiguration#WINDOWING_MODE_FREEFORM}. */
- private void computeFreeformBounds(@NonNull Rect outBounds,
- @NonNull Configuration newParentConfig) {
- // by policy, make sure the window remains within parent somewhere
- final float density =
- ((float) newParentConfig.densityDpi) / DisplayMetrics.DENSITY_DEFAULT;
- final Rect parentBounds =
- new Rect(newParentConfig.windowConfiguration.getBounds());
- final DisplayContent display = getDisplayContent();
- if (display != null) {
- // If a freeform window moves below system bar, there is no way to move it again
- // by touch. Because its caption is covered by system bar. So we exclude them
- // from root task bounds. and then caption will be shown inside stable area.
- final Rect stableBounds = new Rect();
- display.getStableRect(stableBounds);
- parentBounds.intersect(stableBounds);
- }
-
- fitWithinBounds(outBounds, parentBounds,
- (int) (density * WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP),
- (int) (density * WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP));
-
- // Prevent to overlap caption with stable insets.
- final int offsetTop = parentBounds.top - outBounds.top;
- if (offsetTop > 0) {
- outBounds.offset(0, offsetTop);
- }
- }
-
- /**
- * Adjusts bounds to stay within root task bounds.
- *
- * Since bounds might be outside of root task bounds, this method tries to move the bounds in
- * a way that keep them unchanged, but be contained within the root task bounds.
- *
- * @param bounds Bounds to be adjusted.
- * @param rootTaskBounds Bounds within which the other bounds should remain.
- * @param overlapPxX The amount of px required to be visible in the X dimension.
- * @param overlapPxY The amount of px required to be visible in the Y dimension.
- */
- private static void fitWithinBounds(Rect bounds, Rect rootTaskBounds, int overlapPxX,
- int overlapPxY) {
- if (rootTaskBounds == null || rootTaskBounds.isEmpty() || rootTaskBounds.contains(bounds)) {
- return;
- }
-
- // For each side of the parent (eg. left), check if the opposing side of the window (eg.
- // right) is at least overlap pixels away. If less, offset the window by that difference.
- int horizontalDiff = 0;
- // If window is smaller than overlap, use it's smallest dimension instead
- int overlapLR = Math.min(overlapPxX, bounds.width());
- if (bounds.right < (rootTaskBounds.left + overlapLR)) {
- horizontalDiff = overlapLR - (bounds.right - rootTaskBounds.left);
- } else if (bounds.left > (rootTaskBounds.right - overlapLR)) {
- horizontalDiff = -(overlapLR - (rootTaskBounds.right - bounds.left));
- }
- int verticalDiff = 0;
- int overlapTB = Math.min(overlapPxY, bounds.width());
- if (bounds.bottom < (rootTaskBounds.top + overlapTB)) {
- verticalDiff = overlapTB - (bounds.bottom - rootTaskBounds.top);
- } else if (bounds.top > (rootTaskBounds.bottom - overlapTB)) {
- verticalDiff = -(overlapTB - (rootTaskBounds.bottom - bounds.top));
- }
- bounds.offset(horizontalDiff, verticalDiff);
- }
-
/**
* Ensures all visible activities at or below the input activity have the right configuration.
*/
@@ -1652,60 +1567,6 @@
mEnsureVisibleActivitiesConfigHelper.process(start, preserveWindow);
}
- void adjustForMinimalTaskDimensions(@NonNull Rect bounds, @NonNull Rect previousBounds,
- @NonNull Configuration parentConfig) {
- int minWidth = mMinWidth;
- int minHeight = mMinHeight;
- // If the task has no requested minimal size, we'd like to enforce a minimal size
- // so that the user can not render the task fragment too small to manipulate. We don't need
- // to do this for the root pinned task as the bounds are controlled by the system.
- if (!inPinnedWindowingMode()) {
- final int defaultMinSizeDp = mRootWindowContainer.mDefaultMinSizeOfResizeableTaskDp;
- final float density = (float) parentConfig.densityDpi / DisplayMetrics.DENSITY_DEFAULT;
- final int defaultMinSize = (int) (defaultMinSizeDp * density);
-
- if (minWidth == INVALID_MIN_SIZE) {
- minWidth = defaultMinSize;
- }
- if (minHeight == INVALID_MIN_SIZE) {
- minHeight = defaultMinSize;
- }
- }
- if (bounds.isEmpty()) {
- // If inheriting parent bounds, check if parent bounds adhere to minimum size. If they
- // do, we can just skip.
- final Rect parentBounds = parentConfig.windowConfiguration.getBounds();
- if (parentBounds.width() >= minWidth && parentBounds.height() >= minHeight) {
- return;
- }
- bounds.set(parentBounds);
- }
- final boolean adjustWidth = minWidth > bounds.width();
- final boolean adjustHeight = minHeight > bounds.height();
- if (!(adjustWidth || adjustHeight)) {
- return;
- }
-
- if (adjustWidth) {
- if (!previousBounds.isEmpty() && bounds.right == previousBounds.right) {
- bounds.left = bounds.right - minWidth;
- } else {
- // Either left bounds match, or neither match, or the previous bounds were
- // fullscreen and we default to keeping left.
- bounds.right = bounds.left + minWidth;
- }
- }
- if (adjustHeight) {
- if (!previousBounds.isEmpty() && bounds.bottom == previousBounds.bottom) {
- bounds.top = bounds.bottom - minHeight;
- } else {
- // Either top bounds match, or neither match, or the previous bounds were
- // fullscreen and we default to keeping top.
- bounds.bottom = bounds.top + minHeight;
- }
- }
- }
-
void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
@NonNull Configuration parentConfig) {
computeConfigResourceOverrides(inOutConfig, parentConfig, null /* overrideDisplayInfo */,
@@ -2027,13 +1888,17 @@
childActivities.add(wc.asActivityRecord().appToken);
}
}
+ final Point positionInParent = new Point();
+ getRelativePosition(positionInParent);
return new TaskFragmentInfo(
mFragmentToken,
mRemoteToken.toWindowContainerToken(),
getConfiguration(),
getChildCount() == 0,
+ hasRunningActivity(this),
isVisible(),
- childActivities);
+ childActivities,
+ positionInParent);
}
@Nullable
diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
index 496ecde..4843e5a 100644
--- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
@@ -16,6 +16,8 @@
package com.android.server.wm;
+import static android.window.TaskFragmentOrganizer.putExceptionInBundle;
+
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
import static com.android.server.wm.WindowOrganizerController.configurationsAreEqualForOrganizer;
@@ -23,6 +25,7 @@
import android.annotation.Nullable;
import android.content.res.Configuration;
import android.os.Binder;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.ArrayMap;
@@ -190,6 +193,16 @@
Slog.e(TAG, "Exception sending onTaskFragmentParentInfoChanged callback", e);
}
}
+
+ void onTaskFragmentError(ITaskFragmentOrganizer organizer, IBinder errorCallbackToken,
+ Throwable exception) {
+ final Bundle exceptionBundle = putExceptionInBundle(exception);
+ try {
+ organizer.onTaskFragmentError(errorCallbackToken, exceptionBundle);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Exception sending onTaskFragmentError callback", e);
+ }
+ }
}
@Override
@@ -289,6 +302,14 @@
state.removeTaskFragment(taskFragment);
}
+ void onTaskFragmentError(ITaskFragmentOrganizer organizer, IBinder errorCallbackToken,
+ Throwable exception) {
+ validateAndGetState(organizer);
+ PendingTaskFragmentEvent pendingEvent = new PendingTaskFragmentEvent(organizer,
+ errorCallbackToken, exception, PendingTaskFragmentEvent.EVENT_ERROR);
+ mPendingTaskFragmentEvents.add(pendingEvent);
+ }
+
private void removeOrganizer(ITaskFragmentOrganizer organizer) {
final TaskFragmentOrganizerState state = validateAndGetState(organizer);
// remove all of the children of the organized TaskFragment
@@ -321,25 +342,45 @@
static final int EVENT_VANISHED = 1;
static final int EVENT_INFO_CHANGED = 2;
static final int EVENT_PARENT_INFO_CHANGED = 3;
+ static final int EVENT_ERROR = 4;
@IntDef(prefix = "EVENT_", value = {
EVENT_APPEARED,
EVENT_VANISHED,
EVENT_INFO_CHANGED,
- EVENT_PARENT_INFO_CHANGED
+ EVENT_PARENT_INFO_CHANGED,
+ EVENT_ERROR
})
@Retention(RetentionPolicy.SOURCE)
public @interface EventType {}
@EventType
- final int mEventType;
- final TaskFragment mTaskFragment;
- final ITaskFragmentOrganizer mTaskFragmentOrg;
+ private final int mEventType;
+ private final ITaskFragmentOrganizer mTaskFragmentOrg;
+ private final TaskFragment mTaskFragment;
+ private final IBinder mErrorCallback;
+ private final Throwable mException;
- PendingTaskFragmentEvent(TaskFragment taskFragment, ITaskFragmentOrganizer taskFragmentOrg,
+ private PendingTaskFragmentEvent(TaskFragment taskFragment,
+ ITaskFragmentOrganizer taskFragmentOrg, @EventType int eventType) {
+ this(taskFragment, taskFragmentOrg, null /* errorCallback */,
+ null /* exception */, eventType);
+
+ }
+
+ private PendingTaskFragmentEvent(ITaskFragmentOrganizer taskFragmentOrg,
+ IBinder errorCallback, Throwable exception, @EventType int eventType) {
+ this(null /* taskFragment */, taskFragmentOrg, errorCallback, exception,
+ eventType);
+ }
+
+ private PendingTaskFragmentEvent(TaskFragment taskFragment,
+ ITaskFragmentOrganizer taskFragmentOrg, IBinder errorCallback, Throwable exception,
@EventType int eventType) {
mTaskFragment = taskFragment;
mTaskFragmentOrg = taskFragmentOrg;
+ mErrorCallback = errorCallback;
+ mException = exception;
mEventType = eventType;
}
@@ -407,6 +448,10 @@
break;
case PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED:
state.onTaskFragmentParentInfoChanged(taskFragmentOrg, taskFragment);
+ break;
+ case PendingTaskFragmentEvent.EVENT_ERROR:
+ state.onTaskFragmentError(taskFragmentOrg, event.mErrorCallback,
+ event.mException);
}
}
mPendingTaskFragmentEvents.clear();
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 1ac1666..2c17b73 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -46,11 +46,13 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
+import android.os.IRemoteCallback;
import android.os.RemoteException;
import android.os.SystemClock;
import android.util.ArrayMap;
@@ -65,6 +67,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.ProtoLogGroup;
import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.util.function.pooled.PooledLambda;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -130,7 +133,10 @@
/** The final animation targets derived from participants after promotion. */
private ArraySet<WindowContainer> mTargets = null;
+ /** Custom activity-level animation options and callbacks. */
private TransitionInfo.AnimationOptions mOverrideOptions;
+ private IRemoteCallback mClientAnimationStartCallback = null;
+ private IRemoteCallback mClientAnimationFinishCallback = null;
private @TransitionState int mState = STATE_COLLECTING;
private final ReadyTracker mReadyTracker = new ReadyTracker();
@@ -226,13 +232,26 @@
mChanges.get(wc).mExistenceChanged = true;
}
+ private void sendRemoteCallback(@Nullable IRemoteCallback callback) {
+ if (callback == null) return;
+ mController.mAtm.mH.sendMessage(PooledLambda.obtainMessage(cb -> {
+ try {
+ cb.sendResult(null);
+ } catch (RemoteException e) { }
+ }, callback));
+ }
+
/**
* Set animation options for collecting transition by ActivityRecord.
* @param options AnimationOptions captured from ActivityOptions
*/
- void setOverrideAnimation(TransitionInfo.AnimationOptions options) {
+ void setOverrideAnimation(TransitionInfo.AnimationOptions options,
+ @Nullable IRemoteCallback startCallback, @Nullable IRemoteCallback finishCallback) {
if (mSyncId < 0) return;
mOverrideOptions = options;
+ sendRemoteCallback(mClientAnimationStartCallback);
+ mClientAnimationStartCallback = startCallback;
+ mClientAnimationFinishCallback = finishCallback;
}
/**
@@ -352,7 +371,7 @@
final WallpaperWindowToken wt = mParticipants.valueAt(i).asWallpaperToken();
if (wt != null && !wt.isVisibleRequested()) {
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
- " Commit wallpaper becoming invisible: %s", ar);
+ " Commit wallpaper becoming invisible: %s", wt);
wt.commitVisibility(false /* visible */);
}
}
@@ -363,6 +382,8 @@
.scheduleProcessStoppingAndFinishingActivitiesIfNeeded();
}
+ sendRemoteCallback(mClientAnimationFinishCallback);
+
legacyRestoreNavigationBarFromApp();
}
@@ -426,6 +447,9 @@
reportStartReasonsToLogger();
+ // The callback is only populated for custom activity-level client animations
+ sendRemoteCallback(mClientAnimationStartCallback);
+
// Manually show any activities that are visibleRequested. This is needed to properly
// support simultaneous animation queueing/merging. Specifically, if transition A makes
// an activity invisible, it's finishTransaction (which is applied *after* the animation)
@@ -437,6 +461,25 @@
final ActivityRecord ar = mParticipants.valueAt(i).asActivityRecord();
if (ar == null || !ar.mVisibleRequested) continue;
transaction.show(ar.getSurfaceControl());
+
+ // Also manually show any non-reported parents. This is necessary in a few cases
+ // where a task is NOT organized but had its visibility changed within its direct
+ // parent. An example of this is if an alternate home leaf-task HB is started atop the
+ // normal home leaf-task HA: these are both in the Home root-task HR, so there will be a
+ // transition containing HA and HB where HA surface is hidden. If a standard task SA is
+ // launched on top, then HB finishes, no transition will happen since neither home is
+ // visible. When SA finishes, the transition contains HR rather than HA. Since home
+ // leaf-tasks are NOT organized, HA won't be in the transition and thus its surface
+ // wouldn't be shown. Just show is safe here since all other properties will have
+ // already been reset by the original hiding-transition's finishTransaction (we can't
+ // show in the finishTransaction because by then the activity doesn't hide until
+ // surface placement).
+ for (WindowContainer p = ar.getParent(); p != null && !mTargets.contains(p);
+ p = p.getParent()) {
+ if (p.getSurfaceControl() != null) {
+ transaction.show(p.getSurfaceControl());
+ }
+ }
}
mStartTransaction = transaction;
@@ -808,7 +851,11 @@
// of participants that should always be reported even if they aren't top.
for (WindowContainer wc : participants) {
// Don't include detached windows.
- if (!wc.isAttached()) continue;
+ if (!wc.isAttached()) {
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
+ " Rejecting as detached: %s", wc);
+ continue;
+ }
final ChangeInfo changeInfo = changes.get(wc);
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 16d2278..44dee4d 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -30,6 +30,7 @@
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.os.IBinder;
+import android.os.IRemoteCallback;
import android.os.RemoteException;
import android.os.SystemClock;
import android.util.Slog;
@@ -277,9 +278,10 @@
}
/** @see Transition#setOverrideAnimation */
- void setOverrideAnimation(TransitionInfo.AnimationOptions options) {
+ void setOverrideAnimation(TransitionInfo.AnimationOptions options,
+ @Nullable IRemoteCallback startCallback, @Nullable IRemoteCallback finishCallback) {
if (mCollectingTransition == null) return;
- mCollectingTransition.setOverrideAnimation(options);
+ mCollectingTransition.setOverrideAnimation(options, startCallback, finishCallback);
}
/** @see Transition#setReady */
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 5bc4d49..2a271ef 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -122,16 +122,6 @@
*/
void onWindowsForAccessibilityChanged(boolean forceSend, int topFocusedDisplayId,
IBinder topFocusedWindowToken, @NonNull List<WindowInfo> windows);
-
- /**
- * Called when the display is reparented and becomes an embedded
- * display. The {@link WindowsForAccessibilityCallback} with the given embedded
- * display will be replaced by the {@link WindowsForAccessibilityCallback}
- * associated with its parent display at the same time.
- *
- * @param embeddedDisplayId The embedded display Id.
- */
- void onDisplayReparented(int embeddedDisplayId);
}
/**
@@ -375,9 +365,8 @@
*
* @param displayId The logical display id.
* @param callback The callback.
- * @return {@code false} if display id is not valid.
*/
- public abstract boolean setWindowsForAccessibilityCallback(int displayId,
+ public abstract void setWindowsForAccessibilityCallback(int displayId,
WindowsForAccessibilityCallback callback);
/**
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 16e28d4..9cb5126 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -7455,20 +7455,18 @@
}
@Override
- public boolean setWindowsForAccessibilityCallback(int displayId,
+ public void setWindowsForAccessibilityCallback(int displayId,
WindowsForAccessibilityCallback callback) {
synchronized (mGlobalLock) {
if (mAccessibilityController == null) {
mAccessibilityController = new AccessibilityController(
WindowManagerService.this);
}
- final boolean result =
- mAccessibilityController.setWindowsForAccessibilityCallback(
+ mAccessibilityController.setWindowsForAccessibilityCallback(
displayId, callback);
if (!mAccessibilityController.hasCallbacks()) {
mAccessibilityController = null;
}
- return result;
}
}
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 520a104..1788a52 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
+import static android.app.ActivityManager.isStartResultSuccessful;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT;
@@ -44,6 +45,7 @@
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.WindowConfiguration;
+import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
@@ -319,7 +321,6 @@
int effects = 0;
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Apply window transaction, syncId=%d", syncId);
mService.deferWindowLayout();
- mService.mTaskSupervisor.setDeferRootVisibilityUpdate(true /* deferUpdate */);
try {
if (transition != null) {
// First check if we have a display rotation transition and if so, update it.
@@ -370,7 +371,8 @@
final boolean isInLockTaskMode = mService.isInLockTaskMode();
for (int i = 0; i < hopSize; ++i) {
effects |= applyHierarchyOp(hops.get(i), effects, syncId, transition,
- isInLockTaskMode, caller);
+ isInLockTaskMode, caller, t.getErrorCallbackToken(),
+ t.getTaskFragmentOrganizer());
}
}
// Queue-up bounds-change transactions for tasks which are now organized. Do
@@ -408,7 +410,6 @@
task.setMainWindowSizeChangeTransaction(sft);
}
if ((effects & TRANSACT_EFFECTS_LIFECYCLE) != 0) {
- mService.mTaskSupervisor.setDeferRootVisibilityUpdate(false /* deferUpdate */);
// Already calls ensureActivityConfig
mService.mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
mService.mRootWindowContainer.resumeFocusedTasksTopActivities();
@@ -430,7 +431,6 @@
mService.addWindowLayoutReasons(LAYOUT_REASON_CONFIG_CHANGED);
}
} finally {
- mService.mTaskSupervisor.setDeferRootVisibilityUpdate(false /* deferUpdate */);
mService.continueWindowLayout();
}
}
@@ -528,7 +528,8 @@
private int applyHierarchyOp(WindowContainerTransaction.HierarchyOp hop, int effects,
int syncId, @Nullable Transition transition, boolean isInLockTaskMode,
- @Nullable CallerInfo caller) {
+ @Nullable CallerInfo caller, @Nullable IBinder errorCallbackToken,
+ @Nullable ITaskFragmentOrganizer organizer) {
final int type = hop.getType();
switch (type) {
case HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT: {
@@ -655,7 +656,7 @@
case HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT:
final TaskFragmentCreationParams taskFragmentCreationOptions =
hop.getTaskFragmentCreationOptions();
- createTaskFragment(taskFragmentCreationOptions);
+ createTaskFragment(taskFragmentCreationOptions, errorCallbackToken);
break;
case HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT:
wc = WindowContainer.fromBinder(hop.getContainer());
@@ -668,28 +669,37 @@
throw new IllegalArgumentException(
"Can only delete organized TaskFragment, but not Task.");
}
- deleteTaskFragment(taskFragment);
+ deleteTaskFragment(taskFragment, errorCallbackToken);
break;
case HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT:
fragmentToken = hop.getContainer();
if (!mLaunchTaskFragments.containsKey(fragmentToken)) {
- throw new IllegalArgumentException(
+ final Throwable exception = new IllegalArgumentException(
"Not allowed to operate with invalid fragment token");
+ sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
+ break;
}
final Intent activityIntent = hop.getActivityIntent();
final Bundle activityOptions = hop.getLaunchOptions();
- mService.getActivityStartController()
- .startActivityInTaskFragment(mLaunchTaskFragments.get(fragmentToken),
- activityIntent, activityOptions);
- // TODO(b/189385246) : report the failure back to the organizer if the activity
- // start failed
+ final TaskFragment tf = mLaunchTaskFragments.get(fragmentToken);
+ final int result = mService.getActivityStartController()
+ .startActivityInTaskFragment(tf, activityIntent, activityOptions,
+ hop.getCallingActivity());
+ if (!isStartResultSuccessful(result)) {
+ final Throwable exception =
+ new ActivityNotFoundException("start activity in taskFragment failed");
+ sendTaskFragmentOperationFailure(tf.getTaskFragmentOrganizer(),
+ errorCallbackToken, exception);
+ }
break;
case HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT:
fragmentToken = hop.getNewParent();
final ActivityRecord activity = ActivityRecord.forTokenLocked(hop.getContainer());
if (!mLaunchTaskFragments.containsKey(fragmentToken) || activity == null) {
- throw new IllegalArgumentException(
+ final Throwable exception = new IllegalArgumentException(
"Not allowed to operate with invalid fragment token or activity.");
+ sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
+ break;
}
activity.reparent(mLaunchTaskFragments.get(fragmentToken), POSITION_TOP);
break;
@@ -703,7 +713,7 @@
+ oldParent);
break;
}
- reparentTaskFragment(oldParent, newParent);
+ reparentTaskFragment(oldParent, newParent, errorCallbackToken);
break;
}
return effects;
@@ -878,8 +888,8 @@
}
private void sanitizeWindowContainer(WindowContainer wc) {
- if (!(wc instanceof Task) && !(wc instanceof DisplayArea)) {
- throw new RuntimeException("Invalid token in task or displayArea transaction");
+ if (!(wc instanceof TaskFragment) && !(wc instanceof DisplayArea)) {
+ throw new RuntimeException("Invalid token in task fragment or displayArea transaction");
}
}
@@ -1079,37 +1089,50 @@
}
}
- void createTaskFragment(@NonNull TaskFragmentCreationParams creationParams) {
+ void createTaskFragment(@NonNull TaskFragmentCreationParams creationParams,
+ @Nullable IBinder errorCallbackToken) {
final ActivityRecord ownerActivity =
ActivityRecord.forTokenLocked(creationParams.getOwnerToken());
if (ownerActivity == null || ownerActivity.getTask() == null) {
- // TODO(b/189385246) : report the failure back to the organizer
+ final Throwable exception =
+ new IllegalArgumentException("Not allowed to operate with invalid ownerToken");
+ sendTaskFragmentOperationFailure(creationParams.getOrganizer(), errorCallbackToken,
+ exception);
return;
}
// The ownerActivity has to belong to the same app as the root Activity of the target Task.
final ActivityRecord rootActivity = ownerActivity.getTask().getRootActivity();
if (rootActivity.getUid() != ownerActivity.getUid()) {
- // TODO(b/189385246) : report the failure back to the organizer
+ final Throwable exception =
+ new IllegalArgumentException("Not allowed to operate with the ownerToken while "
+ + "the root activity of the target task belong to the different app");
+ sendTaskFragmentOperationFailure(creationParams.getOrganizer(), errorCallbackToken,
+ exception);
return;
}
final TaskFragment taskFragment = new TaskFragment(mService,
creationParams.getFragmentToken(), true /* createdByOrganizer */);
+ // Set task fragment organizer immediately, since it might have to be notified about further
+ // actions.
+ taskFragment.setTaskFragmentOrganizer(
+ creationParams.getOrganizer(), ownerActivity.getPid());
ownerActivity.getTask().addChild(taskFragment, POSITION_TOP);
taskFragment.setWindowingMode(creationParams.getWindowingMode());
taskFragment.setBounds(creationParams.getInitialBounds());
- taskFragment.setTaskFragmentOrganizer(
- creationParams.getOrganizer(), ownerActivity.getPid());
mLaunchTaskFragments.put(creationParams.getFragmentToken(), taskFragment);
}
void reparentTaskFragment(@NonNull WindowContainer oldParent,
- @Nullable WindowContainer newParent) {
+ @Nullable WindowContainer newParent, @Nullable IBinder errorCallbackToken) {
WindowContainer parent = newParent;
if (parent == null && oldParent.asTaskFragment() != null) {
parent = oldParent.asTaskFragment().getTask();
}
if (parent == null) {
- // TODO(b/189385246) : report the failure back to the organizer
+ final Throwable exception =
+ new IllegalArgumentException("Not allowed to operate with invalid container");
+ sendTaskFragmentOperationFailure(oldParent.asTaskFragment().getTaskFragmentOrganizer(),
+ errorCallbackToken, exception);
return;
}
while (oldParent.hasChild()) {
@@ -1117,11 +1140,16 @@
}
}
- void deleteTaskFragment(@NonNull TaskFragment taskFragment) {
+ void deleteTaskFragment(@NonNull TaskFragment taskFragment,
+ @Nullable IBinder errorCallbackToken) {
final int index = mLaunchTaskFragments.indexOfValue(taskFragment);
if (index < 0) {
- throw new IllegalArgumentException(
- "Not allowed to operate with invalid taskFragment");
+ final Throwable exception =
+ new IllegalArgumentException("Not allowed to operate with invalid "
+ + "taskFragment");
+ sendTaskFragmentOperationFailure(taskFragment.getTaskFragmentOrganizer(),
+ errorCallbackToken, exception);
+ return;
}
mLaunchTaskFragments.removeAt(index);
taskFragment.removeImmediately();
@@ -1136,4 +1164,13 @@
mUid = Binder.getCallingUid();
}
}
+
+ void sendTaskFragmentOperationFailure(@NonNull ITaskFragmentOrganizer organizer,
+ @Nullable IBinder errorCallbackToken, @NonNull Throwable exception) {
+ if (organizer == null) {
+ throw new IllegalArgumentException("Not allowed to operate with invalid organizer");
+ }
+ mService.mTaskFragmentOrganizerController
+ .onTaskFragmentError(organizer, errorCallbackToken, exception);
+ }
}
diff --git a/services/core/jni/com_android_server_biometrics_SurfaceToNativeHandleConverter.cpp b/services/core/jni/com_android_server_biometrics_SurfaceToNativeHandleConverter.cpp
index e994c03..d3d532b 100644
--- a/services/core/jni/com_android_server_biometrics_SurfaceToNativeHandleConverter.cpp
+++ b/services/core/jni/com_android_server_biometrics_SurfaceToNativeHandleConverter.cpp
@@ -16,18 +16,19 @@
#define LOG_TAG "SurfaceToNativeHandleConverter"
-#include <nativehelper/JNIHelp.h>
-#include "jni.h"
-
-#include <android/native_window_jni.h>
#include <android_os_NativeHandle.h>
+#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/android_view_Surface.h>
#include <gui/IGraphicBufferProducer.h>
#include <gui/Surface.h>
#include <gui/bufferqueue/1.0/WGraphicBufferProducer.h>
+#include <utils/Log.h>
+
+#include "jni.h"
namespace android {
-
namespace {
+
constexpr int WINDOW_HAL_TOKEN_SIZE_MAX = 256;
native_handle_t* convertHalTokenToNativeHandle(const HalToken& halToken) {
@@ -54,33 +55,73 @@
memcpy(&(nh->data[1]), halToken.data(), nhDataByteSize);
return nh;
}
-} // namespace
-using ::android::sp;
+HalToken convertNativeHandleToHalToken(native_handle_t* handle) {
+ int size = handle->data[0];
+ auto data = reinterpret_cast<uint8_t*>(&handle->data[1]);
+ HalToken halToken;
+ halToken.setToExternal(data, size);
+ return halToken;
+}
-static jobject convertSurfaceToNativeHandle(JNIEnv* env, jobject /* clazz */,
- jobject previewSurface) {
- if (previewSurface == nullptr) {
+jobject acquireSurfaceHandle(JNIEnv* env, jobject /* clazz */, jobject jSurface) {
+ ALOGD("%s", __func__);
+ if (jSurface == nullptr) {
+ ALOGE("%s: jSurface is null", __func__);
return nullptr;
}
- ANativeWindow* previewAnw = ANativeWindow_fromSurface(env, previewSurface);
- sp<Surface> surface = static_cast<Surface*>(previewAnw);
+
+ sp<Surface> surface = android_view_Surface_getSurface(env, jSurface);
+ if (surface == nullptr) {
+ ALOGE("%s: surface is null", __func__);
+ return nullptr;
+ }
+
sp<IGraphicBufferProducer> igbp = surface->getIGraphicBufferProducer();
sp<HGraphicBufferProducer> hgbp = new TWGraphicBufferProducer<HGraphicBufferProducer>(igbp);
+ // The HAL token will be closed in releaseSurfaceHandle.
HalToken halToken;
createHalToken(hgbp, &halToken);
+
native_handle_t* native_handle = convertHalTokenToNativeHandle(halToken);
- return JNativeHandle::MakeJavaNativeHandleObj(env, native_handle);
+ if (native_handle == nullptr) {
+ ALOGE("%s: native_handle is null", __func__);
+ return nullptr;
+ }
+ jobject jHandle = JNativeHandle::MakeJavaNativeHandleObj(env, native_handle);
+ native_handle_delete(native_handle);
+
+ return jHandle;
}
-static const JNINativeMethod method_table[] = {
- {"convertSurfaceToNativeHandle", "(Landroid/view/Surface;)Landroid/os/NativeHandle;",
- reinterpret_cast<void*>(convertSurfaceToNativeHandle)},
+void releaseSurfaceHandle(JNIEnv* env, jobject /* clazz */, jobject jHandle) {
+ ALOGD("%s", __func__);
+ // Creates a native handle from a Java handle. We must call native_handle_delete when we're done
+ // with it because we created it, but we shouldn't call native_handle_close because we don't own
+ // the underlying FDs.
+ native_handle_t* handle =
+ JNativeHandle::MakeCppNativeHandle(env, jHandle, nullptr /* storage */);
+ if (handle == nullptr) {
+ ALOGE("%s: handle is null", __func__);
+ return;
+ }
+
+ HalToken token = convertNativeHandleToHalToken(handle);
+ ALOGD("%s: deleteHalToken, success: %d", __func__, deleteHalToken(token));
+ ALOGD("%s: native_handle_delete, success: %d", __func__, !native_handle_delete(handle));
+}
+
+const JNINativeMethod method_table[] = {
+ {"acquireSurfaceHandle", "(Landroid/view/Surface;)Landroid/os/NativeHandle;",
+ reinterpret_cast<void*>(acquireSurfaceHandle)},
+ {"releaseSurfaceHandle", "(Landroid/os/NativeHandle;)V",
+ reinterpret_cast<void*>(releaseSurfaceHandle)},
};
+} // namespace
int register_android_server_FaceService(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "com/android/server/biometrics/sensors/face/FaceService",
- method_table, NELEM(method_table));
+ return AndroidRuntime::
+ registerNativeMethods(env, "com/android/server/biometrics/sensors/face/FaceService",
+ method_table, NELEM(method_table));
}
-
-}; // namespace android
+} // namespace android
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 193d92a..7efe9d4 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -4567,7 +4567,9 @@
public PasswordMetrics getPasswordMinimumMetrics(@UserIdInt int userHandle,
boolean deviceWideOnly) {
final CallerIdentity caller = getCallerIdentity();
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle)
+ && (isSystemUid(caller) || hasCallingOrSelfPermission(
+ permission.SET_INITIAL_LOCK)));
return getPasswordMinimumMetricsUnchecked(userHandle, deviceWideOnly);
}
diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
index e3e2708..fdf23d3 100644
--- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
+++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
@@ -59,9 +59,7 @@
private static final boolean DEBUG = Log.isLoggable(LOG_TAG, Log.DEBUG);
- private static final long BG_PROCESS_PERIOD = DEBUG
- ? TimeUnit.MINUTES.toMillis(1)
- : TimeUnit.DAYS.toMillis(1);
+ private static final long BG_PROCESS_PERIOD = TimeUnit.DAYS.toMillis(1); // every 1 day.
private IProfCollectd mIProfcollect;
private static ProfcollectForwardingService sSelfService;
@@ -286,6 +284,11 @@
updateEngine.bind(new UpdateEngineCallback() {
@Override
public void onStatusUpdate(int status, float percent) {
+ if (DEBUG) {
+ Log.d(LOG_TAG, "Received OTA status update, status: " + status + ", percent: "
+ + percent);
+ }
+
if (status == UpdateEngine.UpdateStatusConstants.UPDATED_NEED_REBOOT) {
packProfileReport();
}
diff --git a/services/tests/PackageManager/packageinstaller/Android.bp b/services/tests/PackageManager/packageinstaller/Android.bp
new file mode 100644
index 0000000..35d754b
--- /dev/null
+++ b/services/tests/PackageManager/packageinstaller/Android.bp
@@ -0,0 +1,39 @@
+// 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 {
+ // 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"],
+}
+
+android_test {
+ name: "PackageInstallerTests",
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.kt",
+ ],
+ static_libs: [
+ "androidx.test.rules",
+ "androidx.test.runner",
+ "junit",
+ "kotlin-test",
+ "truth-prebuilt",
+ ],
+ platform_apis: true,
+ test_suites: ["device-tests"],
+}
diff --git a/services/tests/PackageManager/packageinstaller/AndroidManifest.xml b/services/tests/PackageManager/packageinstaller/AndroidManifest.xml
new file mode 100644
index 0000000..d706258
--- /dev/null
+++ b/services/tests/PackageManager/packageinstaller/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?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.packageinstaller.test">
+
+ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.packageinstaller.test"
+ />
+
+</manifest>
+
diff --git a/services/tests/PackageManager/packageinstaller/AndroidTest.xml b/services/tests/PackageManager/packageinstaller/AndroidTest.xml
new file mode 100644
index 0000000..c39285ff
--- /dev/null
+++ b/services/tests/PackageManager/packageinstaller/AndroidTest.xml
@@ -0,0 +1,29 @@
+<?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.
+ -->
+
+<configuration description="Test module config for PackageInstallerTests">
+ <option name="test-tag" value="PackageInstallerTests" />
+
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="PackageInstallerTests.apk" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+ <option name="package" value="com.android.packageinstaller.test" />
+ </test>
+</configuration>
diff --git a/services/tests/PackageManager/packageinstaller/src/com/android/packageinstaller/test/ExportedComponentTest.kt b/services/tests/PackageManager/packageinstaller/src/com/android/packageinstaller/test/ExportedComponentTest.kt
new file mode 100644
index 0000000..d7d2726
--- /dev/null
+++ b/services/tests/PackageManager/packageinstaller/src/com/android/packageinstaller/test/ExportedComponentTest.kt
@@ -0,0 +1,50 @@
+/*
+ * 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.packageinstaller.test
+
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.net.Uri
+import androidx.test.InstrumentationRegistry
+import com.google.common.truth.Truth.assertThat
+import com.google.common.truth.Truth.assertWithMessage
+import org.junit.Test
+
+class ExportedComponentTest {
+
+ private val context: Context = InstrumentationRegistry.getContext()
+
+ @Test
+ fun verifyNoExportedReceivers() {
+ val intent = Intent(Intent.ACTION_INSTALL_PACKAGE).apply {
+ data = Uri.parse("content://mockForTest")
+ }
+ val packageInstallers = context.packageManager.queryIntentActivities(intent,
+ PackageManager.MATCH_DEFAULT_ONLY or PackageManager.MATCH_DISABLED_COMPONENTS)
+ .map { it.activityInfo.packageName }
+ .distinct()
+ .map { context.packageManager.getPackageInfo(it, PackageManager.GET_RECEIVERS) }
+
+ assertThat(packageInstallers).isNotEmpty()
+
+ packageInstallers.forEach {
+ val exported = it.receivers.filter { it.exported }
+ assertWithMessage("Receivers should not be exported").that(exported).isEmpty()
+ }
+ }
+}
diff --git a/services/tests/PackageManagerServiceTests/appenumeration/AndroidTest.xml b/services/tests/PackageManagerServiceTests/appenumeration/AndroidTest.xml
index 7b821c0..67efa14 100644
--- a/services/tests/PackageManagerServiceTests/appenumeration/AndroidTest.xml
+++ b/services/tests/PackageManagerServiceTests/appenumeration/AndroidTest.xml
@@ -33,6 +33,7 @@
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
<option name="push" value="AppEnumerationSyncProviderTestApp.apk->/data/local/tmp/appenumerationtests/AppEnumerationSyncProviderTestApp.apk" />
<option name="push" value="AppEnumerationHasAppOpPermissionTestApp.apk->/data/local/tmp/appenumerationtests/AppEnumerationHasAppOpPermissionTestApp.apk" />
+ <option name="push" value="AppEnumerationSharedUserTestApp.apk->/data/local/tmp/appenumerationtests/AppEnumerationSharedUserTestApp.apk" />
</target_preparer>
<option name="test-tag" value="AppEnumerationInternalTest" />
diff --git a/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/AppEnumerationInternalTests.java b/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/AppEnumerationInternalTests.java
index 63aaf24..ab004be 100644
--- a/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/AppEnumerationInternalTests.java
+++ b/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/AppEnumerationInternalTests.java
@@ -23,6 +23,7 @@
import android.app.AppGlobals;
import android.content.pm.IPackageManager;
import android.content.pm.ProviderInfo;
+import android.os.Process;
import androidx.test.runner.AndroidJUnit4;
@@ -45,14 +46,18 @@
TEST_DATA_PATH + "AppEnumerationSyncProviderTestApp.apk";
private static final String HAS_APPOP_PERMISSION_APK_PATH =
TEST_DATA_PATH + "AppEnumerationHasAppOpPermissionTestApp.apk";
+ private static final String SHARED_USER_APK_PATH =
+ TEST_DATA_PATH + "AppEnumerationSharedUserTestApp.apk";
private static final String TARGET_SYNC_PROVIDER = "com.android.appenumeration.syncprovider";
private static final String TARGET_HAS_APPOP_PERMISSION =
"com.android.appenumeration.hasappoppermission";
+ private static final String TARGET_SHARED_USER = "com.android.appenumeration.shareduid";
private static final String SYNC_PROVIDER_AUTHORITY = TARGET_SYNC_PROVIDER;
private static final String PERMISSION_REQUEST_INSTALL_PACKAGES =
"android.permission.REQUEST_INSTALL_PACKAGES";
+ private static final String SHARED_USER_NAME = "com.android.appenumeration.shareduid";
private IPackageManager mIPackageManager;
@@ -65,6 +70,7 @@
public void tearDown() throws Exception {
uninstallPackage(TARGET_SYNC_PROVIDER);
uninstallPackage(TARGET_HAS_APPOP_PERMISSION);
+ uninstallPackage(TARGET_SHARED_USER);
}
@Test
@@ -111,6 +117,22 @@
assertThat(packageNames).asList().doesNotContain(TARGET_HAS_APPOP_PERMISSION);
}
+ @Test
+ public void getUidForSharedUser_canSeeForceQueryable() throws Exception {
+ installPackage(SHARED_USER_APK_PATH, true /* forceQueryable */);
+
+ final int uid = mIPackageManager.getUidForSharedUser(SHARED_USER_NAME);
+ assertThat(uid).isGreaterThan(Process.FIRST_APPLICATION_UID);
+ }
+
+ @Test
+ public void getUidForSharedUser_cannotSeeSharedUser() throws Exception {
+ installPackage(SHARED_USER_APK_PATH, false /* forceQueryable */);
+
+ final int uid = mIPackageManager.getUidForSharedUser(SHARED_USER_NAME);
+ assertThat(uid).isEqualTo(Process.INVALID_UID);
+ }
+
private static void installPackage(String apkPath, boolean forceQueryable) {
final StringBuilder cmd = new StringBuilder("pm install ");
if (forceQueryable) {
diff --git a/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/Android.bp b/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/Android.bp
index 7aa300b..e0f8327 100644
--- a/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/Android.bp
+++ b/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/Android.bp
@@ -48,3 +48,17 @@
test_suites: ["device-tests"],
platform_apis: true,
}
+
+android_test_helper_app {
+ name: "AppEnumerationSharedUserTestApp",
+ srcs: ["src/**/*.java"],
+ manifest: "AndroidManifest-sharedUser.xml",
+ dex_preopt: {
+ enabled: false,
+ },
+ optimize: {
+ enabled: false,
+ },
+ test_suites: ["device-tests"],
+ platform_apis: true,
+}
diff --git a/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/AndroidManifest-sharedUser.xml b/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/AndroidManifest-sharedUser.xml
new file mode 100644
index 0000000..b424298
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/AndroidManifest-sharedUser.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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.appenumeration.shareduid"
+ android:sharedUserId="com.android.appenumeration.shareduid">
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+</manifest>
\ No newline at end of file
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 a254f68..16afef5 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
@@ -3002,7 +3002,8 @@
final PendingIntent pi = getNewMockPendingIntent();
setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i, pi);
- verify(() -> MetricsHelper.pushAlarmScheduled(argThat(a -> a.matches(pi, null))));
+ verify(() -> MetricsHelper.pushAlarmScheduled(argThat(a -> a.matches(pi, null)),
+ anyInt()));
}
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
index 803a0c1..26b5218 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
@@ -1003,7 +1003,7 @@
dummyPackageName, dummyClassName), "", definingUid));
}
app.mServices.setConnectionGroup(connectionGroup);
- app.mState.setSetProcState(procState);
+ app.mState.setReportedProcState(procState);
app.mProfile.setLastMemInfo(spy(new Debug.MemoryInfo()));
app.mProfile.setLastPss(pss);
app.mProfile.setLastRss(rss);
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 8840057..85ef8f7 100644
--- a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
@@ -207,7 +207,7 @@
}
private void mockDeviceConfigInvalid() {
- String configString = "mode=2,downscaleFactor=0.55";
+ String configString = "";
when(DeviceConfig.getProperty(anyString(), anyString()))
.thenReturn(configString);
}
@@ -373,11 +373,12 @@
*/
@Test
public void testSetGameModePermissionDenied() {
+ mockModifyGameModeGranted();
+ mockDeviceConfigAll();
GameManagerService gameManagerService = new GameManagerService(mMockContext);
gameManagerService.onUserStarting(USER_ID_1);
// Update the game mode so we can read back something valid.
- mockModifyGameModeGranted();
gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_STANDARD, USER_ID_1);
assertEquals(GameManager.GAME_MODE_STANDARD,
gameManagerService.getGameMode(mPackageName, USER_ID_1));
diff --git a/services/tests/mockingservicestests/src/com/android/server/appsearch/AppSearchConfigTest.java b/services/tests/mockingservicestests/src/com/android/server/appsearch/AppSearchConfigTest.java
index 8336663..9926953 100644
--- a/services/tests/mockingservicestests/src/com/android/server/appsearch/AppSearchConfigTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/appsearch/AppSearchConfigTest.java
@@ -50,6 +50,14 @@
AppSearchConfig.DEFAULT_SAMPLING_INTERVAL);
assertThat(appSearchConfig.getCachedSamplingIntervalForPutDocumentStats()).isEqualTo(
AppSearchConfig.DEFAULT_SAMPLING_INTERVAL);
+ assertThat(appSearchConfig.getCachedSamplingIntervalForInitializeStats()).isEqualTo(
+ AppSearchConfig.DEFAULT_SAMPLING_INTERVAL);
+ assertThat(appSearchConfig.getCachedSamplingIntervalForSearchStats()).isEqualTo(
+ AppSearchConfig.DEFAULT_SAMPLING_INTERVAL);
+ assertThat(appSearchConfig.getCachedSamplingIntervalForGlobalSearchStats()).isEqualTo(
+ AppSearchConfig.DEFAULT_SAMPLING_INTERVAL);
+ assertThat(appSearchConfig.getCachedSamplingIntervalForOptimizeStats()).isEqualTo(
+ AppSearchConfig.DEFAULT_SAMPLING_INTERVAL);
assertThat(appSearchConfig.getCachedLimitConfigMaxDocumentSizeBytes()).isEqualTo(
AppSearchConfig.DEFAULT_LIMIT_CONFIG_MAX_DOCUMENT_SIZE_BYTES);
assertThat(appSearchConfig.getCachedLimitConfigMaxDocumentCount()).isEqualTo(
@@ -100,6 +108,11 @@
final int samplingIntervalDefault = -1;
final int samplingIntervalPutDocumentStats = -2;
final int samplingIntervalBatchCallStats = -3;
+ final int samplingIntervalInitializeStats = -4;
+ final int samplingIntervalSearchStats = -5;
+ final int samplingIntervalGlobalSearchStats = -6;
+ final int samplingIntervalOptimizeStats = -7;
+
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
AppSearchConfig.KEY_SAMPLING_INTERVAL_DEFAULT,
Integer.toString(samplingIntervalDefault),
@@ -112,6 +125,22 @@
AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_BATCH_CALL_STATS,
Integer.toString(samplingIntervalBatchCallStats),
false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
+ AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_INITIALIZE_STATS,
+ Integer.toString(samplingIntervalInitializeStats),
+ false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
+ AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_SEARCH_STATS,
+ Integer.toString(samplingIntervalSearchStats),
+ false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
+ AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_GLOBAL_SEARCH_STATS,
+ Integer.toString(samplingIntervalGlobalSearchStats),
+ false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
+ AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_OPTIMIZE_STATS,
+ Integer.toString(samplingIntervalOptimizeStats),
+ false);
AppSearchConfig appSearchConfig = AppSearchConfig.create(DIRECT_EXECUTOR);
@@ -121,6 +150,14 @@
samplingIntervalPutDocumentStats);
assertThat(appSearchConfig.getCachedSamplingIntervalForBatchCallStats()).isEqualTo(
samplingIntervalBatchCallStats);
+ assertThat(appSearchConfig.getCachedSamplingIntervalForInitializeStats()).isEqualTo(
+ samplingIntervalInitializeStats);
+ assertThat(appSearchConfig.getCachedSamplingIntervalForSearchStats()).isEqualTo(
+ samplingIntervalSearchStats);
+ assertThat(appSearchConfig.getCachedSamplingIntervalForGlobalSearchStats()).isEqualTo(
+ samplingIntervalGlobalSearchStats);
+ assertThat(appSearchConfig.getCachedSamplingIntervalForOptimizeStats()).isEqualTo(
+ samplingIntervalOptimizeStats);
}
@Test
@@ -128,6 +165,10 @@
int samplingIntervalDefault = -1;
int samplingIntervalPutDocumentStats = -2;
int samplingIntervalBatchCallStats = -3;
+ int samplingIntervalInitializeStats = -4;
+ int samplingIntervalSearchStats = -5;
+ int samplingIntervalGlobalSearchStats = -6;
+ int samplingIntervalOptimizeStats = -7;
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
AppSearchConfig.KEY_SAMPLING_INTERVAL_DEFAULT,
Integer.toString(samplingIntervalDefault),
@@ -140,12 +181,32 @@
AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_BATCH_CALL_STATS,
Integer.toString(samplingIntervalBatchCallStats),
false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
+ AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_INITIALIZE_STATS,
+ Integer.toString(samplingIntervalInitializeStats),
+ false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
+ AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_SEARCH_STATS,
+ Integer.toString(samplingIntervalSearchStats),
+ false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
+ AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_GLOBAL_SEARCH_STATS,
+ Integer.toString(samplingIntervalGlobalSearchStats),
+ false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
+ AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_OPTIMIZE_STATS,
+ Integer.toString(samplingIntervalOptimizeStats),
+ false);
AppSearchConfig appSearchConfig = AppSearchConfig.create(DIRECT_EXECUTOR);
// Overrides
samplingIntervalDefault = -4;
samplingIntervalPutDocumentStats = -5;
samplingIntervalBatchCallStats = -6;
+ samplingIntervalInitializeStats = -7;
+ samplingIntervalSearchStats = -8;
+ samplingIntervalGlobalSearchStats = -9;
+ samplingIntervalOptimizeStats = -10;
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
AppSearchConfig.KEY_SAMPLING_INTERVAL_DEFAULT,
Integer.toString(samplingIntervalDefault),
@@ -158,6 +219,22 @@
AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_BATCH_CALL_STATS,
Integer.toString(samplingIntervalBatchCallStats),
false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
+ AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_INITIALIZE_STATS,
+ Integer.toString(samplingIntervalInitializeStats),
+ false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
+ AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_SEARCH_STATS,
+ Integer.toString(samplingIntervalSearchStats),
+ false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
+ AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_GLOBAL_SEARCH_STATS,
+ Integer.toString(samplingIntervalGlobalSearchStats),
+ false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
+ AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_OPTIMIZE_STATS,
+ Integer.toString(samplingIntervalOptimizeStats),
+ false);
assertThat(appSearchConfig.getCachedSamplingIntervalDefault()).isEqualTo(
samplingIntervalDefault);
@@ -165,6 +242,14 @@
samplingIntervalPutDocumentStats);
assertThat(appSearchConfig.getCachedSamplingIntervalForBatchCallStats()).isEqualTo(
samplingIntervalBatchCallStats);
+ assertThat(appSearchConfig.getCachedSamplingIntervalForInitializeStats()).isEqualTo(
+ samplingIntervalInitializeStats);
+ assertThat(appSearchConfig.getCachedSamplingIntervalForSearchStats()).isEqualTo(
+ samplingIntervalSearchStats);
+ assertThat(appSearchConfig.getCachedSamplingIntervalForGlobalSearchStats()).isEqualTo(
+ samplingIntervalGlobalSearchStats);
+ assertThat(appSearchConfig.getCachedSamplingIntervalForOptimizeStats()).isEqualTo(
+ samplingIntervalOptimizeStats);
}
/**
@@ -366,6 +451,18 @@
() -> appSearchConfig.getCachedSamplingIntervalForPutDocumentStats());
Assert.assertThrows("Trying to use a closed AppSearchConfig instance.",
IllegalStateException.class,
+ () -> appSearchConfig.getCachedSamplingIntervalForInitializeStats());
+ Assert.assertThrows("Trying to use a closed AppSearchConfig instance.",
+ IllegalStateException.class,
+ () -> appSearchConfig.getCachedSamplingIntervalForSearchStats());
+ Assert.assertThrows("Trying to use a closed AppSearchConfig instance.",
+ IllegalStateException.class,
+ () -> appSearchConfig.getCachedSamplingIntervalForGlobalSearchStats());
+ Assert.assertThrows("Trying to use a closed AppSearchConfig instance.",
+ IllegalStateException.class,
+ () -> appSearchConfig.getCachedSamplingIntervalForOptimizeStats());
+ Assert.assertThrows("Trying to use a closed AppSearchConfig instance.",
+ IllegalStateException.class,
() -> appSearchConfig.getCachedBytesOptimizeThreshold());
Assert.assertThrows("Trying to use a closed AppSearchConfig instance.",
IllegalStateException.class,
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index 906e6d2..dd70c87 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -5417,10 +5417,9 @@
timeout(remainingTimeMs / 2 + 2 * SECOND_IN_MILLIS).times(1))
.onControllerStateChanged(any());
// Top should still be "in quota" since it started before the app ran on top out of quota.
- assertFalse(jobBg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_EXPEDITED_QUOTA));
- assertTrue(jobTop.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_EXPEDITED_QUOTA));
- assertFalse(
- jobUnstarted.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_EXPEDITED_QUOTA));
+ assertFalse(jobBg.isExpeditedQuotaApproved());
+ assertTrue(jobTop.isExpeditedQuotaApproved());
+ assertFalse(jobUnstarted.isExpeditedQuotaApproved());
synchronized (mQuotaController.mLock) {
assertTrue(
0 >= mQuotaController
@@ -5445,18 +5444,18 @@
synchronized (mQuotaController.mLock) {
mQuotaController.prepareForExecutionLocked(jobTop2);
}
- assertTrue(jobTop2.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_EXPEDITED_QUOTA));
- assertTrue(jobFg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_EXPEDITED_QUOTA));
- assertTrue(jobBg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_EXPEDITED_QUOTA));
- assertTrue(jobUnstarted.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_EXPEDITED_QUOTA));
+ assertTrue(jobTop2.isExpeditedQuotaApproved());
+ assertTrue(jobFg.isExpeditedQuotaApproved());
+ assertTrue(jobBg.isExpeditedQuotaApproved());
+ assertTrue(jobUnstarted.isExpeditedQuotaApproved());
// App still in foreground so everything should be in quota.
advanceElapsedClock(20 * SECOND_IN_MILLIS);
setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
- assertTrue(jobTop2.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_EXPEDITED_QUOTA));
- assertTrue(jobFg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_EXPEDITED_QUOTA));
- assertTrue(jobBg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_EXPEDITED_QUOTA));
- assertTrue(jobUnstarted.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_EXPEDITED_QUOTA));
+ assertTrue(jobTop2.isExpeditedQuotaApproved());
+ assertTrue(jobFg.isExpeditedQuotaApproved());
+ assertTrue(jobBg.isExpeditedQuotaApproved());
+ assertTrue(jobUnstarted.isExpeditedQuotaApproved());
advanceElapsedClock(20 * SECOND_IN_MILLIS);
setProcessState(ActivityManager.PROCESS_STATE_SERVICE);
@@ -5464,13 +5463,12 @@
.onControllerStateChanged(any());
// App is now in background and out of quota. Fg should now change to out of quota since it
// wasn't started. Top should remain in quota since it started when the app was in TOP.
- assertTrue(jobTop2.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_EXPEDITED_QUOTA));
- assertFalse(jobFg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_EXPEDITED_QUOTA));
- assertFalse(jobBg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_EXPEDITED_QUOTA));
+ assertTrue(jobTop2.isExpeditedQuotaApproved());
+ assertFalse(jobFg.isExpeditedQuotaApproved());
+ assertFalse(jobBg.isExpeditedQuotaApproved());
trackJobs(jobBg2);
- assertFalse(jobBg2.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_EXPEDITED_QUOTA));
- assertFalse(
- jobUnstarted.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_EXPEDITED_QUOTA));
+ assertFalse(jobBg2.isExpeditedQuotaApproved());
+ assertFalse(jobUnstarted.isExpeditedQuotaApproved());
synchronized (mQuotaController.mLock) {
assertTrue(
0 >= mQuotaController
@@ -5602,7 +5600,7 @@
verify(mJobSchedulerService,
timeout(remainingTimeMs + 2 * SECOND_IN_MILLIS).times(0))
.onControllerStateChanged(any());
- assertTrue(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_EXPEDITED_QUOTA));
+ assertTrue(jobStatus.isExpeditedQuotaApproved());
// The job used up the remaining quota, but in that time, the same amount of time in the
// old TimingSession also fell out of the quota window, so it should still have the same
// amount of remaining time left its quota.
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
index d4f17f3..3c97c95 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
@@ -28,6 +28,7 @@
import android.content.pm.UserInfo
import android.content.pm.parsing.ParsingPackage
import android.content.pm.parsing.ParsingPackageUtils
+import android.content.pm.parsing.result.ParseTypeImpl
import android.content.res.Resources
import android.hardware.display.DisplayManager
import android.os.Build
@@ -390,8 +391,10 @@
val apkPath = File(File(parent, packageName), "base.apk")
val pkg = PackageImpl.forTesting(packageName, apkPath.parentFile.path) as PackageImpl
pkg.signingDetails = signingDetails
- wheneverStatic { ParsingPackageUtils.getSigningDetails(eq(pkg), anyBoolean()) }
- .thenReturn(signingDetails)
+ val result = ParseTypeImpl.forDefaultParsing().success(signingDetails)
+ wheneverStatic { ParsingPackageUtils.getSigningDetails(
+ any(ParseTypeImpl::class.java), eq(pkg), anyBoolean()) }
+ .thenReturn(result)
pkg.versionCode = versionCode.toInt()
pkg.versionCodeMajor = (versionCode shr 32).toInt()
pkg.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT
@@ -498,8 +501,10 @@
val apk = File(File(rootDirectory, "framework"), "framework-res.apk")
val frameworkPkg = PackageImpl.forTesting("android",
apk.parentFile.path) as PackageImpl
- wheneverStatic { ParsingPackageUtils.getSigningDetails(frameworkPkg, true) }
- .thenReturn(frameworkSignature)
+ val result = ParseTypeImpl.forDefaultParsing().success(frameworkSignature)
+ wheneverStatic { ParsingPackageUtils.getSigningDetails(
+ any(ParseTypeImpl::class.java), eq(frameworkPkg), eq(true)) }
+ .thenReturn(result)
stageParse(apk, frameworkPkg)
stageSettingInsert("android",
PackageSettingBuilder().setCodePath(apk.path).setName(
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceBootTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceBootTest.kt
index bd44c36..dbbf73b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceBootTest.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceBootTest.kt
@@ -18,7 +18,6 @@
import android.content.pm.ApplicationInfo.FLAG_SYSTEM
import android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRIVILEGED
import android.content.pm.PackageManager
-import android.content.pm.PackageParser
import android.os.Build
import android.os.Process
import android.util.Log
@@ -122,7 +121,7 @@
argThat { path: File -> path.path.contains("a.data.package") },
anyInt(),
anyBoolean()))
- .thenThrow(PackageParser.PackageParserException(
+ .thenThrow(PackageManagerException(
PackageManager.INSTALL_FAILED_INVALID_APK, "Oh no!"))
val pm = createPackageManagerService()
verify(rule.mocks().settings, Mockito.never()).insertPackageSettingLPw(
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java
index ab43adc..ba5a58f 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java
@@ -467,6 +467,66 @@
assertThat(apkSession.getErrorMessage()).isEqualTo("Another apex session failed");
}
+ @Test
+ public void getSessionIdByPackageName() throws Exception {
+ FakeStagedSession session = new FakeStagedSession(239);
+ session.setCommitted(true);
+ session.setSessionReady();
+ session.setPackageName("com.foo");
+
+ mStagingManager.createSession(session);
+ assertThat(mStagingManager.getSessionIdByPackageName("com.foo")).isEqualTo(239);
+ }
+
+ @Test
+ public void getSessionIdByPackageName_appliedSession_ignores() throws Exception {
+ FakeStagedSession session = new FakeStagedSession(37);
+ session.setCommitted(true);
+ session.setSessionApplied();
+ session.setPackageName("com.foo");
+
+ mStagingManager.createSession(session);
+ assertThat(mStagingManager.getSessionIdByPackageName("com.foo")).isEqualTo(-1);
+ }
+
+ @Test
+ public void getSessionIdByPackageName_failedSession_ignores() throws Exception {
+ FakeStagedSession session = new FakeStagedSession(73);
+ session.setCommitted(true);
+ session.setSessionFailed(1, "whatevs");
+ session.setPackageName("com.foo");
+
+ mStagingManager.createSession(session);
+ assertThat(mStagingManager.getSessionIdByPackageName("com.foo")).isEqualTo(-1);
+ }
+
+ @Test
+ public void getSessionIdByPackageName_destroyedSession_ignores() throws Exception {
+ FakeStagedSession session = new FakeStagedSession(23);
+ session.setCommitted(true);
+ session.setDestroyed(true);
+ session.setPackageName("com.foo");
+
+ mStagingManager.createSession(session);
+ assertThat(mStagingManager.getSessionIdByPackageName("com.foo")).isEqualTo(-1);
+ }
+
+ @Test
+ public void getSessionIdByPackageName_noSessions() throws Exception {
+ assertThat(mStagingManager.getSessionIdByPackageName("com.foo")).isEqualTo(-1);
+ }
+
+ @Test
+ public void getSessionIdByPackageName_noSessionHasThisPackage() throws Exception {
+ FakeStagedSession session = new FakeStagedSession(37);
+ session.setCommitted(true);
+ session.setSessionApplied();
+ session.setPackageName("com.foo");
+
+ mStagingManager.createSession(session);
+ assertThat(mStagingManager.getSessionIdByPackageName("com.bar")).isEqualTo(-1);
+ }
+
private StagingManager.StagedSession createSession(int sessionId, String packageName,
long committedMillis) {
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java
index c5416fb..1a3e53e 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java
@@ -261,8 +261,8 @@
@Test
public void resolveValidReportedPackage_uidAndPkgNameMatched_returnPkgName()
throws PackageManager.NameNotFoundException {
- when(mMockPackageManager.getPackageUidAsUser(PACKAGE_NAME, TEST_USER_ID))
- .thenReturn(APP_UID);
+ when(mMockPackageManager.getPackageUidAsUser(PACKAGE_NAME,
+ PackageManager.MATCH_ANY_USER, TEST_USER_ID)).thenReturn(APP_UID);
assertEquals(mA11ySecurityPolicy.resolveValidReportedPackageLocked(
PACKAGE_NAME, APP_UID, TEST_USER_ID, APP_PID),
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
index 4afe099..ca9ab4f 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
@@ -30,7 +30,6 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertThat;
-import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
@@ -836,19 +835,6 @@
assertNull(token);
}
- @Test
- public void onDisplayReparented_shouldRemoveObserver() throws RemoteException {
- // Starts tracking window of second display.
- startTrackingPerDisplay(SECONDARY_DISPLAY_ID);
- assertTrue(mA11yWindowManager.isTrackingWindowsLocked(SECONDARY_DISPLAY_ID));
- // Notifies the second display is an embedded one of the default display.
- final WindowsForAccessibilityCallback callbacks =
- mCallbackOfWindows.get(Display.DEFAULT_DISPLAY);
- callbacks.onDisplayReparented(SECONDARY_DISPLAY_ID);
- // Makes sure the observer of the second display is removed.
- assertFalse(mA11yWindowManager.isTrackingWindowsLocked(SECONDARY_DISPLAY_ID));
- }
-
private void registerLeashedTokenAndWindowId() {
mA11yWindowManager.registerIdLocked(mMockHostToken, HOST_WINDOW_ID);
mA11yWindowManager.registerIdLocked(mMockEmbeddedToken, EMBEDDED_WINDOW_ID);
@@ -878,8 +864,6 @@
windowInfosForDisplay.get(DEFAULT_FOCUSED_INDEX).focused = true;
}
// Turns on windows tracking, and update window info.
- when(mMockWindowManagerInternal.setWindowsForAccessibilityCallback(eq(displayId), any()))
- .thenReturn(true);
mA11yWindowManager.startTrackingWindows(displayId);
// Puts window lists into array.
mWindowInfos.put(displayId, windowInfosForDisplay);
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java
index 5b067bc..f40a5ad 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java
@@ -42,6 +42,7 @@
import com.android.server.appsearch.external.localstorage.converter.GenericDocumentToProtoConverter;
import com.android.server.appsearch.external.localstorage.stats.InitializeStats;
+import com.android.server.appsearch.external.localstorage.stats.OptimizeStats;
import com.android.server.appsearch.external.localstorage.util.PrefixUtil;
import com.android.server.appsearch.icing.proto.DocumentProto;
import com.android.server.appsearch.icing.proto.GetOptimizeInfoResultProto;
@@ -451,19 +452,26 @@
assertThat(optimizeInfo.getOptimizableDocs()).isEqualTo(1);
// Increase mutation counter and stop before reach the threshold
- mAppSearchImpl.checkForOptimize(AppSearchImpl.CHECK_OPTIMIZE_INTERVAL - 1);
+ mAppSearchImpl.checkForOptimize(
+ AppSearchImpl.CHECK_OPTIMIZE_INTERVAL - 1, /*builder=*/ null);
// Verify the optimize() isn't triggered.
optimizeInfo = mAppSearchImpl.getOptimizeInfoResultLocked();
assertThat(optimizeInfo.getOptimizableDocs()).isEqualTo(1);
// Increase the counter and reach the threshold, optimize() should be triggered.
- mAppSearchImpl.checkForOptimize(/*mutateBatchSize=*/ 1);
+ OptimizeStats.Builder builder = new OptimizeStats.Builder();
+ mAppSearchImpl.checkForOptimize(/*mutateBatchSize=*/ 1, builder);
// Verify optimize() is triggered.
optimizeInfo = mAppSearchImpl.getOptimizeInfoResultLocked();
assertThat(optimizeInfo.getOptimizableDocs()).isEqualTo(0);
assertThat(optimizeInfo.getEstimatedOptimizableBytes()).isEqualTo(0);
+
+ // Verify the stats have been set.
+ OptimizeStats oStats = builder.build();
+ assertThat(oStats.getOriginalDocumentCount()).isEqualTo(1);
+ assertThat(oStats.getDeletedDocumentCount()).isEqualTo(1);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java
index 7bacbb6..7c97687 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java
@@ -29,12 +29,14 @@
import com.android.server.appsearch.external.localstorage.stats.CallStats;
import com.android.server.appsearch.external.localstorage.stats.InitializeStats;
+import com.android.server.appsearch.external.localstorage.stats.OptimizeStats;
import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats;
import com.android.server.appsearch.external.localstorage.stats.RemoveStats;
import com.android.server.appsearch.external.localstorage.stats.SearchStats;
import com.android.server.appsearch.icing.proto.DeleteStatsProto;
import com.android.server.appsearch.icing.proto.DocumentProto;
import com.android.server.appsearch.icing.proto.InitializeStatsProto;
+import com.android.server.appsearch.icing.proto.OptimizeStatsProto;
import com.android.server.appsearch.icing.proto.PutDocumentStatsProto;
import com.android.server.appsearch.icing.proto.PutResultProto;
import com.android.server.appsearch.icing.proto.QueryStatsProto;
@@ -81,6 +83,7 @@
@Nullable InitializeStats mInitializeStats;
@Nullable SearchStats mSearchStats;
@Nullable RemoveStats mRemoveStats;
+ @Nullable OptimizeStats mOptimizeStats;
@Override
public void logStats(@NonNull CallStats stats) {
@@ -106,6 +109,11 @@
public void logStats(@NonNull RemoveStats stats) {
mRemoveStats = stats;
}
+
+ @Override
+ public void logStats(@NonNull OptimizeStats stats) {
+ mOptimizeStats = stats;
+ }
}
@Test
@@ -286,6 +294,48 @@
assertThat(rStats.getDeletedDocumentCount()).isEqualTo(nativeNumDocumentDeleted);
}
+ @Test
+ public void testAppSearchLoggerHelper_testCopyNativeStats_optimize() {
+ int nativeLatencyMillis = 1;
+ int nativeDocumentStoreOptimizeLatencyMillis = 2;
+ int nativeIndexRestorationLatencyMillis = 3;
+ int nativeNumOriginalDocuments = 4;
+ int nativeNumDeletedDocuments = 5;
+ int nativeNumExpiredDocuments = 6;
+ long nativeStorageSizeBeforeBytes = Integer.MAX_VALUE + 1;
+ long nativeStorageSizeAfterBytes = Integer.MAX_VALUE + 2;
+ long nativeTimeSinceLastOptimizeMillis = Integer.MAX_VALUE + 3;
+ OptimizeStatsProto optimizeStatsProto =
+ OptimizeStatsProto.newBuilder()
+ .setLatencyMs(nativeLatencyMillis)
+ .setDocumentStoreOptimizeLatencyMs(nativeDocumentStoreOptimizeLatencyMillis)
+ .setIndexRestorationLatencyMs(nativeIndexRestorationLatencyMillis)
+ .setNumOriginalDocuments(nativeNumOriginalDocuments)
+ .setNumDeletedDocuments(nativeNumDeletedDocuments)
+ .setNumExpiredDocuments(nativeNumExpiredDocuments)
+ .setStorageSizeBefore(nativeStorageSizeBeforeBytes)
+ .setStorageSizeAfter(nativeStorageSizeAfterBytes)
+ .setTimeSinceLastOptimizeMs(nativeTimeSinceLastOptimizeMillis)
+ .build();
+ OptimizeStats.Builder oBuilder = new OptimizeStats.Builder();
+
+ AppSearchLoggerHelper.copyNativeStats(optimizeStatsProto, oBuilder);
+
+ OptimizeStats oStats = oBuilder.build();
+ assertThat(oStats.getNativeLatencyMillis()).isEqualTo(nativeLatencyMillis);
+ assertThat(oStats.getDocumentStoreOptimizeLatencyMillis())
+ .isEqualTo(nativeDocumentStoreOptimizeLatencyMillis);
+ assertThat(oStats.getIndexRestorationLatencyMillis())
+ .isEqualTo(nativeIndexRestorationLatencyMillis);
+ assertThat(oStats.getOriginalDocumentCount()).isEqualTo(nativeNumOriginalDocuments);
+ assertThat(oStats.getDeletedDocumentCount()).isEqualTo(nativeNumDeletedDocuments);
+ assertThat(oStats.getExpiredDocumentCount()).isEqualTo(nativeNumExpiredDocuments);
+ assertThat(oStats.getStorageSizeBeforeBytes()).isEqualTo(nativeStorageSizeBeforeBytes);
+ assertThat(oStats.getStorageSizeAfterBytes()).isEqualTo(nativeStorageSizeAfterBytes);
+ assertThat(oStats.getTimeSinceLastOptimizeMillis())
+ .isEqualTo(nativeTimeSinceLastOptimizeMillis);
+ }
+
//
// Testing actual logging
//
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java
index 57d9941..c1dc0e4 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java
@@ -348,4 +348,49 @@
assertThat(rStats.getDeleteType()).isEqualTo(deleteType);
assertThat(rStats.getDeletedDocumentCount()).isEqualTo(documentDeletedCount);
}
+
+ @Test
+ public void testAppSearchStats_OptimizeStats() {
+ int nativeLatencyMillis = 1;
+ int nativeDocumentStoreOptimizeLatencyMillis = 2;
+ int nativeIndexRestorationLatencyMillis = 3;
+ int nativeNumOriginalDocuments = 4;
+ int nativeNumDeletedDocuments = 5;
+ int nativeNumExpiredDocuments = 6;
+ long nativeStorageSizeBeforeBytes = Integer.MAX_VALUE + 1;
+ long nativeStorageSizeAfterBytes = Integer.MAX_VALUE + 2;
+ long nativeTimeSinceLastOptimizeMillis = Integer.MAX_VALUE + 3;
+
+ final OptimizeStats oStats =
+ new OptimizeStats.Builder()
+ .setStatusCode(TEST_STATUS_CODE)
+ .setTotalLatencyMillis(TEST_TOTAL_LATENCY_MILLIS)
+ .setNativeLatencyMillis(nativeLatencyMillis)
+ .setDocumentStoreOptimizeLatencyMillis(
+ nativeDocumentStoreOptimizeLatencyMillis)
+ .setIndexRestorationLatencyMillis(nativeIndexRestorationLatencyMillis)
+ .setOriginalDocumentCount(nativeNumOriginalDocuments)
+ .setDeletedDocumentCount(nativeNumDeletedDocuments)
+ .setExpiredDocumentCount(nativeNumExpiredDocuments)
+ .setStorageSizeBeforeBytes(nativeStorageSizeBeforeBytes)
+ .setStorageSizeAfterBytes(nativeStorageSizeAfterBytes)
+ .setTimeSinceLastOptimizeMillis(nativeTimeSinceLastOptimizeMillis)
+ .build();
+
+ assertThat(oStats.getStatusCode()).isEqualTo(TEST_STATUS_CODE);
+ assertThat(oStats.getTotalLatencyMillis()).isEqualTo(TEST_TOTAL_LATENCY_MILLIS);
+ assertThat(oStats.getNativeLatencyMillis()).isEqualTo(nativeLatencyMillis);
+ assertThat(oStats.getNativeLatencyMillis()).isEqualTo(nativeLatencyMillis);
+ assertThat(oStats.getDocumentStoreOptimizeLatencyMillis())
+ .isEqualTo(nativeDocumentStoreOptimizeLatencyMillis);
+ assertThat(oStats.getIndexRestorationLatencyMillis())
+ .isEqualTo(nativeIndexRestorationLatencyMillis);
+ assertThat(oStats.getOriginalDocumentCount()).isEqualTo(nativeNumOriginalDocuments);
+ assertThat(oStats.getDeletedDocumentCount()).isEqualTo(nativeNumDeletedDocuments);
+ assertThat(oStats.getExpiredDocumentCount()).isEqualTo(nativeNumExpiredDocuments);
+ assertThat(oStats.getStorageSizeBeforeBytes()).isEqualTo(nativeStorageSizeBeforeBytes);
+ assertThat(oStats.getStorageSizeAfterBytes()).isEqualTo(nativeStorageSizeAfterBytes);
+ assertThat(oStats.getTimeSinceLastOptimizeMillis())
+ .isEqualTo(nativeTimeSinceLastOptimizeMillis);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
index a8bf0c7..1fe4123 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
@@ -372,6 +372,11 @@
protected void startHalOperation() {
}
+
+ @Override
+ protected void handleLifecycleAfterAuth(boolean authenticated) {
+
+ }
}
private static class TestAuthenticationClient extends AuthenticationClient<Object> {
@@ -395,6 +400,11 @@
protected void startHalOperation() {
}
+
+ @Override
+ protected void handleLifecycleAfterAuth(boolean authenticated) {
+
+ }
}
private static class TestClientMonitor2 extends TestClientMonitor {
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/CoexCoordinatorTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/CoexCoordinatorTest.java
index 589463e..a169ebd 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/CoexCoordinatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/CoexCoordinatorTest.java
@@ -16,64 +16,362 @@
package com.android.server.biometrics.sensors;
+import static com.android.server.biometrics.sensors.BiometricScheduler.SENSOR_TYPE_FACE;
+import static com.android.server.biometrics.sensors.BiometricScheduler.SENSOR_TYPE_UDFPS;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.withSettings;
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
import android.platform.test.annotations.Presubmit;
+import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
+import com.android.server.biometrics.sensors.fingerprint.Udfps;
+
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.LinkedList;
+
@Presubmit
@SmallTest
public class CoexCoordinatorTest {
- private CoexCoordinator mCoexCoordinator;
+ private static final String TAG = "CoexCoordinatorTest";
+ private CoexCoordinator mCoexCoordinator;
+ private Handler mHandler;
+
+ @Mock
+ private Context mContext;
@Mock
private CoexCoordinator.Callback mCallback;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+
+ mHandler = new Handler(Looper.getMainLooper());
+
mCoexCoordinator = CoexCoordinator.getInstance();
+ mCoexCoordinator.setAdvancedLogicEnabled(true);
}
@Test
public void testBiometricPrompt_authSuccess() {
+ mCoexCoordinator.reset();
+
AuthenticationClient<?> client = mock(AuthenticationClient.class);
when(client.isBiometricPrompt()).thenReturn(true);
- mCoexCoordinator.onAuthenticationSucceeded(client, mCallback);
+ mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, client);
+
+ mCoexCoordinator.onAuthenticationSucceeded(0 /* currentTimeMillis */, client, mCallback);
verify(mCallback).sendHapticFeedback();
verify(mCallback).sendAuthenticationResult(eq(false) /* addAuthTokenIfStrong */);
+ verify(mCallback).handleLifecycleAfterAuth();
}
@Test
public void testBiometricPrompt_authReject_whenNotLockedOut() {
+ mCoexCoordinator.reset();
+
AuthenticationClient<?> client = mock(AuthenticationClient.class);
when(client.isBiometricPrompt()).thenReturn(true);
- mCoexCoordinator.onAuthenticationRejected(client, LockoutTracker.LOCKOUT_NONE, mCallback);
+ mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, client);
+
+ mCoexCoordinator.onAuthenticationRejected(0 /* currentTimeMillis */,
+ client, LockoutTracker.LOCKOUT_NONE, mCallback);
verify(mCallback).sendHapticFeedback();
verify(mCallback).sendAuthenticationResult(eq(false) /* addAuthTokenIfStrong */);
+ verify(mCallback).handleLifecycleAfterAuth();
}
@Test
public void testBiometricPrompt_authReject_whenLockedOut() {
+ mCoexCoordinator.reset();
+
AuthenticationClient<?> client = mock(AuthenticationClient.class);
when(client.isBiometricPrompt()).thenReturn(true);
- mCoexCoordinator.onAuthenticationRejected(client, LockoutTracker.LOCKOUT_TIMED, mCallback);
+ mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, client);
+
+ mCoexCoordinator.onAuthenticationRejected(0 /* currentTimeMillis */,
+ client, LockoutTracker.LOCKOUT_TIMED, mCallback);
verify(mCallback).sendHapticFeedback();
verify(mCallback, never()).sendAuthenticationResult(anyBoolean());
+ verify(mCallback).handleLifecycleAfterAuth();
+ }
+
+ @Test
+ public void testKeyguard_faceAuthOnly_success() {
+ mCoexCoordinator.reset();
+
+ AuthenticationClient<?> client = mock(AuthenticationClient.class);
+ when(client.isKeyguard()).thenReturn(true);
+
+ mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, client);
+
+ mCoexCoordinator.onAuthenticationSucceeded(0 /* currentTimeMillis */, client, mCallback);
+ verify(mCallback).sendHapticFeedback();
+ verify(mCallback).sendAuthenticationResult(eq(true) /* addAuthTokenIfStrong */);
+ verify(mCallback).handleLifecycleAfterAuth();
+ }
+
+ @Test
+ public void testKeyguard_faceAuth_udfpsNotTouching_faceSuccess() {
+ mCoexCoordinator.reset();
+
+ AuthenticationClient<?> faceClient = mock(AuthenticationClient.class);
+ when(faceClient.isKeyguard()).thenReturn(true);
+
+ AuthenticationClient<?> udfpsClient = mock(AuthenticationClient.class,
+ withSettings().extraInterfaces(Udfps.class));
+ when(udfpsClient.isKeyguard()).thenReturn(true);
+ when(((Udfps) udfpsClient).isPointerDown()).thenReturn(false);
+
+ mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, faceClient);
+ mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_UDFPS, udfpsClient);
+
+ mCoexCoordinator.onAuthenticationSucceeded(0 /* currentTimeMillis */, faceClient,
+ mCallback);
+ verify(mCallback).sendHapticFeedback();
+ verify(mCallback).sendAuthenticationResult(eq(true) /* addAuthTokenIfStrong */);
+ verify(mCallback).handleLifecycleAfterAuth();
+ }
+
+ @Test
+ public void testKeyguard_faceAuth_udfpsTouching_faceSuccess_thenUdfpsRejectedWithinBounds() {
+ testKeyguard_faceAuth_udfpsTouching_faceSuccess(false /* thenUdfpsAccepted */,
+ 0 /* udfpsRejectedAfterMs */);
+ }
+
+ @Test
+ public void testKeyguard_faceAuth_udfpsTouching_faceSuccess_thenUdfpsRejectedAfterBounds() {
+ testKeyguard_faceAuth_udfpsTouching_faceSuccess(false /* thenUdfpsAccepted */,
+ CoexCoordinator.SUCCESSFUL_AUTH_VALID_DURATION_MS + 1 /* udfpsRejectedAfterMs */);
+ }
+
+ @Test
+ public void testKeyguard_faceAuth_udfpsTouching_faceSuccess_thenUdfpsAccepted() {
+ testKeyguard_faceAuth_udfpsTouching_faceSuccess(true /* thenUdfpsAccepted */,
+ 0 /* udfpsRejectedAfterMs */);
+ }
+
+ private void testKeyguard_faceAuth_udfpsTouching_faceSuccess(boolean thenUdfpsAccepted,
+ long udfpsRejectedAfterMs) {
+ mCoexCoordinator.reset();
+
+ AuthenticationClient<?> faceClient = mock(AuthenticationClient.class);
+ when(faceClient.isKeyguard()).thenReturn(true);
+
+ AuthenticationClient<?> udfpsClient = mock(AuthenticationClient.class,
+ withSettings().extraInterfaces(Udfps.class));
+ when(udfpsClient.isKeyguard()).thenReturn(true);
+ when(((Udfps) udfpsClient).isPointerDown()).thenReturn(true);
+ when (udfpsClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED);
+
+ mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, faceClient);
+ mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_UDFPS, udfpsClient);
+
+ mCoexCoordinator.onAuthenticationSucceeded(0 /* currentTimeMillis */, faceClient,
+ mCallback);
+ verify(mCallback, never()).sendHapticFeedback();
+ verify(mCallback, never()).sendAuthenticationResult(anyBoolean());
+ // CoexCoordinator requests the system to hold onto this AuthenticationClient until
+ // UDFPS result is known
+ verify(mCallback, never()).handleLifecycleAfterAuth();
+
+ // Reset the mock
+ CoexCoordinator.Callback udfpsCallback = mock(CoexCoordinator.Callback.class);
+ assertEquals(1, mCoexCoordinator.mSuccessfulAuths.size());
+ assertEquals(faceClient, mCoexCoordinator.mSuccessfulAuths.get(0).mAuthenticationClient);
+ if (thenUdfpsAccepted) {
+ mCoexCoordinator.onAuthenticationSucceeded(0 /* currentTimeMillis */, udfpsClient,
+ udfpsCallback);
+ verify(udfpsCallback).sendHapticFeedback();
+ verify(udfpsCallback).sendAuthenticationResult(true /* addAuthTokenIfStrong */);
+ verify(udfpsCallback).handleLifecycleAfterAuth();
+
+ assertTrue(mCoexCoordinator.mSuccessfulAuths.isEmpty());
+ } else {
+ mCoexCoordinator.onAuthenticationRejected(udfpsRejectedAfterMs, udfpsClient,
+ LockoutTracker.LOCKOUT_NONE, udfpsCallback);
+ if (udfpsRejectedAfterMs <= CoexCoordinator.SUCCESSFUL_AUTH_VALID_DURATION_MS) {
+ verify(udfpsCallback, never()).sendHapticFeedback();
+
+ verify(mCallback).sendHapticFeedback();
+ verify(mCallback).sendAuthenticationResult(eq(true) /* addAuthTokenIfStrong */);
+ verify(mCallback).handleLifecycleAfterAuth();
+
+ assertTrue(mCoexCoordinator.mSuccessfulAuths.isEmpty());
+ } else {
+ assertTrue(mCoexCoordinator.mSuccessfulAuths.isEmpty());
+
+ verify(mCallback, never()).sendHapticFeedback();
+ verify(mCallback, never()).sendAuthenticationResult(anyBoolean());
+
+ verify(udfpsCallback).sendHapticFeedback();
+ verify(udfpsCallback)
+ .sendAuthenticationResult(eq(false) /* addAuthTokenIfStrong */);
+ verify(udfpsCallback).handleLifecycleAfterAuth();
+ }
+ }
+ }
+
+ @Test
+ public void testKeyguard_udfpsAuthSuccess_whileFaceScanning() {
+ mCoexCoordinator.reset();
+
+ AuthenticationClient<?> faceClient = mock(AuthenticationClient.class);
+ when(faceClient.isKeyguard()).thenReturn(true);
+ when(faceClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED);
+
+ AuthenticationClient<?> udfpsClient = mock(AuthenticationClient.class,
+ withSettings().extraInterfaces(Udfps.class));
+ when(udfpsClient.isKeyguard()).thenReturn(true);
+ when(((Udfps) udfpsClient).isPointerDown()).thenReturn(true);
+
+ mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, faceClient);
+ mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_UDFPS, udfpsClient);
+
+ mCoexCoordinator.onAuthenticationSucceeded(0 /* currentTimeMillis */, udfpsClient,
+ mCallback);
+ verify(mCallback).sendHapticFeedback();
+ verify(mCallback).sendAuthenticationResult(eq(true));
+ verify(faceClient).cancel();
+ verify(mCallback).handleLifecycleAfterAuth();
+ }
+
+ @Test
+ public void testKeyguard_faceRejectedWhenUdfpsTouching_thenUdfpsRejected() {
+ mCoexCoordinator.reset();
+
+ AuthenticationClient<?> faceClient = mock(AuthenticationClient.class);
+ when(faceClient.isKeyguard()).thenReturn(true);
+ when(faceClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED);
+
+ AuthenticationClient<?> udfpsClient = mock(AuthenticationClient.class,
+ withSettings().extraInterfaces(Udfps.class));
+ when(udfpsClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED);
+ when(udfpsClient.isKeyguard()).thenReturn(true);
+ when(((Udfps) udfpsClient).isPointerDown()).thenReturn(true);
+
+ mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, faceClient);
+ mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_UDFPS, udfpsClient);
+
+ mCoexCoordinator.onAuthenticationRejected(0 /* currentTimeMillis */, faceClient,
+ LockoutTracker.LOCKOUT_NONE, mCallback);
+ verify(mCallback, never()).sendHapticFeedback();
+ verify(mCallback).handleLifecycleAfterAuth();
+
+ // BiometricScheduler removes the face authentication client after rejection
+ mCoexCoordinator.removeAuthenticationClient(SENSOR_TYPE_FACE, faceClient);
+
+ // Then UDFPS rejected
+ CoexCoordinator.Callback udfpsCallback = mock(CoexCoordinator.Callback.class);
+ mCoexCoordinator.onAuthenticationRejected(1 /* currentTimeMillis */, udfpsClient,
+ LockoutTracker.LOCKOUT_NONE, udfpsCallback);
+ verify(udfpsCallback).sendHapticFeedback();
+ verify(udfpsCallback).sendAuthenticationResult(eq(false) /* addAuthTokenIfStrong */);
+ verify(mCallback, never()).sendHapticFeedback();
+ }
+
+ @Test
+ public void testKeyguard_udfpsRejected_thenFaceRejected() {
+ mCoexCoordinator.reset();
+
+ AuthenticationClient<?> faceClient = mock(AuthenticationClient.class);
+ when(faceClient.isKeyguard()).thenReturn(true);
+ when(faceClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED);
+
+ AuthenticationClient<?> udfpsClient = mock(AuthenticationClient.class,
+ withSettings().extraInterfaces(Udfps.class));
+ when(udfpsClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED);
+ when(udfpsClient.isKeyguard()).thenReturn(true);
+ when(((Udfps) udfpsClient).isPointerDown()).thenReturn(true);
+
+ mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, faceClient);
+ mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_UDFPS, udfpsClient);
+
+ mCoexCoordinator.onAuthenticationRejected(0 /* currentTimeMillis */, udfpsClient,
+ LockoutTracker.LOCKOUT_NONE, mCallback);
+ // Client becomes paused, but finger does not necessarily lift, since we suppress the haptic
+ when(udfpsClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED_PAUSED);
+ verify(mCallback, never()).sendHapticFeedback();
+ verify(mCallback).handleLifecycleAfterAuth();
+
+ // Then face rejected. Note that scheduler leaves UDFPS in the CoexCoordinator since
+ // unlike face, its lifecycle becomes "paused" instead of "finished".
+ CoexCoordinator.Callback faceCallback = mock(CoexCoordinator.Callback.class);
+ mCoexCoordinator.onAuthenticationRejected(1 /* currentTimeMillis */, faceClient,
+ LockoutTracker.LOCKOUT_NONE, faceCallback);
+ verify(faceCallback).sendHapticFeedback();
+ verify(faceCallback).sendAuthenticationResult(eq(false) /* addAuthTokenIfStrong */);
+ verify(mCallback, never()).sendHapticFeedback();
+ }
+
+ @Test
+ public void testNonKeyguard_rejectAndNotLockedOut() {
+ mCoexCoordinator.reset();
+
+ AuthenticationClient<?> faceClient = mock(AuthenticationClient.class);
+ when(faceClient.isKeyguard()).thenReturn(false);
+ when(faceClient.isBiometricPrompt()).thenReturn(true);
+
+ mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, faceClient);
+ mCoexCoordinator.onAuthenticationRejected(0 /* currentTimeMillis */, faceClient,
+ LockoutTracker.LOCKOUT_NONE, mCallback);
+
+ verify(mCallback).sendHapticFeedback();
+ verify(mCallback).sendAuthenticationResult(eq(false));
+ verify(mCallback).handleLifecycleAfterAuth();
+ }
+
+ @Test
+ public void testNonKeyguard_rejectLockedOut() {
+ mCoexCoordinator.reset();
+
+ AuthenticationClient<?> faceClient = mock(AuthenticationClient.class);
+ when(faceClient.isKeyguard()).thenReturn(false);
+ when(faceClient.isBiometricPrompt()).thenReturn(true);
+
+ mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, faceClient);
+ mCoexCoordinator.onAuthenticationRejected(0 /* currentTimeMillis */, faceClient,
+ LockoutTracker.LOCKOUT_TIMED, mCallback);
+
+ verify(mCallback).sendHapticFeedback();
+ verify(mCallback, never()).sendAuthenticationResult(anyBoolean());
+ verify(mCallback).handleLifecycleAfterAuth();
+ }
+
+ @Test
+ public void testCleanupRunnable() {
+ LinkedList<CoexCoordinator.SuccessfulAuth> successfulAuths = mock(LinkedList.class);
+ CoexCoordinator.SuccessfulAuth auth = mock(CoexCoordinator.SuccessfulAuth.class);
+ CoexCoordinator.Callback callback = mock(CoexCoordinator.Callback.class);
+ CoexCoordinator.SuccessfulAuth.CleanupRunnable runnable =
+ new CoexCoordinator.SuccessfulAuth.CleanupRunnable(successfulAuths, auth, callback);
+ runnable.run();
+
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+ verify(callback).handleLifecycleAfterAuth();
+ verify(successfulAuths).remove(eq(auth));
}
}
diff --git a/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java b/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java
index 1ad8850..cc3591c8 100644
--- a/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java
@@ -92,7 +92,6 @@
@Mock IThermalService mThermalServiceMock;
@Mock Injector mInjectorMock;
- @Mock BrightnessSetting mBrightnessSetting;
@Captor ArgumentCaptor<IThermalEventListener> mThermalEventListenerCaptor;
@@ -123,7 +122,7 @@
initHandler(null);
final HighBrightnessModeController hbmc = new HighBrightnessModeController(
mInjectorMock, mHandler, DISPLAY_WIDTH, DISPLAY_HEIGHT, mDisplayToken, DEFAULT_MIN,
- DEFAULT_MAX, null, () -> {}, mContextSpy, mBrightnessSetting);
+ DEFAULT_MAX, null, () -> {}, mContextSpy);
assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_OFF);
}
@@ -132,7 +131,7 @@
initHandler(null);
final HighBrightnessModeController hbmc = new HighBrightnessModeController(
mInjectorMock, mHandler, DISPLAY_WIDTH, DISPLAY_HEIGHT, mDisplayToken, DEFAULT_MIN,
- DEFAULT_MAX, null, () -> {}, mContextSpy, mBrightnessSetting);
+ DEFAULT_MAX, null, () -> {}, mContextSpy);
hbmc.setAutoBrightnessEnabled(true);
hbmc.onAmbientLuxChange(MINIMUM_LUX - 1); // below allowed range
assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_OFF);
@@ -464,7 +463,7 @@
initHandler(clock);
return new HighBrightnessModeController(mInjectorMock, mHandler, DISPLAY_WIDTH,
DISPLAY_HEIGHT, mDisplayToken, DEFAULT_MIN, DEFAULT_MAX, DEFAULT_HBM_DATA, () -> {},
- mContextSpy, mBrightnessSetting);
+ mContextSpy);
}
private void initHandler(OffsettableClock clock) {
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index a710839..e8c5fb3 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -520,10 +520,12 @@
final ParsedPackage pkg = new TestPackageParser2()
.parsePackage(testFile, 0 /*flags*/, false /*useCaches*/);
final List<String> compatPermissions =
- Arrays.stream(COMPAT_PERMS).map(p -> p.name).collect(toList());
+ Arrays.stream(COMPAT_PERMS).map(ParsedUsesPermission::getName)
+ .collect(toList());
assertWithMessage(
"Compatibility permissions shouldn't be added into uses permissions.")
- .that(pkg.getUsesPermissions().stream().map(p -> p.name).collect(toList()))
+ .that(pkg.getUsesPermissions().stream().map(ParsedUsesPermission::getName)
+ .collect(toList()))
.containsNoneIn(compatPermissions);
assertWithMessage(
"Compatibility permissions shouldn't be added into requested permissions.")
@@ -544,18 +546,19 @@
.parsePackage(testFile, 0 /*flags*/, false /*useCaches*/);
assertWithMessage(
"Compatibility permissions should be added into uses permissions.")
- .that(Arrays.stream(COMPAT_PERMS).map(p -> p.name)
- .allMatch(pkg.getUsesPermissions().stream().map(p -> p.name)
+ .that(Arrays.stream(COMPAT_PERMS).map(ParsedUsesPermission::getName)
+ .allMatch(pkg.getUsesPermissions().stream()
+ .map(ParsedUsesPermission::getName)
.collect(toList())::contains))
.isTrue();
assertWithMessage(
"Compatibility permissions should be added into requested permissions.")
- .that(Arrays.stream(COMPAT_PERMS).map(p -> p.name)
+ .that(Arrays.stream(COMPAT_PERMS).map(ParsedUsesPermission::getName)
.allMatch(pkg.getRequestedPermissions()::contains))
.isTrue();
assertWithMessage(
"Compatibility permissions should be added into implicit permissions.")
- .that(Arrays.stream(COMPAT_PERMS).map(p -> p.name)
+ .that(Arrays.stream(COMPAT_PERMS).map(ParsedUsesPermission::getName)
.allMatch(pkg.getImplicitPermissions()::contains))
.isTrue();
} finally {
@@ -954,8 +957,8 @@
.setVisibleToInstantApps(true)
.setSplitHasCode(0, true)
.hideAsParsed())
- .setBaseCodePath("foo5")
- .setCodePath("foo4")
+ .setBaseApkPath("foo5")
+ .setPath("foo4")
.setVersionCode(100)
.setRestrictUpdateHash(new byte[16])
.setVersionCodeMajor(100)
diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
index 8e1fc16..8153242 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
@@ -51,11 +51,11 @@
import android.util.Pair;
import com.android.server.compat.PlatformCompat;
-import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
import com.android.server.pm.parsing.PackageInfoUtils;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
@@ -241,7 +241,7 @@
.setPackageName("static.lib.pkg.123")
.setVersionCodeMajor(1)
.setVersionCode(234)
- .setBaseCodePath("/some/path.apk")
+ .setBaseApkPath("/some/path.apk")
.setSplitCodePaths(new String[] {"/some/other/path.apk"});
final PackageManagerService.ScanRequest scanRequest = new ScanRequestBuilder(pkg)
@@ -273,7 +273,7 @@
.hideAsParsed())
.setVersionCodeMajor(1)
.setVersionCode(234)
- .setBaseCodePath("/some/path.apk")
+ .setBaseApkPath("/some/path.apk")
.setSplitCodePaths(new String[] {"/some/other/path.apk"});
final PackageManagerService.ScanRequest scanRequest =
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
index bc0a540..16f72f7 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
@@ -23,7 +23,6 @@
import android.content.Context;
import android.content.pm.PackageManager;
-import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.dex.DexMetadataHelper;
import android.content.pm.parsing.ApkLite;
import android.content.pm.parsing.ApkLiteParseUtils;
@@ -137,25 +136,30 @@
}
private static void validatePackageDexMetadata(AndroidPackage pkg, boolean requireManifest)
- throws PackageParserException {
+ throws PackageManagerException {
Collection<String> apkToDexMetadataList =
AndroidPackageUtils.getPackageDexMetadata(pkg).values();
String packageName = pkg.getPackageName();
long versionCode = pkg.toAppInfoWithoutState().longVersionCode;
+ final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
for (String dexMetadata : apkToDexMetadataList) {
- DexMetadataHelper.validateDexMetadataFile(
- dexMetadata, packageName, versionCode, requireManifest);
+ final ParseResult result = DexMetadataHelper.validateDexMetadataFile(
+ input.reset(), dexMetadata, packageName, versionCode, requireManifest);
+ if (result.isError()) {
+ throw new PackageManagerException(
+ result.getErrorCode(), result.getErrorMessage(), result.getException());
+ }
}
}
private static void validatePackageDexMetatadataVaryingRequireManifest(ParsedPackage pkg)
- throws PackageParserException {
+ throws PackageManagerException {
validatePackageDexMetadata(pkg, /*requireManifest=*/true);
validatePackageDexMetadata(pkg, /*requireManifest=*/false);
}
@Test
- public void testParsePackageWithDmFileValid() throws IOException, PackageParserException {
+ public void testParsePackageWithDmFileValid() throws IOException, PackageManagerException {
copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base);
createDexMetadataFile("install_split_base.apk");
ParsedPackage pkg = new TestPackageParser2().parsePackage(mTmpDir, /*flags=*/0, false);
@@ -172,7 +176,7 @@
@Test
public void testParsePackageSplitsWithDmFileValid()
- throws IOException, PackageParserException {
+ throws IOException, PackageManagerException {
copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base);
copyApkToToTmpDir("install_split_feature_a.apk", R.raw.install_split_feature_a);
createDexMetadataFile("install_split_base.apk");
@@ -195,7 +199,7 @@
@Test
public void testParsePackageSplitsNoBaseWithDmFileValid()
- throws IOException, PackageParserException {
+ throws IOException, PackageManagerException {
copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base);
copyApkToToTmpDir("install_split_feature_a.apk", R.raw.install_split_feature_a);
createDexMetadataFile("install_split_feature_a.apk");
@@ -221,7 +225,7 @@
ParsedPackage pkg = new TestPackageParser2().parsePackage(mTmpDir, /*flags=*/0, false);
validatePackageDexMetadata(pkg, /*requireManifest=*/true);
fail("Should fail validation: empty .dm file");
- } catch (PackageParserException e) {
+ } catch (PackageManagerException e) {
assertEquals(e.error, PackageManager.INSTALL_FAILED_BAD_DEX_METADATA);
}
@@ -229,14 +233,14 @@
ParsedPackage pkg = new TestPackageParser2().parsePackage(mTmpDir, /*flags=*/0, false);
validatePackageDexMetadata(pkg, /*requireManifest=*/false);
fail("Should fail validation: empty .dm file");
- } catch (PackageParserException e) {
+ } catch (PackageManagerException e) {
assertEquals(e.error, PackageManager.INSTALL_FAILED_BAD_DEX_METADATA);
}
}
@Test
public void testParsePackageSplitsWithDmFileInvalid()
- throws IOException, PackageParserException {
+ throws IOException, PackageManagerException {
copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base);
copyApkToToTmpDir("install_split_feature_a.apk", R.raw.install_split_feature_a);
createDexMetadataFile("install_split_base.apk");
@@ -247,7 +251,7 @@
ParsedPackage pkg = new TestPackageParser2().parsePackage(mTmpDir, /*flags=*/0, false);
validatePackageDexMetadata(pkg, /*requireManifest=*/true);
fail("Should fail validation: empty .dm file");
- } catch (PackageParserException e) {
+ } catch (PackageManagerException e) {
assertEquals(e.error, PackageManager.INSTALL_FAILED_BAD_DEX_METADATA);
}
@@ -255,14 +259,14 @@
ParsedPackage pkg = new TestPackageParser2().parsePackage(mTmpDir, /*flags=*/0, false);
validatePackageDexMetadata(pkg, /*requireManifest=*/false);
fail("Should fail validation: empty .dm file");
- } catch (PackageParserException e) {
+ } catch (PackageManagerException e) {
assertEquals(e.error, PackageManager.INSTALL_FAILED_BAD_DEX_METADATA);
}
}
@Test
public void testParsePackageWithDmFileInvalidManifest()
- throws IOException, PackageParserException {
+ throws IOException, PackageManagerException {
copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base);
createDexMetadataFile("install_split_base.apk", /*validManifest=*/false);
@@ -270,14 +274,14 @@
ParsedPackage pkg = new TestPackageParser2().parsePackage(mTmpDir, /*flags=*/0, false);
validatePackageDexMetadata(pkg, /*requireManifest=*/true);
fail("Should fail validation: missing manifest.json in the .dm archive");
- } catch (PackageParserException e) {
+ } catch (PackageManagerException e) {
assertEquals(e.error, PackageManager.INSTALL_FAILED_BAD_DEX_METADATA);
}
}
@Test
public void testParsePackageWithDmFileEmptyManifest()
- throws IOException, PackageParserException {
+ throws IOException, PackageManagerException {
copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base);
createDexMetadataFile("install_split_base.apk", /*packageName=*/"doesn't matter",
/*versionCode=*/-12345L, /*emptyManifest=*/true, /*validManifest=*/true);
@@ -286,14 +290,14 @@
ParsedPackage pkg = new TestPackageParser2().parsePackage(mTmpDir, /*flags=*/0, false);
validatePackageDexMetadata(pkg, /*requireManifest=*/true);
fail("Should fail validation: empty manifest.json in the .dm archive");
- } catch (PackageParserException e) {
+ } catch (PackageManagerException e) {
assertEquals(e.error, PackageManager.INSTALL_FAILED_BAD_DEX_METADATA);
}
}
@Test
public void testParsePackageWithDmFileBadPackageName()
- throws IOException, PackageParserException {
+ throws IOException, PackageManagerException {
copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base);
createDexMetadataFile("install_split_base.apk", /*packageName=*/"bad package name",
DEX_METADATA_VERSION_CODE, /*emptyManifest=*/false, /*validManifest=*/true);
@@ -302,14 +306,14 @@
ParsedPackage pkg = new TestPackageParser2().parsePackage(mTmpDir, /*flags=*/0, false);
validatePackageDexMetadata(pkg, /*requireManifest=*/true);
fail("Should fail validation: bad package name in the .dm archive");
- } catch (PackageParserException e) {
+ } catch (PackageManagerException e) {
assertEquals(e.error, PackageManager.INSTALL_FAILED_BAD_DEX_METADATA);
}
}
@Test
public void testParsePackageWithDmFileBadVersionCode()
- throws IOException, PackageParserException {
+ throws IOException, PackageManagerException {
copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base);
createDexMetadataFile("install_split_base.apk", DEX_METADATA_PACKAGE_NAME,
/*versionCode=*/12345L, /*emptyManifest=*/false, /*validManifest=*/true);
@@ -318,14 +322,14 @@
ParsedPackage pkg = new TestPackageParser2().parsePackage(mTmpDir, /*flags=*/0, false);
validatePackageDexMetadata(pkg, /*requireManifest=*/true);
fail("Should fail validation: bad version code in the .dm archive");
- } catch (PackageParserException e) {
+ } catch (PackageManagerException e) {
assertEquals(e.error, PackageManager.INSTALL_FAILED_BAD_DEX_METADATA);
}
}
@Test
public void testParsePackageWithDmFileMissingPackageName()
- throws IOException, PackageParserException {
+ throws IOException, PackageManagerException {
copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base);
createDexMetadataFile("install_split_base.apk", /*packageName=*/null,
DEX_METADATA_VERSION_CODE, /*emptyManifest=*/false, /*validManifest=*/true);
@@ -334,14 +338,14 @@
ParsedPackage pkg = new TestPackageParser2().parsePackage(mTmpDir, /*flags=*/0, false);
validatePackageDexMetadata(pkg, /*requireManifest=*/true);
fail("Should fail validation: missing package name in the .dm archive");
- } catch (PackageParserException e) {
+ } catch (PackageManagerException e) {
assertEquals(e.error, PackageManager.INSTALL_FAILED_BAD_DEX_METADATA);
}
}
@Test
public void testParsePackageWithDmFileMissingVersionCode()
- throws IOException, PackageParserException {
+ throws IOException, PackageManagerException {
copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base);
createDexMetadataFile("install_split_base.apk", DEX_METADATA_PACKAGE_NAME,
/*versionCode=*/null, /*emptyManifest=*/false, /*validManifest=*/true);
@@ -350,7 +354,7 @@
ParsedPackage pkg = new TestPackageParser2().parsePackage(mTmpDir, /*flags=*/0, false);
validatePackageDexMetadata(pkg, /*requireManifest=*/true);
fail("Should fail validation: missing version code in the .dm archive");
- } catch (PackageParserException e) {
+ } catch (PackageManagerException e) {
assertEquals(e.error, PackageManager.INSTALL_FAILED_BAD_DEX_METADATA);
}
}
@@ -370,7 +374,7 @@
@Test
public void testPackageSplitsWithDmFileNoMatch()
- throws IOException, PackageParserException {
+ throws IOException {
copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base);
copyApkToToTmpDir("install_split_feature_a.apk", R.raw.install_split_feature_a);
createDexMetadataFile("install_split_base.apk");
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
index c2b3858..1502839 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
@@ -17,7 +17,6 @@
package com.android.server.pm.parsing;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -29,12 +28,14 @@
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
import android.content.pm.PermissionInfo;
+import android.content.pm.SigningDetails;
import android.content.pm.parsing.PackageInfoWithoutStateUtils;
import android.content.pm.parsing.ParsingPackage;
import android.content.pm.parsing.ParsingPackageUtils;
import android.content.pm.parsing.component.ParsedComponent;
import android.content.pm.parsing.component.ParsedPermission;
import android.content.pm.parsing.result.ParseResult;
+import android.content.pm.parsing.result.ParseTypeImpl;
import android.os.Build;
import android.os.Bundle;
import android.os.FileUtils;
@@ -48,6 +49,7 @@
import com.android.frameworks.servicestests.R;
import com.android.internal.util.ArrayUtils;
+import com.android.server.pm.PackageManagerException;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.parsing.pkg.ParsedPackage;
@@ -335,7 +337,7 @@
* Copies a specified {@code resourceId} to a file. Returns a non-null file if the copy
* succeeded, or {@code null} otherwise.
*/
- File copyRawResourceToFile(String baseName, int resourceId) throws Exception {
+ File copyRawResourceToFile(String baseName, int resourceId) {
// Copy the resource to a file.
Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
InputStream is = context.getResources().openRawResource(resourceId);
@@ -537,8 +539,14 @@
throw new IllegalStateException(result.getErrorMessage(), result.getException());
}
+ ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
ParsingPackage pkg = result.getResult();
- pkg.setSigningDetails(ParsingPackageUtils.getSigningDetails(pkg, false));
+ ParseResult<SigningDetails> ret = ParsingPackageUtils.getSigningDetails(
+ input, pkg, false /*skipVerify*/);
+ if (ret.isError()) {
+ throw new IllegalStateException(ret.getErrorMessage(), ret.getException());
+ }
+ pkg.setSigningDetails(ret.getResult());
PackageInfo pi = PackageInfoWithoutStateUtils.generate(pkg, apexInfo, flags);
assertEquals("com.google.android.tzdata", pi.applicationInfo.packageName);
@@ -596,7 +604,7 @@
try {
parsePackage(filename, resId, x -> x);
expect.withMessage("Expected parsing error %d from %s", result, filename).fail();
- } catch (PackageParser.PackageParserException expected) {
+ } catch (PackageManagerException expected) {
expect.that(expected.error).isEqualTo(result);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/SystemPartitionParseTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/SystemPartitionParseTest.kt
index 4cd057c..ffa1957 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/SystemPartitionParseTest.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/SystemPartitionParseTest.kt
@@ -17,8 +17,9 @@
package com.android.server.pm.parsing
import android.content.pm.PackageManager
-import android.content.pm.PackageParser
+import android.content.pm.parsing.ParsingPackageUtils
import android.platform.test.annotations.Postsubmit
+import com.android.server.pm.PackageManagerException
import com.android.server.pm.PackageManagerService
import com.android.server.pm.PackageManagerServiceUtils
import org.junit.Rule
@@ -80,11 +81,12 @@
val exceptions = buildApks()
.map {
runCatching {
- parser.parsePackage(it, PackageParser.PARSE_IS_SYSTEM_DIR, false)
+ parser.parsePackage(
+ it, ParsingPackageUtils.PARSE_IS_SYSTEM_DIR, false /*useCaches*/)
}
}
.mapNotNull { it.exceptionOrNull() }
- .filterNot { (it as? PackageParser.PackageParserException)?.error ==
+ .filterNot { (it as? PackageManagerException)?.error ==
PackageManager.INSTALL_PARSE_FAILED_SKIPPED }
if (exceptions.isEmpty()) return
diff --git a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
index 9044b27..5eb21a5 100644
--- a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
@@ -19,6 +19,7 @@
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
+import static org.testng.Assert.expectThrows;
import android.platform.test.annotations.Presubmit;
import android.util.ArrayMap;
@@ -200,6 +201,46 @@
assertThat(mSysConfig.getWhitelistedStagedInstallers())
.containsExactly("com.android.package1");
+ assertThat(mSysConfig.getModulesInstallerPackageName()).isNull();
+ }
+
+ @Test
+ public void readPermissions_parsesStagedInstallerWhitelist_modulesInstaller()
+ throws IOException {
+ final String contents =
+ "<config>\n"
+ + " <whitelisted-staged-installer package=\"com.android.package1\" "
+ + " isModulesInstaller=\"true\" />\n"
+ + "</config>";
+ final File folder = createTempSubfolder("folder");
+ createTempFile(folder, "staged-installer-whitelist.xml", contents);
+
+ mSysConfig.readPermissions(folder, /* Grant all permission flags */ ~0);
+
+ assertThat(mSysConfig.getWhitelistedStagedInstallers())
+ .containsExactly("com.android.package1");
+ assertThat(mSysConfig.getModulesInstallerPackageName())
+ .isEqualTo("com.android.package1");
+ }
+
+ @Test
+ public void readPermissions_parsesStagedInstallerWhitelist_multipleModulesInstallers()
+ throws IOException {
+ final String contents =
+ "<config>\n"
+ + " <whitelisted-staged-installer package=\"com.android.package1\" "
+ + " isModulesInstaller=\"true\" />\n"
+ + " <whitelisted-staged-installer package=\"com.android.package2\" "
+ + " isModulesInstaller=\"true\" />\n"
+ + "</config>";
+ final File folder = createTempSubfolder("folder");
+ createTempFile(folder, "staged-installer-whitelist.xml", contents);
+
+ IllegalStateException e = expectThrows(
+ IllegalStateException.class,
+ () -> mSysConfig.readPermissions(folder, /* Grant all permission flags */ ~0));
+
+ assertThat(e).hasMessageThat().contains("Multiple modules installers");
}
/**
@@ -230,14 +271,16 @@
throws IOException {
final String contents =
"<config>\n"
- + " <allowed-vendor-apex package=\"com.android.apex1\" />\n"
+ + " <allowed-vendor-apex package=\"com.android.apex1\" "
+ + "installerPackage=\"com.installer\" />\n"
+ "</config>";
final File folder = createTempSubfolder("folder");
createTempFile(folder, "vendor-apex-allowlist.xml", contents);
mSysConfig.readPermissions(folder, /* Grant all permission flags */ ~0);
- assertThat(mSysConfig.getAllowedVendorApexes()).containsExactly("com.android.apex1");
+ assertThat(mSysConfig.getAllowedVendorApexes())
+ .containsExactly("com.android.apex1", "com.installer");
}
/**
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 fef7168..e367579 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -2590,7 +2590,6 @@
false /* activityCreate */, false /* suggestEmpty */);
waitUntilHandlersIdle();
assertHasStartingWindow(activity);
- activity.mStartingWindowState = ActivityRecord.STARTING_WINDOW_SHOWN;
doCallRealMethod().when(task).startActivityLocked(
any(), any(), anyBoolean(), anyBoolean(), any(), any());
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
index c555612..3a6aac9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -19,6 +19,7 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
@@ -27,6 +28,7 @@
import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE;
import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN;
import static android.view.WindowManager.TRANSIT_OPEN;
+import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -167,6 +169,69 @@
assertFalse(mAppTransitionController.isTransitWithinTask(TRANSIT_OLD_TASK_OPEN, task));
}
+
+ @Test
+ public void testIntraWallpaper_open() {
+ final ActivityRecord opening = createActivityRecord(mDisplayContent,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ opening.setVisible(false);
+ final WindowManager.LayoutParams attrOpening = new WindowManager.LayoutParams(
+ TYPE_BASE_APPLICATION);
+ attrOpening.setTitle("WallpaperOpening");
+ attrOpening.flags |= FLAG_SHOW_WALLPAPER;
+ final TestWindowState appWindowOpening = createWindowState(attrOpening, opening);
+ opening.addWindow(appWindowOpening);
+
+ final ActivityRecord closing = createActivityRecord(mDisplayContent,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ final WindowManager.LayoutParams attrClosing = new WindowManager.LayoutParams(
+ TYPE_BASE_APPLICATION);
+ attrOpening.setTitle("WallpaperClosing");
+ attrClosing.flags |= FLAG_SHOW_WALLPAPER;
+ final TestWindowState appWindowClosing = createWindowState(attrClosing, closing);
+ closing.addWindow(appWindowClosing);
+
+ mDisplayContent.prepareAppTransition(TRANSIT_OPEN);
+ mDisplayContent.mOpeningApps.add(opening);
+ mDisplayContent.mClosingApps.add(closing);
+
+ assertEquals(WindowManager.TRANSIT_OLD_WALLPAPER_INTRA_OPEN,
+ AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition,
+ mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
+ appWindowClosing, null, false));
+ }
+
+ @Test
+ public void testIntraWallpaper_toFront() {
+ final ActivityRecord opening = createActivityRecord(mDisplayContent,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ opening.setVisible(false);
+ final WindowManager.LayoutParams attrOpening = new WindowManager.LayoutParams(
+ TYPE_BASE_APPLICATION);
+ attrOpening.setTitle("WallpaperOpening");
+ attrOpening.flags |= FLAG_SHOW_WALLPAPER;
+ final TestWindowState appWindowOpening = createWindowState(attrOpening, opening);
+ opening.addWindow(appWindowOpening);
+
+ final ActivityRecord closing = createActivityRecord(mDisplayContent,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ final WindowManager.LayoutParams attrClosing = new WindowManager.LayoutParams(
+ TYPE_BASE_APPLICATION);
+ attrOpening.setTitle("WallpaperClosing");
+ attrClosing.flags |= FLAG_SHOW_WALLPAPER;
+ final TestWindowState appWindowClosing = createWindowState(attrClosing, closing);
+ closing.addWindow(appWindowClosing);
+
+ mDisplayContent.prepareAppTransition(TRANSIT_TO_FRONT);
+ mDisplayContent.mOpeningApps.add(opening);
+ mDisplayContent.mClosingApps.add(closing);
+
+ assertEquals(WindowManager.TRANSIT_OLD_WALLPAPER_INTRA_OPEN,
+ AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition,
+ mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
+ appWindowClosing, null, false));
+ }
+
@Test
public void testGetAnimationTargets_visibilityAlreadyUpdated() {
// [DisplayContent] -+- [Task1] - [ActivityRecord1] (opening, visible)
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
index c4faaa3..1f123cc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
@@ -24,6 +24,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER;
import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;
+import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_LAST;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -57,6 +58,7 @@
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Binder;
+import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
import android.view.SurfaceControl;
import android.view.View;
@@ -556,6 +558,7 @@
final DisplayArea<WindowContainer> displayArea = new DisplayArea<>(
mWm, BELOW_TASKS, "NewArea", FEATURE_VENDOR_FIRST);
final IDisplayAreaOrganizer mockDisplayAreaOrganizer = mock(IDisplayAreaOrganizer.class);
+ doReturn(mock(IBinder.class)).when(mockDisplayAreaOrganizer).asBinder();
displayArea.mOrganizer = mockDisplayAreaOrganizer;
spyOn(mWm.mAtmService.mWindowOrganizerController.mDisplayAreaOrganizerController);
mDisplayContent.addChild(displayArea, 0);
@@ -592,6 +595,30 @@
assertThat(info2.rootDisplayAreaId).isEqualTo(root.mFeatureId);
}
+ @Test
+ public void testRegisterSameFeatureOrganizer_expectThrowsException() {
+ final IDisplayAreaOrganizer mockDisplayAreaOrganizer = mock(IDisplayAreaOrganizer.class);
+ final IBinder binder = mock(IBinder.class);
+ doReturn(true).when(binder).isBinderAlive();
+ doReturn(binder).when(mockDisplayAreaOrganizer).asBinder();
+ final DisplayAreaOrganizerController controller =
+ mWm.mAtmService.mWindowOrganizerController.mDisplayAreaOrganizerController;
+ controller.registerOrganizer(mockDisplayAreaOrganizer, FEATURE_VENDOR_FIRST);
+ assertThrows(IllegalStateException.class,
+ () -> controller.registerOrganizer(mockDisplayAreaOrganizer, FEATURE_VENDOR_FIRST));
+ }
+
+ @Test
+ public void testRegisterUnregisterOrganizer() {
+ final IDisplayAreaOrganizer mockDisplayAreaOrganizer = mock(IDisplayAreaOrganizer.class);
+ doReturn(mock(IBinder.class)).when(mockDisplayAreaOrganizer).asBinder();
+ final DisplayAreaOrganizerController controller =
+ mWm.mAtmService.mWindowOrganizerController.mDisplayAreaOrganizerController;
+ controller.registerOrganizer(mockDisplayAreaOrganizer, FEATURE_VENDOR_FIRST);
+ controller.unregisterOrganizer(mockDisplayAreaOrganizer);
+ controller.registerOrganizer(mockDisplayAreaOrganizer, FEATURE_VENDOR_FIRST);
+ }
+
private static class TestDisplayArea<T extends WindowContainer> extends DisplayArea<T> {
private TestDisplayArea(WindowManagerService wms, Rect bounds) {
super(wms, ANY, "half display area");
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java b/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
index 7ebf775..6cc60ea 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
@@ -30,7 +30,6 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doCallRealMethod;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
@@ -90,9 +89,6 @@
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.util.ArrayList;
-import java.util.function.Consumer;
-
/**
* Tests for the root {@link Task} behavior.
*
@@ -1506,41 +1502,6 @@
}
@Test
- public void testIterateOccludedActivity() {
- final ArrayList<ActivityRecord> occludedActivities = new ArrayList<>();
- final Consumer<ActivityRecord> handleOccludedActivity = occludedActivities::add;
- final Task task = new TaskBuilder(mSupervisor).build();
- final ActivityRecord bottomActivity = new ActivityBuilder(mAtm).setTask(task).build();
- final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(task).build();
- // Top activity occludes bottom activity.
- doReturn(true).when(task).shouldBeVisible(any());
- assertTrue(topActivity.shouldBeVisible());
- assertFalse(bottomActivity.shouldBeVisible());
-
- task.forAllOccludedActivities(handleOccludedActivity);
- assertThat(occludedActivities).containsExactly(bottomActivity);
-
- // Top activity doesn't occlude parent, so the bottom activity is not occluded.
- doReturn(false).when(topActivity).occludesParent();
- assertTrue(bottomActivity.shouldBeVisible());
-
- occludedActivities.clear();
- task.forAllOccludedActivities(handleOccludedActivity);
- assertThat(occludedActivities).isEmpty();
-
- // A finishing activity should not occlude other activities behind.
- final ActivityRecord finishingActivity = new ActivityBuilder(mAtm).setTask(task).build();
- finishingActivity.finishing = true;
- doCallRealMethod().when(finishingActivity).occludesParent();
- assertTrue(topActivity.shouldBeVisible());
- assertTrue(bottomActivity.shouldBeVisible());
-
- occludedActivities.clear();
- task.forAllOccludedActivities(handleOccludedActivity);
- assertThat(occludedActivities).isEmpty();
- }
-
- @Test
public void testClearUnknownAppVisibilityBehindFullscreenActivity() {
final UnknownAppVisibilityController unknownAppVisibilityController =
mDefaultTaskDisplayArea.mDisplayContent.mUnknownAppVisibilityController;
@@ -1564,14 +1525,13 @@
}
mSupervisor.endDeferResume();
- setBooted(mAtm);
// 2 activities are started while keyguard is locked, so they are waiting to be resolved.
assertFalse(unknownAppVisibilityController.allResolved());
- // Assume the top activity is going to resume and
- // {@link RootWindowContainer#cancelInitializingActivities} should clear the unknown
- // visibility records that are occluded.
- task.resumeTopActivityUncheckedLocked(null /* prev */, null /* options */);
+ // Any common path that updates activity visibility should clear the unknown visibility
+ // records that are no longer visible according to hierarchy.
+ task.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
+ false /* preserveWindows */);
// Assume the top activity relayouted, just remove it directly.
unknownAppVisibilityController.appRemovedOrHidden(activities[1]);
// All unresolved records should be removed.
diff --git a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
index e32b2aa..cac948c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
+++ b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
@@ -270,4 +270,10 @@
public SurfaceControl.Transaction setColorSpace(SurfaceControl sc, ColorSpace colorSpace) {
return this;
}
+
+ @Override
+ public SurfaceControl.Transaction setTrustedOverlay(SurfaceControl sc,
+ boolean isTrustedOverlay) {
+ return this;
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
index ac981cf..025da84 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
@@ -16,8 +16,6 @@
package com.android.server.wm;
-import static android.window.TaskFragmentOrganizer.putExceptionInBundle;
-
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.server.wm.testing.Assert.assertThrows;
@@ -35,7 +33,6 @@
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Binder;
-import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
@@ -198,9 +195,11 @@
public void testOnTaskFragmentError() throws RemoteException {
final IBinder errorCallbackToken = new Binder();
final Throwable exception = new IllegalArgumentException("Test exception");
- final Bundle exceptionBundle = putExceptionInBundle(exception);
- mIOrganizer.onTaskFragmentError(errorCallbackToken, exceptionBundle);
+ mController.registerOrganizer(mIOrganizer);
+ mController.onTaskFragmentError(mTaskFragment.getTaskFragmentOrganizer(),
+ errorCallbackToken, exception);
+ mController.dispatchPendingEvents();
verify(mOrganizer).onTaskFragmentError(eq(errorCallbackToken), eq(exception));
}
@@ -320,7 +319,7 @@
// Allow organizer to create TaskFragment and start/reparent activity to TaskFragment.
mTransaction.createTaskFragment(mock(TaskFragmentCreationParams.class));
mTransaction.startActivityInTaskFragment(
- mFragmentToken, new Intent(), null /* activityOptions */);
+ mFragmentToken, null /* callerToken */, new Intent(), null /* activityOptions */);
mTransaction.reparentActivityToTaskFragment(mFragmentToken, mock(IBinder.class));
// It is expected to fail for the mock TaskFragmentCreationParams. It is ok as we are
diff --git a/tests/StagedInstallTest/Android.bp b/tests/StagedInstallTest/Android.bp
index 1aa0499..cac14a7 100644
--- a/tests/StagedInstallTest/Android.bp
+++ b/tests/StagedInstallTest/Android.bp
@@ -32,6 +32,7 @@
test_suites: ["general-tests"],
java_resources: [
":com.android.apex.apkrollback.test_v2",
+ ":StagedInstallTestApexV2",
":StagedInstallTestApexV2_WrongSha",
":test.rebootless_apex_v1",
":test.rebootless_apex_v2",
diff --git a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
index 738e68e..4684f01 100644
--- a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
@@ -55,8 +55,11 @@
private static final TestApp TEST_APEX_WITH_APK_V2 = new TestApp("TestApexWithApkV2",
APK_IN_APEX_TESTAPEX_NAME, 2, /*isApex*/true, APK_IN_APEX_TESTAPEX_NAME + "_v2.apex");
private static final TestApp APEX_WRONG_SHA_V2 = new TestApp(
- "ApexWrongSha2", SHIM_APEX_PACKAGE_NAME, 2, /*isApex*/true,
+ "ApexWrongSha2", SHIM_APEX_PACKAGE_NAME, 2, /* isApex= */ true,
"com.android.apex.cts.shim.v2_wrong_sha.apex");
+ private static final TestApp APEX_V2 = new TestApp(
+ "ApexV2", SHIM_APEX_PACKAGE_NAME, 2, /* isApex= */ true,
+ "com.android.apex.cts.shim.v2.apex");
private File mTestStateFile = new File(
InstrumentationRegistry.getInstrumentation().getContext().getFilesDir(),
@@ -237,6 +240,96 @@
}
@Test
+ public void testApexInstallerNotInAllowListCanNotInstall_staged() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1);
+ // We don't really care which APEX we are trying to install here, since the session creation
+ // should fail immediately.
+ InstallUtils.commitExpectingFailure(
+ SecurityException.class,
+ "Installer not allowed to commit staged install",
+ Install.single(APEX_WRONG_SHA_V2).setBypassStangedInstallerCheck(false)
+ .setStaged());
+ }
+
+ @Test
+ public void testApexInstallerNotInAllowListCanNotInstall_nonStaged() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1);
+ // We don't really care which APEX we are trying to install here, since the session creation
+ // should fail immediately.
+ InstallUtils.commitExpectingFailure(
+ SecurityException.class,
+ "Installer not allowed to commit non-staged APEX install",
+ Install.single(APEX_WRONG_SHA_V2).setBypassStangedInstallerCheck(false));
+ }
+
+ @Test
+ public void testApexNotInAllowListCanNotInstall_staged() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(1);
+ TestApp apex = new TestApp("apex", "test.apex.rebootless", 2,
+ /* isApex= */ true, "test.rebootless_apex_v2.apex");
+ InstallUtils.commitExpectingFailure(
+ AssertionError.class,
+ "Update of APEX package test.apex.rebootless is not allowed "
+ + "for com.android.tests.stagedinstallinternal",
+ Install.single(apex).setBypassAllowedApexUpdateCheck(false).setStaged());
+ }
+
+ @Test
+ public void testApexNotInAllowListCanNotInstall_nonStaged() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(1);
+ TestApp apex = new TestApp("apex", "test.apex.rebootless", 2,
+ /* isApex= */ true, "test.rebootless_apex_v2.apex");
+ InstallUtils.commitExpectingFailure(
+ AssertionError.class,
+ "Update of APEX package test.apex.rebootless is not allowed "
+ + "for com.android.tests.stagedinstallinternal",
+ Install.single(apex).setBypassAllowedApexUpdateCheck(false));
+ }
+
+ @Test
+ public void testVendorApexWrongInstaller_staged() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(1);
+ TestApp apex = new TestApp("apex", "test.apex.rebootless", 2,
+ /* isApex= */ true, "test.rebootless_apex_v2.apex");
+ InstallUtils.commitExpectingFailure(
+ AssertionError.class,
+ "Update of APEX package test.apex.rebootless is not allowed "
+ + "for com.android.tests.stagedinstallinternal",
+ Install.single(apex).setBypassAllowedApexUpdateCheck(false).setStaged());
+ }
+
+ @Test
+ public void testVendorApexWrongInstaller_nonStaged() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(1);
+ TestApp apex = new TestApp("apex", "test.apex.rebootless", 2,
+ /* isApex= */ true, "test.rebootless_apex_v2.apex");
+ InstallUtils.commitExpectingFailure(
+ AssertionError.class,
+ "Update of APEX package test.apex.rebootless is not allowed "
+ + "for com.android.tests.stagedinstallinternal",
+ Install.single(apex).setBypassAllowedApexUpdateCheck(false));
+ }
+
+ @Test
+ public void testVendorApexCorrectInstaller_staged() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(1);
+ TestApp apex = new TestApp("apex", "test.apex.rebootless", 2,
+ /* isApex= */ true, "test.rebootless_apex_v2.apex");
+ int sessionId =
+ Install.single(apex).setBypassAllowedApexUpdateCheck(false).setStaged().commit();
+ InstallUtils.getPackageInstaller().abandonSession(sessionId);
+ }
+
+ @Test
+ public void testVendorApexCorrectInstaller_nonStaged() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(1);
+ TestApp apex = new TestApp("apex", "test.apex.rebootless", 2,
+ /* isApex= */ true, "test.rebootless_apex_v2.apex");
+ Install.single(apex).setBypassAllowedApexUpdateCheck(false).commit();
+ assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(2);
+ }
+
+ @Test
public void testRebootlessUpdates() throws Exception {
InstallUtils.dropShellPermissionIdentity();
InstallUtils.adoptShellPermissionIdentity(Manifest.permission.INSTALL_PACKAGE_UPDATES);
@@ -298,6 +391,19 @@
}
}
+ @Test
+ public void testRebootlessUpdate_hasStagedSessionWithSameApex_fails() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1);
+
+ int sessionId = Install.single(APEX_V2).setStaged().commit();
+ assertSessionReady(sessionId);
+ InstallUtils.commitExpectingFailure(
+ AssertionError.class,
+ "Staged session " + sessionId + " already contains " + SHIM_APEX_PACKAGE_NAME,
+ Install.single(APEX_V2));
+
+ }
+
private static void assertSessionApplied(int sessionId) {
assertSessionState(sessionId, (session) -> {
assertThat(session.isStagedSessionApplied()).isTrue();
diff --git a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
index 3bd3767..5021009 100644
--- a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
@@ -43,7 +43,9 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.io.BufferedWriter;
import java.io.File;
+import java.io.FileWriter;
import java.util.List;
import java.util.stream.Collectors;
@@ -60,6 +62,9 @@
private static final String APK_A = "TestAppAv1.apk";
private static final String APK_IN_APEX_TESTAPEX_NAME = "com.android.apex.apkrollback.test";
+ private static final String TEST_VENDOR_APEX_ALLOW_LIST =
+ "/vendor/etc/sysconfig/test-vendor-apex-allow-list.xml";
+
private final InstallUtilsHost mHostUtils = new InstallUtilsHost(this);
/**
@@ -87,7 +92,8 @@
"/data/apex/active/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex",
"/data/apex/active/" + SHIM_APEX_PACKAGE_NAME + "*.apex",
"/system/apex/test.rebootless_apex_v1.apex",
- "/data/apex/active/test.apex.rebootless*.apex");
+ "/data/apex/active/test.apex.rebootless*.apex",
+ TEST_VENDOR_APEX_ALLOW_LIST);
}
@Before
@@ -134,7 +140,23 @@
}
getDevice().remountSystemWritable();
assertTrue(getDevice().pushFile(apex, "/system/apex/" + fileName));
- getDevice().reboot();
+ }
+
+ private void pushTestVendorApexAllowList(String installerPackageName) throws Exception {
+ if (!getDevice().isAdbRoot()) {
+ getDevice().enableAdbRoot();
+ }
+ getDevice().remountSystemWritable();
+ File file = File.createTempFile("test-vendor-apex-allow-list", ".xml");
+ try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
+ final String fmt =
+ "<config>\n"
+ + " <allowed-vendor-apex package=\"test.apex.rebootless\" "
+ + " installerPackage=\"%s\" />\n"
+ + "</config>";
+ writer.write(String.format(fmt, installerPackageName));
+ }
+ getDevice().pushFile(file, TEST_VENDOR_APEX_ALLOW_LIST);
}
/**
@@ -144,6 +166,8 @@
@LargeTest
public void testDuplicateApkInApexShouldFail() throws Exception {
pushTestApex(APK_IN_APEX_TESTAPEX_NAME + "_v1.apex");
+ getDevice().reboot();
+
runPhase("testDuplicateApkInApexShouldFail_Commit");
getDevice().reboot();
runPhase("testDuplicateApkInApexShouldFail_Verify");
@@ -389,11 +413,71 @@
}
@Test
+ public void testApexInstallerNotInAllowListCanNotInstall() throws Exception {
+ assumeTrue("Device does not support updating APEX",
+ mHostUtils.isApexUpdateSupported());
+
+ runPhase("testApexInstallerNotInAllowListCanNotInstall_staged");
+ runPhase("testApexInstallerNotInAllowListCanNotInstall_nonStaged");
+ }
+
+ @Test
+ @LargeTest
+ public void testApexNotInAllowListCanNotInstall() throws Exception {
+ assumeTrue("Device does not support updating APEX",
+ mHostUtils.isApexUpdateSupported());
+
+ pushTestApex("test.rebootless_apex_v1.apex");
+ getDevice().reboot();
+
+ runPhase("testApexNotInAllowListCanNotInstall_staged");
+ runPhase("testApexNotInAllowListCanNotInstall_nonStaged");
+ }
+
+ @Test
+ @LargeTest
+ public void testVendorApexWrongInstaller() throws Exception {
+ assumeTrue("Device does not support updating APEX",
+ mHostUtils.isApexUpdateSupported());
+
+ pushTestVendorApexAllowList("com.wrong.installer");
+ pushTestApex("test.rebootless_apex_v1.apex");
+ getDevice().reboot();
+
+ runPhase("testVendorApexWrongInstaller_staged");
+ runPhase("testVendorApexWrongInstaller_nonStaged");
+ }
+
+ @Test
+ @LargeTest
+ public void testVendorApexCorrectInstaller() throws Exception {
+ assumeTrue("Device does not support updating APEX",
+ mHostUtils.isApexUpdateSupported());
+
+ pushTestVendorApexAllowList("com.android.tests.stagedinstallinternal");
+ pushTestApex("test.rebootless_apex_v1.apex");
+ getDevice().reboot();
+
+ runPhase("testVendorApexCorrectInstaller_staged");
+ runPhase("testVendorApexCorrectInstaller_nonStaged");
+ }
+
+ @Test
public void testRebootlessUpdates() throws Exception {
pushTestApex("test.rebootless_apex_v1.apex");
+ getDevice().reboot();
+
runPhase("testRebootlessUpdates");
}
+ @Test
+ public void testRebootlessUpdate_hasStagedSessionWithSameApex_fails() throws Exception {
+ assumeTrue("Device does not support updating APEX",
+ mHostUtils.isApexUpdateSupported());
+
+ runPhase("testRebootlessUpdate_hasStagedSessionWithSameApex_fails");
+ }
+
private List<String> getStagingDirectories() throws DeviceNotAvailableException {
String baseDir = "/data/app-staging";
try {
diff --git a/tests/vcn/java/com/android/server/vcn/VcnNetworkProviderTest.java b/tests/vcn/java/com/android/server/vcn/VcnNetworkProviderTest.java
index 72db55b..e9026e2 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnNetworkProviderTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnNetworkProviderTest.java
@@ -87,8 +87,8 @@
eq(mVcnNetworkProvider),
argThat(
score ->
- score.getLegacyInt()
- == Vcn.getNetworkScore().getLegacyInt()),
+ score.getLegacyInt() == Vcn.getNetworkScore().getLegacyInt()
+ && score.isTransportPrimary()),
any(),
any(),
cbCaptor.capture());